Application Development with Rapid Application Development Framework AllcountJS

The idea of Rapid Application Development (RAD) was born as a response to traditional waterfall development models. Many variations of RAD exist; for example, Agile development and the Rational Unified Process. However, all such models have one thing in common: they aim to yield maximum business value with minimal development time through prototyping and iterative development. To accomplish this, the Rapid Application Development model relies on tools that ease the process. In this article, we shall explore one such tool, and how it can be used to focus on business value and optimization of the development process.

AllcountJS is an emerging open source framework built with rapid application development in mind. It is based on the idea of declarative application development using JSON-like configuration code that describes the structure and behavior of the application. The framework has been built on top of Node.js, Express, MongoDB and relies heavily on AngularJS and Twitter Bootstrap. Although it is reliant on declarative patterns, the framework still allows further customization through direct access to API where needed.

AllcountJS as your RAD Framework

Why AllcountJS as Your RAD Framework?

According to Wikipedia, there are at least one hundred tools that promise rapid application development, but this raises the question: how rapid is “rapid.” Do these tools allow a particular data-centric application to be developed in a few hours? Or, perhaps, it is “rapid” if the application can be developed in a few days or a few weeks. Some of these tools even claim that a few minutes is all it takes to produce a working application. However, it is unlikely that you could build a useful application in under five minutes and still claim to have satisfied every business need. AllcountJS doesn’t claim to be such a tool; what AllcountJS offers is a way to prototype an idea in a short period of time.

With AllcountJS framework, it is possible to build an application with a themeable auto-generated user interface, user management features, RESTful API and a handful of other features with minimal effort and time. It is possible to use AllcountJS for a wide variety of use cases, but it best suits applications where you have different collections of objects with different views for them. Typically, business applications are a good fit for this model.

AllcountJS has been used to build allcountjs.com, plus a project tracker for it. It is worth noting that allcountjs.com is a customized AllcountJS application, and that AllcountJS allows both static and dynamic views to be combined with little hassle. It even allows dynamically loaded parts to be inserted into static content. For example, AllcountJS manages a collection of demo application templates. There is a demo widget on the main page of allcountjs.com that loads a random application template from that collection. A handful of other sample applications are available in the gallery at allcountjs.com.

Getting Started

To demonstrate some of the capabilities of RAD framework AllcountJS, we will create a simple application for Toptal, which we will call Toptal Community. If you follow our blog you may already know that a similar application was built using Hoodie as part of one of our earlier blog posts. This application will allow community members to sign up, create events and apply to attend them.

In order to set up the environment, you should install Node.jsMongoDB and Git. Then, install AllcountJS CLI by invoking an “npm install” command and perform project init:

npm install -g allcountjs-cli
allcountjs init toptal-community-allcount
cd toptal-community-allcount
npm install

AllcountJS CLI will ask you to enter some info about your project in order to pre-fill package.json.

AllcountJS can be used as standalone server or as a dependency. In our first example we aren’t going to extend AllcountJS, so a standalone server should just work for us.

Inside this newly created app-config directory, we will replace contents of main.js JavaScript file with the following snippet of code:

A.app({
appName: "Toptal Community",
onlyAuthenticated: true,
allowSignUp: true,
appIcon: "rocket",
menuItems: [{
name: "Events",
entityTypeId: "Event",
icon: "calendar"
}, {
name: "My Events",
entityTypeId: "MyEvent",
icon: "calendar"
}],
entities: function(Fields) {
return {
Event: {
title: "Events",
fields: {
eventName: Fields.text("Event").required(),
date: Fields.date("Date").required(),
time: Fields.text("Starts at").masked("99:99").required(),
appliedUsers: Fields.relation("Applied users", "AppliedUser", "event")
},
referenceName: "eventName",
sorting: [['date', -1], ['time', -1]],
actions: [{
id: "apply",
name: "Apply",
actionTarget: 'single-item',
perform: function (User, Actions, Crud) {
return Crud.actionContextCrud().readEntity(Actions.selectedEntityId()).then(function (eventToApply) {
var userEventCrud = Crud.crudForEntityType('UserEvent');
return userEventCrud.find({filtering: {"user": User.id, "event": eventToApply.id}}).then(function (events) {
if (events.length) {
return Actions.modalResult("Can't apply to event", "You've already applied to this event");
} else {
return userEventCrud.createEntity({
user: {id: User.id},
event: {id: eventToApply.id},
date: eventToApply.date,
time: eventToApply.time
}).then(function () { return Actions.navigateToEntityTypeResult("MyEvent") });
}
});
})
}
}]
},
UserEvent: {
fields: {
user: Fields.fixedReference("User", "OnlyNameUser").required(),
event: Fields.fixedReference("Event", "Event").required(),
date: Fields.date("Date").required(),
time: Fields.text("Starts at").masked("99:99").required()
},
filtering: function (User) { return {"user.id": User.id} },
sorting: [['date', -1], ['time', -1]],
views: {
MyEvent: {
title: "My Events",
showInGrid: ['event', 'date', 'time'],
permissions: {
write: [],
delete: null
}
},
AppliedUser: {
permissions: {
write: []
},
showInGrid: ['user']
}
}
},
User: {
views: {
OnlyNameUser: {
permissions: {
read: null,
write: ['admin']
}
},
fields: {
username: Fields.text("User name")
}
}
}
}
}
});

Although AllcountJS works with Git repositories, for sake of simplicity we will not use it in this tutorial. To run the Toptal Community application, all we have to do is invoke AllcountJS CLI run command in the toptal-community-allcount directory.

allcountjs run

It is worth noting that MongoDB should be running when this command is executed. If all goes well, the application should be up and running at http://localhost:9080.

To login please use the username “admin” and password “admin”.

Less Than 100 Lines

You may have noticed that the application defined in main.js took only 91 lines of code. These lines include the declaration of all the behaviors that you may observe when you navigate to http://localhost:9080. So, what exactly is happening, under the hood? Let us take a closer look at each aspect of the application, and see how the code relates to them.

Sign in & Sign up

The first page you see after opening the application is a sign in. This doubles as a sign up page, assuming that the checkbox - labelled “Sign Up” - is checked before submitting the form.

Sign in & Sign up

This page is shown because the main.js file declares that only authenticated users may use this application. Moreover, it enables the ability for users to sign up from this page. The following two lines are all that was necessary for this:

A.app({
...,
onlyAuthenticated: true,
allowSignUp: true,
...
})

Welcome Page

After signing in, you’ll be redirected to a welcome page with an application menu. This portion of the application is generated automatically, based on the menu items defined under the “menuItems” key.

welcome page example

Along with a couple of other relevant configurations, the menu is defined in the main.js file as follows:

A.app({
...,
appName: "Toptal Community",
appIcon: "rocket",
menuItems: [{
name: "Events",
entityTypeId: "Event",
icon: "calendar"
}, {
name: "My Events",
entityTypeId: "MyEvent",
icon: "calendar"
}],
...
});

AllcountJS uses Font Awesome icons, so all icon names referenced in the configuration are mapped to Font Awesome icon names.

Browsing & Editing Events

After clicking on “Events” from the menu, you’ll be taken to the Events view shown in the screenshot below. It is a standard AllcountJS view that provides some generic CRUD functionalities on the corresponding entities. Here, you may search for events, create new events and edit or delete existing ones. There are two modes of this CRUD interface: list and form. This portion of the application is configured through the following few lines of JavaScript code.

A.app({
...,
entities: function(Fields) {
return {
Event: {
title: "Events",
fields: {
eventName: Fields.text("Event").required(),
date: Fields.date("Date").required(),
time: Fields.text("Starts at").masked("99:99").required(),
appliedUsers: Fields.relation("Applied users", "AppliedUser", "event")
},
referenceName: "eventName",
sorting: [['date', -1], ['time', -1]],
...
}
}
}
});

This example shows how entity descriptions are configured in AllcountJS. Notice how we are using a function to define the entities; every property of AllcountJS configuration can be a function. These functions can request dependencies to be resolved through its argument names. Before the function is called, appropriate dependencies are injected. Here, “Fields” is one of the AllcountJS configuration APIs used to describe entity fields. The property “Entities” contains name-value pairs where the name is an entity-type identifier and value is its description. An entity-type for events is described, in this example, where the title is “Events.” Other configurations, such as default-sort-ordering, reference name, and the like, may also be defined here. Default-sort-order is defined through an array of field names and directions, while the reference name is defined through a string (read more here).

allcountJS function

This particular entity-type has been defined as having four fields: “eventName,” “date,” “time” and “appliedUsers,” the first three of which are persisted in the database. These fields are mandatory, as indicated by the use of “required().” Values in these fields with such rules are validated before the form is submitted on the front-end as shown in the screenshot below. AllcountJS combines both client-side and server-side validations to provide the best user experience. The fourth field is a relationship that bears a list of users who have applied to attend the event. Naturally, this field is not persisted in the database, and is populated by selecting only those AppliedUser entities relevant to the event.

allcountjs development rules

Applying to Attend Events

When a user selects a particular event, the toolbar shows a button labelled “Apply.” Clicking on it adds the event to the user’s schedule. In AllcountJS, actions similar to this can be configured by simply declaring them in the configuration:

actions: [{
id: "apply",
name: "Apply",
actionTarget: 'single-item',
perform: function (User, Actions, Crud) {
return Crud.actionContextCrud().readEntity(Actions.selectedEntityId()).then(function (eventToApply) {
var userEventCrud = Crud.crudForEntityType('UserEvent');
return userEventCrud.find({filtering: {"user": User.id, "event": eventToApply.id}}).then(function (events) {
if (events.length) {
return Actions.modalResult("Can't apply to event", "You've already applied to this event");
} else {
return userEventCrud.createEntity({
user: {id: User.id},
event: {id: eventToApply.id},
date: eventToApply.date,
time: eventToApply.time
}).then(function () { return Actions.navigateToEntityTypeResult("MyEvent") });
}
});
})
}
}]

The property “actions” of any entity type takes an array of objects that describe the behavior of each custom action. Each object has an “id” property which defines a unique identifier for the action, the property “name” defines the display name and the property “actionTarget” is used to define the action context. Setting “actionTarget” to “single-item” indicates that the action should be performed with a particular event. A function defined under the property “perform” is the logic executed when this action is performed, typically when the user clicks on the corresponding button.

Dependencies may be requested by this function. For instance, in this example the function depends on “User,” “Actions” and “Crud.” When an action occurs, a reference to the user, invoking this action, can be obtained by requiring the “User” dependency. The “Crud” dependency, which allows the manipulation of database state for these entities, is also requested here. The two methods that return an instance of Crud object are: The method “actionContextCrud()” - returns CRUD for “Event” entity-type since the action “Apply” belongs to it, while the method “crudForEntityType()” - returns CRUD for any entity type identified by its type ID.

CRUD dependencies

The implementation of the action begins by checking if this event is already scheduled for the user, and if not, it creates one. If it is already scheduled, a dialog box is shown by returning the value from calling “Actions.modalResult()”. Besides showing a modal, an action may perform different types of operations in a similar way, such as “navigate to view,” “refresh view,” “show dialog,” and so on.

implementation of the action

User Schedule of Applied Events

After successfully applying to an event, the browser is redirected to the “My Events” view, which shows a list of events the user has applied to. The view is defined by the following configuration:

UserEvent: {
fields: {
user: Fields.fixedReference("User", "OnlyNameUser").required(),
event: Fields.fixedReference("Event", "Event").required(),
date: Fields.date("Date").required(),
time: Fields.text("Starts at").masked("99:99").required()
},
filtering: function (User) { return {"user.id": User.id} },
sorting: [['date', -1], ['time', -1]],
views: {
MyEvent: {
title: "My Events",
showInGrid: ['event', 'date', 'time'],
permissions: {
write: [],
delete: null
}
},
AppliedUser: {
permissions: {
write: []
},
showInGrid: ['user']
}
}
},

In this case, we are using a new configuration property, “filtering.” As with our earlier example, this function also relies on the “User” dependency. If the function returns an object, it is treated as a MongoDB query; the query filters the collection for events that belong only to the current user.

Another interesting property is “Views.” “View” is a regular entity-type, but it’s MongoDB collection is the same as for parent entity-type. This makes it possible to create visually different views for the same data in the database. In fact, we used this feature to create two different views for “UserEvent:” “MyEvent” and “AppliedUser.” Since the prototype of the sub-views is set to the parent entity type, properties that are not overridden are “inherited” from the parent type.

views

Listing Event Attendees

After applying to an event, other users may see a list of all the users planning to attend. This is generated as a result of the following configuration elements in main.js:

AppliedUser: {
permissions: {
write: []
},
showInGrid: ['user']
}
// ...
appliedUsers: Fields.relation("Applied users", "AppliedUser", "event")

“AppliedUser” is a read-only view for a “MyEvent” entity-type. This read-only permission is enforced by setting an empty array to the “Write” property of the permissions object. Also, as the “Read” permission isn&

Usability for Conversion: Stop Using Fads, Start Using Data

When it comes to creating and designing a product, we are looking for the best solution to ensure we meet our goal. Ultimately, our goal will always be to convince the customer to buy our product or use our service; i.e., for converting leads into sales. But what can we do to ensure the highest conversion rate (i.e., of leads to sales) possible? When we look around for ways to understand what works with conversion and what doesn’t, we may encounter several fads or trends that presumptuously claim to know exactly what we need to do; things like changing a button to a particular color, using a particular picture or icon, or employing a certain layout. However, there is no one size fits all “magic bullet” to conversion. EVERY demographic is different, so we need to use our data and our knowledge of our specific targeted audience to create designs that convert. IF there is one single piece of advice that’s most important, it’s to focus on usability.

Usability and Conversion

Stop following trends to achieve your conversion rates.

Building your product and setting it loose.

You or your client have just launched your new website or product, but you are noticing that your conversionrate is dramatically low. To use an example for this exercise, let’s give a percentage: 0.3%. That’s only 3 out of every 1000 leads converting into customers. Presumably not what you’re looking for.

Concerned, you run off to Google and search ways to convert users and you find articles that say:

“Red converts better than green!” “Orange beats any color!” “Cat pictures! Everybody loves kittens!” “Pictures of people convert better!” “Pictures of products convert better!” “Company logos make you $$”

While each of these approaches may have in fact been useful in one or more scenarios, the likelihood that these “magic answers” are right for you is often slim at best. There’s no data behind the claim that making the button orange in all of our products will help our product convert better.

Another thing to point out when we read articles like the ones above is the quality of leads that the company is receiving. Although we would want as many leads as possible, we would also want to make sure that these are quality leads to getting better data and keep improving our product for that target audience. Having a ton of leads might sound exciting, but we end up wasting our time on leads that don’t go anywhere, in which case we are wasting money and losing opportunities on the leads that will move our company forward and help out product grow.

How do you identify your quality leads?

There are a couple of things to think about before you start the process of optimizing your site for conversion. Here’s a list that you should consider before you start optimizing your site:

  • Know Your Audience – What is your audience like? Their demographics? Their location? Is your website tailored to them?

  • Know Your Goals – What is the ultimate goal for the site? Are you looking to store emails? Get people to sign up for a service? Buy a product?

  • Know Your Usability Scores – How is your site performing in mobile? IS it responsive? How’s the speed of the site when it loads in the browser? How’s the navigation?

  • Check Your Content – Is your content easy to read? Is the language geared to the personality and education level of your targeted audience? Does the content clearly communicate your message/goal?

  • Check Your Fallout – Where are you losing your audience? What is your bounce rate? What is the average time visitors are spending on your pages? What are the high performing pages? What are the low performing pages?

Once you have all of these questions answered, you can start optimizing your site. You will notice that I didn’t touch on your colors or designs for the checklist. Although it was not mentioned, once you define your audience, analyze your website, and have clear goals, you will find that your design will either reflect or miss that.

Find your audience.

The most important thing is your audience. To find your audience you have to look at the process before you started working on the site.

Usability and Conversion

Find your audience.

Who are you targeting?

It is important that you have a precise definition of who are you targeting. If your product is intended for people around the age of 18 - 24, your content, design, and usability should reflect that. The easiest way to come up with all these descriptions is to create your own personas. Personas are fictitious or real people that describe a specific member of your audience. You need to write up everything that you need from them, like name, age, ethnicity, occupation, technology savviness, etc.

You can use tools like Google Analytics or other paid analytic tools to help obtain good in-depth information about your users. You can also perform some user testing in various websites like UserTesting.com or in person where you can develop your personas from them.

What are you targeting them for?

Another clear thing you need to have before you even start the design is the purpose of the site. Are you selling the user goods or are you providing a service? Hows does the site align with the company’s mission and vision? How does the goal align with your personas?

Defining usability data.

Once you have all this data written down, you can then proceed to check your usability stats. When it comes to mobile websites, there is a great tool I like to use to check my user experience (you’ve probably heard of it too): Google PageSpeed.

As a rule of thumb, you want your User Experience grade to be above 90. This means that things are clear and easy to tap/click, see, and navigate through your site. You also want to make sure your site speed is at least 80 or more. If you are 70, check the options to help you optimize your page for speed. Use services like CloudFlare, Highwinds, Akamai, etc. for caching and CDN (Content Delivery Network) to help improve speed.

For your desktop, I would suggest you use tools like Crazy EggGoogle AnalyticsVisual Web Optimizer, or any other heat map or visual guide software. These will help you find where people are focusing the most and identify pitfalls such as areas that don’t get much attention. If you combine some of these products, using heat maps, trackers, and Google Analytics you can identify your fallouts and what pages aren’t performing the way you want them to.

Another great way to test your product is by performing live user testing either at your site or at a formal user testing facility. UserTesting.com is a great tool that you can use to test your websites or mobile applications. You set up your questionnaire and identify your audience, and just wait for the results. Listen to their feedback, but watch what they do. Sometimes an action gives much more data than an answer to a question.

The next step on our list will be to check the content. This could be an incredible source of valuable information. Sometimes we focus on the design, when in reality changing a few words here and there will give you the conversion that you desire. Check your content before you decide to make any other design changes.

Everything checks out, then what is going on?

When you look at the design and start wondering what to change, keep in mind that you want to test for usability and not for conversion. I’ll explain this in a bit. One of the keys to a site that converts well is that the user trusts it. Repeat that again: One of the keys to a site that converts well is that the user trusts it.

Your presentation, colors, branding, content, everything creates an impact on the user and, in just a matter of seconds, you can lose a user or gain their full confidence.

Usability and Conversion

Your product colors

For colors, make sure they are all consistent with your brand and your company. Design for what you want the user to perceive when they first look at the site. Remember, you only have a few seconds before they go away. My general recommendation is that you create a 3 color palette.

  • Your primary color. This color is what most of the site will have. The color will portray your company/product’s vision.

  • Your secondary color. This color consists of the items you will use to bring attention to another section of the site while the user reads and digests your content. These would be the colors for your links, navigation, etc.

  • Your call-to-action color. This color is extremely important. The color of this button or link will let the user know that this button is performing an action (in our case, convert them). Normally this color should compliment the rest of the colors. You want this color to stand out, but not clash or take away from your brand.

To give you an example of a fad, there are sites that have claimed in the past that turning a button from green to red, or vice versa, will automatically increase your conversion rate. They will cite an example of how it worked for their site. Before you rush to change your colors, though, look at the design. Is your primary or secondary color red? If that is the case, then your button as red will just blend in with the rest of your product, people will ignore it. Are your colors clashing with red? That creates a distraction, not a conversion.

Layouts

Layouts are going to be important for you to convert your users and these need to be very specific in terms of usability. You need to create harmony between your content strategy and the design emotion you want to evoke from the user when they see the landing page. Remember what we talked about before? Trust. Make sure your page engenders trust in the user.

A lot of people ask about hero banners and how effective they are in terms of improving conversion rates. The answer to this, like most things we’ve discussed, depends on your audience. Does your hero banner easily explain what the user wants? Then go for it. Test it out. Otherwise, consider other options that might fit better with your message.

Another example of a fad is hero carousels. You will notice that some websites will provide a big banner on their page, but just as you are reading it, the banner switches over and shows you more information. This rarely works well for usability. You are creating a stressful situation for the user, because now they have a time limit to finish reading what they first saw upon arrival. If you want to use carousels, make sure you make them with plenty of time for a user to finish reading the content of each slides, or just don’t auto-animate it.

Building forms

If you need the user to sign up for something, make that process obvious, easy, and readily accessible.

  • Do you really need all the fields you have on your sign up form?

  • Could more information be collected once you start building a relationship with your user rather than requiring it of them upfront?

If you need a lot of fields for your product form, consider splitting the form into different steps. Make the user follow your flow. Create a funnel that is enjoyable for the user.

Be clear on why you are asking for information. Do you need an address? Tell the user why you need it. You need a user to provide a phone number? Tell the user why. If you don’t need that information right away and you can build a relationship with an email, then go that route. It may take a little longer for you to “secure” that lead, but in the end, it will provide so much more quality to your brand and your business, and will probably yield more leads.

Elements inside your pages

Work with your content team (if you are not writing the content yourself) to discover things that you want to emphasize to the user to communicate that you are looking out for their best interest.

Typography plays an important role. Make sure that your main headline is the easiest to read and answers quickly the question that the user has when landing on your page. Use bullet points to engage the user with simple and quick answers. Give the user what they want, but entice them; educate them on why they need to know more. Once you build that trust and interest, your leads will start converting at a higher rate.

While no single image is magical, using imagery to complement your message is a valuable technique. Are you trying to offer a service that is good for the family? Look for images that complement this, like a happy family. Imagery can play a big role depending on your audience so, again, it is very important that you know your audience before you choose an image.

NOTE: A quick note about using stock photography, it should be common sense by now, but just in case, make sure you’re using stock photography that looks natural. You want the photo to enhance the story of your page, not just display people looking eerily happy while they look at the camera.

YET another example of a fad is showing a professional looking person as a “customer rep” which, 9 out of 10 times, is just a stock image to give a user a sense of trust. Users will be able to identify that these aren’t really the people taking care of them. Additionally, the product should be about your user, not you. How is the image going to make them feel? How does the image relate to the product you’re selling or the service you are providing?

Don’t have imagery? An illustration can help provide more information and instill confidence in your user. Again, when designing an illustration focus on what user needs, the emotion they should feel upon looking at the illustration, and so on.

Usability and Conversion

Usability instead of conversion

So how do you measure the success of your new designs? The main thing that you have to understand about conversion is that it can’t be completely broken down into categories. You have to test and test often. However, when you test, be specific on what you are trying to test. The more specific you can make your test, the better data you will collect to keep improving.

So why should you test for usability rather than conversion? Because when you test for usability you are by definition looking at things from the user’s perspective. The user will notice this and, if you can reach a level of trust between the user and your brand, you will be able to get a conversion. The keyword here for you is trust. If you build only to try and “trick” the user into converting, you will end up damaging a relationship with that user, which will cause you to lose the confidence and trust from that user and many others.

Build trust and build relationships. This can’t be emphasized enough. When you build trust with your users, you keep them coming back and you help promote your business indirectly by word of mouth. People are very active in social media and other areas of their lives. Getting positive reviews will help you get more confidence with new users and better leads.

What is another great thing about usability? SEO. In order to start gaining more leads, you need to drive more people to your website. Usability will not only create a great user experience but it can help you stand out from your competitors on Google Searches, etc. Google has put a huge focus on giving the user what they need, just by searching, so sites that demonstrate the capability to provide the users with that information get ahead from others who are just trying to beat or game the system.

Let’s recap. Evaluate your site and follow the checklist provided above. Test for usability and test often. Focus your design on helping the users reach their goals. Design to build trust, not to trick. The more trust you can build with the user, the stronger the relationship and the higher quality conversion you will receive.

Happy converting! :D

This article was originally posted on Toptal 

Control Your Laptop with an Android Phone using Python, Twisted, and Django

Introduction

It’s always fun to put your Android or Python programming skills on display. A while back, I figured it’d be cool to try and control my laptop via my Android mobile device. Think about it: remote laptop access including being able to play and pause music, start and stop programming jobs or downloads, etc., all by sending messages from your phone. Neat, huh?

Before you keep on reading, please bear in mind that this is a pet project, still in its early stages—but the basic platform is there. By gluing together some mainstream tools, I was able to setup my Android phone to control my laptop via a Python interpreter.

By the way: the project is open source. You can check out the client code here, and the server code here.

The Remote Laptop Access Tool Belt: Python, Twisted, Django, and Amarok

This project involves the following technologies, some of which you may be familiar with, some of which are quite specific to the task at-hand:

  • Python 2.7+
  • Twisted: an excellent event-driven framework especially crafted for network hackers.
  • Django: I used v1.4, so you’ll have to adjust the location of some files if you want to run a lower version.
  • Amarok: a D-BUS (more on this below) manageable media player. This could be subbed out for other such media players (ClementineVLC, or anything that supports MPRIS) if you know their messaging structures. I chose Amarok because it comes with my KDE distribution by default. Plus, it’s fast and easily configurable.
  • An Android phone with Python for Android installed (more on this below). The process is pretty straightforward—even for Py3k!
  • Remote Amarok and Remote Amarok Web.

At a High Level

At a high level, we consider our Android phone to be the client and our laptop, the server. I’ll go through this remote access architecture in-depth below, but the basic flow of the project is as follows:

  1. The user types some command into the Python interpreter.
  2. The command is sent to the Django instance.
  3. Django then passes the command along to Twisted.
  4. Twisted then parses the command sends a new command via D-Bus to Amarok.
  5. Amarok interacts with the actual laptop, controlling the playing/pausing of music.

Using this toolbelt, learn how to control a laptop with Python, Twisted, and Django.

Now, lets dig in.

Python on Android

So one good day, I started looking at Python interpreters that I could run on my Android phone (Droid 2, back then). Soon after, I discovered the excellent SL4A package that brought Python For Android to life. It’s a really nifty package: you click a couple buttons and suddenly you have an almost fully functional Python environment on your mobile or tablet device that can both run your good ol’ Python code and access the Android API (I say almost because some stuff probably is missing and the Android API isn’t 100% accessible, but for most use-cases, it’s sufficient).

If you prefer, you can also build your own Python distribution to run on your Android device, which has the advantage that you can then run any version of the interpreter you desire. The process involves cross-compiling Python to be run on ARM (the architecture used on Android devices and other tablets). It’s not easy, but it’s certainly doable. If you’re up for the challenge, check here or here.

Once you have your interpreter setup, you can do basically whatever you like by combining Python with the Android API, including controlling your laptop remotely. For example, you can:

  • Send and read SMS.
  • Interact with third-party APIs around the Internet via urllib and other libraries.
  • Display native look and feel prompts, spinning dialogs, and the like.
  • Change your ringtone.
  • Play music or videos.
  • Interact with Bluetooth—this one in particular paves the way for a lot of opportunities. For example, I once played around with using my phone as a locker-unlocker application for my laptop (e.g., unlock my laptop via Bluetooth when my phone was nearby).

How Using Your Phone to Control Your Laptop Works

The Architecture

Our project composition is as follows:

  • A client-side application built on Twisted if you want to test the server code (below) without having to run the Django application at all.

  • A server-side Django application, which reads in commands from the Android device and passes them along to Twisted. As it stands, Amarok is the only laptop application that the server can interact with (i.e., to control music), but that’s a sufficient proof-of-concept, as the platform is easily extensible.

  • A server-side Twisted ‘instance’ which communicates with the laptop’s media player via D-Bus, sending along commands as they come in from Django (currently, I support ‘next’, ‘previous’, ‘play’, ‘pause’, ‘stop’, and ‘mute’). Why not just pass the commands directly from Django to Amarok? Twisted’s event-driven, non-blocking attributes take away all the hard work of threading (more below). If you’re interested in marrying the two, see here.

Twisted is excellent, event-driven, and versatile. It operates using a callback system, deferred objects, and some other techniques. I’d definitely recommend that you try it out: the amount of work that you avoid by using Twisted is seriously impressive. For example, it serves boilerplate code for lots of protocol, including IRC, HTTP, SSH, etc. without having to deal with non-blocking mechanisms (threads, select, etc.).
  • The client-side Android code, uploaded to your device with a customized URL to reach your Django application. It’s worth mentioning that this particular piece of code runs on Python 2.7+, including Py3k.

What’s D-Bus?

I’ve mentioned D-Bus several times, so it’s probably worth discussing it in more detail. Broadly speaking, D-Bus is a messaging bus system for communicating between applications (e.g., on a laptop computer and Android phone) easily through specially crafted messages.

It’s mainly composed of two buses: the system bus, for system-wide stuff; and the session bus, for userland stuff. Typical messages to the system bus would be “Hey, I’ve added a new printer, notify my D-Bus enabled applications that a new printer is online”, while typical Inter-Process Communication (IPC) among applications would go to the session bus.

We use the session bus to communicate with Amarok. It’s very likely that most modern applications (under Linux environments, at least) will support this type of messaging and generally all the commands/functions that they can process are well documented. As any application with D-Bus support can be controlled under this architecture, the possibilities are nearly endless.

More info can be found here.

Behind the Scenes:

Having set up all the infrastructure, you can fire off the Android application and it will enter into an infinite loop to read incoming messages, process them with some sanity checks, and, if valid, send them to a predefined URL (i.e., the URL of your Django app), which will in-turn process the input and act accordingly. The Android client then marks the message as read and the loop continues until a message with the exact contents “exitclient” (clever, huh?) is processed, in which case the client will exit.

On the server, the Django application picks up a command to-be processed and checks if it starts with a valid instruction. If so, it connects to the Twisted server (using Telnetlib to connect via telnet) and sends the command along. Finally, Twisted parses the input, transforms it into something suitable for Amarok, and lets Amarok do its the magic! Finally, your laptop responds by playing songs, pausing, skipping, etc.

Regarding the “predefined URL”: if you want to be controlling your computer from afar, this will have to be a public URL (reachable over the Internet). Be aware that, currently, the code doesn’t implement any layer of security (SSL, etc.)—such improvements are exercises for the reader, at the moment.

What Else Can I Do With This?

Everything looks really simple so far, huh? You may be asking yourself: “Can this be extended to support nifty feature [X]?” The answer is: Yes (probably)! Given that you know how to interact with your computer using your phone properly, you can supplement the server-side code to do whatever you like. Before you know it, you’ll be shooting off lengthy processes on your computer remotely. Or, if you can cope with the electronics, you could build an interface between your computer and your favorite appliance, controlling that via SMS instructions (“Make me coffee!” comes to mind). 

 

This article originally appeared on Toptal