It’s been an amazing 3.5 years, but all incredible, life-and-career-changing experiences must eventually come to an end. This week I’ll be leaving my role as Senior Engineer at Appcelerator and moving on to Innovu, a new startup in my hometown of Pittsburgh.
Pure and simple, I have an opportunity to be the Director of Software Development at an up and coming startup run by a handful of people I’ve come to respect and trust over the course of over a decade. I’ll be choosing the technology stack, building the team from the ground up (more on that below), and having an impact on company success to a degree I never have before. It’s a huge career move, it’s a risk, and I’m ready for both.
Despite how obviously fantastic this opportunity is, I still labored over the idea of leaving Appcelerator. I’m going to miss the whole crew a lot. Ironically, without having worked with a bunch of brilliant people on ground-breaking tech for an amazing developer community in the meat grinder of Silicon Valley, I wouldn’t have the confidence to take this next big step. I blame Appcelerator for my ambition!
As I’ve said at least a dozen times in the last week, I’ve taken way more from my fellow Appcelerati than I think I’ve given. In particular, a few people I’d really like to thank (past and present):
I’m sure there’s a whole bunch of people I’m forgetting to thank, so to all of you, THANK YOU!
As many of you know, I’ve got a multitude of Appcelerator-based open source side projects. Realistically, I’m just not going to have the time to spend on many of them that they deserve. Many of these projects are regularly relied on by the community, so I don’t want to see them turn to rust while others still need them. To that end, if you’re interested in being made a committer/npm owner on any of the following projects, shoot me an email or just ping me on twitter.
UPDATE: All projects have had volunteers step forward to continue maintaining them. Thank you so much for the extremely quick response!
These will all play very well with his titaniumifier project.
fs
for Titaniumconsole
for Titaniumvm
for Titanium (experimental)os
for TitaniumNow that I’m moving on to Innovu and building a new team, I’m curious if there’s anybody out there (or anyone you know) who would want to come work with me? Here’s some purposely terse job descriptions. I hate overly-detailed, impossible-to-meet criteria for tech jobs.
Be smart. Want to learn. Play nice. Work hard. The rest is details.
Python, Postgres, and AWS experience a plus for either. Like I mentioned above, shoot me an email if you’re interested or know someone who might be.
I’ll be around. You know where to find me. I’ll still be very active in the open source community. I’ll even be likely to host the local Pittsburgh Javascript meetup at the new Innovu offices in Station Square once we get set up. It’s going to be a fun time!
In closing, I’ll just leave you with this: {{profound_life_and_career_insight}}
]]>maybeCallback()
function.
1 2 3 4 5 6 7 8 |
|
Essentially, if you give it a function, it gives you the function back. Otherwise, it gives you back a new function that quietly does nothing, unless there’s an error, in which case it throws that error. Simple, right?
In node.js, it is a standard convention that the callback for an asynchronous function is the last argument. This is simple enough with concrete APIs, like say fs.stat:
fs.stat(path, callback)
There’s always a path
, and always a callback
. No trickery needed in the API creation. But what about an API like fs.readFile?
fs.readFile(filename, [options], callback)
There’s always a filename
, there might options
, and there should be a callback
. So how exactly might we structure this under-the-hood? I won’t regurgitate the node.js source code here, but let’s instead see how we might use maybeCallback
to set up this API.
1 2 3 4 5 6 7 8 |
|
Those few lines of code do the following:
maybeCallback()
on the last argument to get our callback.options
doens’t exist, or is a function (implying that it’s our callback), do your default processing of the options.This is a common pattern that I use all the time when creating APIs. And giving the users of your modules this flexibility is often key to not just their success, but also their delight in using your code. More users, more feedback, more pull requests, better module. You know how it goes.
]]>In short, it bridges the gap between app and API development, taking the functional links of the Appcelerator Platform and turning them into a powerful, cohesive chain. The following screencast is a (very early) preview where I’ll show you the following:
All of that done automatically, simply by defining your API in the Appcelerator 360 dashboard. Way more to come, not publicly available yet, so stay tuned.
]]>Here I’d like to explain exactly how you can do #4. I was originally inspired by this post, but the method therein made available only a small subset of should.js’s assertion functionality. To quote Freddy Mercury, ♫ I want it all, and I want it now. ♫
Let’s say you have a configuration file that must abide by this format:
1 2 3 4 5 |
|
We’d like to strictly enforce that format using assertions. Lots of them. A ridiculous amount in fact. Yes, it could be done much more tersely, but it helps express the point of customization. Let’s do it in a mocha BDD structure.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Here we’re effectively asserting the format of the configuration, but we’re losing a bit of the expressiveness of should.js in the process. We’ve essentially got 11 lines of assertion code when what we really just want to say is
this object should be a valid config
In addition, what if we want to validate the config at the beginning of many tests and keep it DRY? It’s undoubtedly getting messy fast here.
Let’s say “this object is a valid config” exactly by creating a custom assertion within should.js. And let’s go one step further and show how this custom assertion can be placed in a separate module. This will make our tests as simple, clean, and expressive as possible.
I’m going to explain some of the should.js assertion internals inline, but for more details I’d highly suggest perusing the source code, particularly the extensions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
|
and now are unit test looks like this:
1 2 3 4 5 6 7 8 9 10 11 |
|
Aaaaaahhh, now that is nice. It should be pretty clear at this point how custom assertions can improve the readability and scalability of your test suites. It becomes clearer as your test suites grow.
Just in case you aren’t convinced, here’s a few more examples of using custom assertions in should.js to execute critical testing while preserving maximal expressiveness.
Remember, Titanium proxies don’t play well with should.js, so you need to wrap them manually before running assertions.
1 2 3 4 5 6 |
|
1 2 3 4 5 |
|
Here’s a simple case of validating that a given object is an XML string using xmldom.
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 4 5 |
|
You can even do some really complex validating using functions instead of getters. Here’s an example of asserting that a chunk of Javascript will be be minified into an expected string using uglifyjs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 |
|
Resolving bug reports is like trying to rescue developers lost on a desert island. Sometimes you get the privilege of rescuing the developer who started a signal fire you couldn’t possible miss, kindled by reproducible test cases and detailed specifics of their environment. They make the rescue easy and still thank you profusely for the aid. In the end, everyone involved is happy. But this isn’t always the case…
Sometimes you have to resuce the developer who makes no effort on their own to get off the island. They’re just sitting in the sand, arms folded, pissed off at the world for getting marooned. This developer essentially throws a message in a bottle into the sea, the entire contents reading:
I’m lost. Find me.
When the maintainer of the “offending” software project actually manages to find the message, they often tweet cynical things like this:
“It failed” or “there was an error” is not a bug report
— Tony Lukasavage (@tonylukasavage) January 24, 2014
And while there is a minute, fleeting catharsis to complaining into the void of twitter, nothing is achieved. The stranded developer is still stuck. The maintainer’s project has not improved and they still need to wonder if the poorly-defined report is legitimate.
It is at this point that I paraphrase the immortal wisdom of Henry Hill, as delivered through the genius of Martin Scorcese’s “Goodfellas”:
Fuck you, show me.
Trouble with the framework?
Fuck you, show me.
An uncaught exception crashed your app?
Fuck you, show me.
You’re stuck on what you think is a bug and your client is expecting a deliverable ASAP?
Fuck you, show me.
Am I really this callous with the bug-reporting-challenged? No, not even close. I want to harbor a notion of inclusivity and even education on this task that is the lifeblood of an open source project. So maybe that’s not exactly how you should phrase it. Perhaps in practice it sounds a little more like:
You haven’t provided enough information for anyone to help you troubleshoot. Please provide the details of your development environment, as well as a reproducible test case that manifests the bug you are reporting, and an explanation of what the expected behavior is if it’s not clear.
But the sentiment is the same. And without the aforementioned requirements, I will not assist with the bug. Why the hard line on bug reporting? Because standing firm on this point is best for everyone.
Don’t get stuck on a desert island only to get blown off by a gangster-quoting maintainer. Write minimal, detailed, reproducible bug reports.
Feel free to link the shit out of this on issue lists, Q&A boards, forums, etc… Spread the word.
]]>If you follow me on twitter, my current love affair with task management via the node.js module grunt is no secret. Long story short, it is a deliciously simple way to automate development tasks, with a multitude of those tasks (like linting, minification, file watching, etc…) already done for you. I could babble on about it here, but I think a tweet of mine best encapsulates my experience with it.
I love @gruntjs. I now officially spend next to no time on shit that isn’t integral to the user-facing functionality of my projects.
— Tony Lukasavage (@tonylukasavage) December 20, 2013
In a natural fusion of my current technological entanglements, I took to creating grunt task plugins for Appcelerator’s core cross-platform mobile development tools. As a result, we now have grunt-titanium for the Titanium CLI and grunt-alloy for the Alloy MVC framework. With these plugins you can now automate all functionality involved by these 2 tools, in turn letting you shift your focus onto your mobile app development, where it should be.
For a crash course in…
In the meantime, though, check out these few examples of how you can use grunt-titanium and grunt-alloy to super-charge your development workflow. Bear in mind that these are excerpts from a Gruntfile.js implementation, so again, read up on grunt and check out the grunt-titanium and grunt-alloy repos to fully understand how to use these examples.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
Stay tuned. I’ll soon be posting about how you can expand this workflow with ti-mocha to start automating the runtime testing of your Titanium and Alloy apps!
PS - grunt-clean is a great plugin to use for cleaning up after yourself when creating temporary Titanium/Alloy apps for test automation.
The Appcelerator community has long been asking for a clear choice for unit testing. While many (including myself) have used Jasmine, I have over time gained preference for another. Mocha has quickly become my unit testing framework of choice for all node.js development, due to its stability, flexibility, and the consistently awesome work of its author, TJ Holowaychuk. There was one small problem. It didn’t work out of the box with Titanium. And even once you got past the critical breaking issues, you still had the fact that Titanium Studio and the Titanium.API log functions weren’t compatible with almost any of mocha’s reporters.
But no longer. ti-mocha resolves these issues and is ready for use in your Titanium apps. I’m not going to ramble on here, since pretty much everything is covered on the documentation website, but here’s the highlights:
ti-spec
and ti-spec-studio
Titanium reporters, optimized for terminal and Titanium Studio, respectivelyYou’ve got one less reason to not be unit testing your Titanium apps. So grab ti-mocha, get to it, and let me know what you think.
Get the source: Automata on Github
Every once in a while I like to engage in some wildly impractical coding experiments. You know the sort, the “Hey, I got Gentoo running on my toaster!” stuff. Today’s experiement was implementing Conway’s Game of Life using nothing more than Appcelerator Titanium views and deploying it to iOS. Let me explain a bit more why this is a ridiculous idea…
Titanium makes high-quality, cross-platform mobile applications leveraging native UI and functionality. It does exceptionally well with data-driven apps that make heavy use of the underlying mobile platform’s own UI. It will win the app bake-off against any other cross-platform mobile framework there is, and often times native counterparts as well.
It is, however, not well-suited for any type of gaming. It is not a rendering canvas. It is not a game/particle engine. It has no standard render loop like you would expect in those aforementioned tools. Implementing any kind of graphical game-like experience is ill-advised. But sometimes ill can be a good thing. Just ask the Beastie Boys (RIP MCA).
Despite that fact, you should see what the Appcelerator-funded Lanica is doing with the Platino. Now there’s a game engine. Be sure to hit up Carlos Icaza, former co-founder/CEO of Ansca (makers of the Corona SDK), if you want more info about it.
But I digress…
Any normal person implementing this in Titanium would use a webview. Why? Because webviews, depending on the platform, actually have rendering facilities for these exact type of experiences. You could use an HTML5 canvas or even a WebGL surface to render this zero-person game, like I did with my experiment rendering 3D STL files on the web, just like Github.
Because writing code to see “what if” is what makes a hacker a hacker.
Here’s a test run of Automata on my iPhone Simulator (6.1) using Titanium SDK 3.1.1. As you can see, as the number of live cells dwindles, the speed increases drastically, as is to be expected. Despite it’s limitations, Titanium makes for a pretty cool demo of this game.
In order to implement the Game of Life with nothing more than Appcelerator Titanium Views I needed to do the following:
And by crude, I mean really crude, along the lines of:
1 2 3 4 5 |
|
This so far only plays well with iOS. The perpetual while loop seems to prevent the UI from updating on Titanium’s other supported platforms. Perhaps some toying around with setInterval
or other timing methods could alleviate this limitation.
I needed to execute the game in performance-conscious JavaScript. I’m sure someone can squeeze a little more performance out of this, but this section accounts for less than 1% of the actual execution time. It doesn’t really seem worth the time investment to push it further.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Titanium’s UI handling of each cell needed to be handled in an even more performance-conscious manner, as this is where over 99% of the execution time would eventually end up. The views are wrapped in a plain JS object in order to keep track of state and toggle the UI’s dead/alive rendering as infrequently as possible. The single cell.proxy.visible
assignment below accounts for over 99% of the total execution time on each loop. Future versions of Titanium are actually planning to make these “native bridge crossings” much faster. Automata can serve as a bar by which some of these improvements can be measured.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
opacity
instead of visible
had no discernable affect on performance.Get the full demo: jsstl on Github
Recently Github announced that they were integrating a web-based STL viewer into their interface. The STL file format has become very well known as of late do to the growing popularity of 3D printing among makers. STL is the format of choice for most 3D printing devices and is as such the format used by almost all accompanying software. So whether you want to print, manage STL files, or convert them to some other format, you need to get to know them well.
Seeing as how I’m not a maker but I am intrigued by the 3D printing process, about a year ago I implemented a pure Javascript STL parser (both ascii and binary format) and web-based renderer. It’s far from polished, but more than usable. Go ahead and check it out on Github. It makes use of a few cool technologies, including Javascript typed arrays, WebGL, and three.js.
Parsing the ascii format of STL files was pretty straight forward based on the specification. Verbose, but easy. The binary format on the other hand was a bit trickier. Javascript isn’t exactly known for its robust binary data handling. Despite this shortcoming, I really wanted to see if I could handle this in pure Javascript. Enter Javascript typed arrays.
I won’t go into it all too deeply here, other than to say that they make binary parsing possible in Javascript. ArrayBuffers represent a generic, fixed-length data buffer, in this case used to store the data from a binary formatted STL file. The DataView in turn exposes a low-level interface for reading, manipulating, and writing ArrayBuffers. Both are used in conjunction to read and pull apart the binary STL into a format that can be used by the web-based rendering engine.
This small snippet below shows how a binary STL file can be read using the DataView. Be sure to check out the APIs for DataView and ArrayBuffer to get the full scope of what they can do.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
|
Since STLs represent real objects, they obviously need to be rendered in 3 dimensions. On the web we have a few choices for that, but I’m going to let my framework of choice do the selection for me. In this case I used three.js. Three.js has exposed a 3D rendering API in Javascript that is compatible with both WebGL and the HTML5 canvas element. In this way you can gracefully fail back to canvas when operating in a browser that does not support the higher performing WebGL.
It’s not dumb luck that I chose to use this terrific library, I’ve used it before. Over a year ago I used three.js and Titanium to create an experimental 3D demonstration across multiple mobile devices using socket communication in realtime. Instead of trying to explain it all, you can check out the screencast I did regarding it below. This is part 3 of a 3 part series. Click here to check out the previous parts.
So needless to say I was already primed to use it again. In the STL viewer I would be using it to render the 3D triangle information from the STL files into faces of a mesh. This turned out to be pretty easy with three.js. The snippet below shows how I took the data I read from the STL in the Binary Parsing section above and then used it to render a series of triangles that would compose a mesh of the STL object.
1 2 3 4 5 6 7 8 9 10 11 |
|
And that’s it. The hard part was done creating that geo
object. We now have the mesh
object to which we can add to a prepared three.js scene. For the full code, check the repo.
To keep things interesting, naturally I chose a weird, frankenstein of an STL in octocat that I found on thingiverse.com for my testing. I did this for 3 reasons.
So without further ado, here’s the end result, provided your browser supports it. Feel free to use, bend, mold, and/or steal this code as you like. A digital high five would be nice, but is not required.
]]>One aspect of my current project, the Alloy MVC framework for building cross-platform mobile apps, is simple integration with local storage via SQLite databases. SQLite is a powerful and relatively simple way to store data for offline use, or just to cache remote data to speed up interactions. Unfortunately, the current data and structure of SQLite databases can sometimes be tricky to ascertain when housed on mobile devices, emulators, and simulators. This is especially true when developing for multiple platforms and having gone through multiple iterations of your data structure.
Jump to: sqlite3 command | Android | iOS | SQLite database inspection
There’s some common things it would be great to know quickly about your deployed databases, like:
In order to make this a little less painful of an experience, let’s take a look at a very simple way to inspect SQLite databases, and where we can find those databases on various mobile platforms. First we’ll need a tool to actually interact with a SQLite database…
My weapon of choice is generally the command line. For that reason I tend to stick to the sqlite3 command line tool. It comes preloaded on Mac OSX and is available for all other major OSes. Interacting with a SQLite database becomes as easy as:
1 2 3 4 5 6 7 8 |
|
You can quickly get to know the rest of the commands by executing .help
in the sqlite3 prompt. Remember to include the .
before the name of the command.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
|
The nice thing about the Android interface is that we can use a single command to find the SQLite databases on both emulators and devices. Assuming you have an open emulator and/or connected Android devices, execute adb devices
to get a listing of their serial numbers.
1 2 3 4 |
|
So now connecting to an emulator or device is easy. Just pick the target serial number and execute adb -s MYSERIAL shell
. We’ll use this shell for the duration of the :
1 2 |
|
All commands from here on in will assume you are already connected via adb shell
.
Now that we’re connected to the target Android device/emulator, let’s get a list of the SQLite databases installed on our target app. To find that, we’ll first need our target app’s ID. It’s typically a domain name format, like com.somedomain.someapp
. If you don’t know how to find your app ID, you can always list the installed apps on your device/emulator with the adb shell and search there:
1 2 3 4 5 6 7 8 9 10 |
|
In this case we’ll use com.appcelerator.Harness
as the target app, which happens to be the test harness app I used for testing Alloy. Now we just need to list the databases installed on this app:
1 2 3 |
|
In this case we find 2 installed databases, users
and Titanium
. Congrats, you found your Android SQLite databases. To start inspecting, you just need to open up the database file with the sqlite3
command while in the adb shell. That is, Android already has sqlite3
available at its shell, so you can use it directly from the shell:
1 2 3 4 5 |
|
Now you’ve got yourself full access to the live SQLite database on your Android emulator/device. To take a look at a handful of useful ways to inspect your database from the sqite3 prompt, check out the inspecting your SQLite database section.
Unlike Android, you’ll have to take a different approach in locating your SQLite database(s) depending on whether you are inspecting a simulator or device. It’s actually pretty easy on the simulator. Devices, on the other hand, are a bit more of a pain in the ass to work with with respect to SQLite databases. So it goes with iOS.
To find a SQLite database on an iPhone/iPad simulator, let’s first track down a listing of all the installed applications. To find this you’ll need your current Mac username as well as the iOS version of the simulator you are running. For this example let’s assume the following:
To list the applications we now execute the following. You can use Finder, but I prefer the CLI:
1 2 3 4 5 6 7 8 |
|
Now you need to select which app ID is the one that corresponds to your installed app. For this example, we’ll assume it’s 25D2F0D4-B225-4E19-A830-4EE6DB0093A0
. Once you’ve determined that, we’ll dig a little bit deeper to find the actual location of that app’s SQLite databases. Bear in mind, if the following directories don’t exist in your app, you likely don’t actually have a SQLite database installed. We’ll continue from the previous code block:
1 2 3 4 5 |
|
Hey look, there’s our databases! Now that we have the location, opening up the databases is as easy as issuing the sqlite3
command:
1 2 3 4 5 |
|
You can now hop to the inspecting your SQLite database section to see what you can do with it.
It’s unfortunate, but on iOS we don’t really have a good CLI method for accessing the on-device SQLite database like we do with Android. For this, we’ll need to crack open Xcode, and more specifically Organizer.
Open up Xcode and then hit SHIFT+CMD+2
or go to Window -> Organizer
to open up Organizer. In there we’ll find a listing of your currently configured iOS devices. Follow these steps to retrieve the SQLite database (and additional application data) on your target device:
Now that you have the app data downloaded, we just need to navigate to the embedded SQLite database and you’ll be free to use sqlite3
on it. Assuming you downloaded the xcappdata file to your current path, this is how you would find it:
1 2 3 4 5 6 |
|
Though a bit more effort than the simulator, you now have full access to the SQLite database from your iOS device. Move on to the next section for some tips of what you can do with it to learn more about your app.
Now that you’ve found your app’s SQLite database, here’s a hadful of useful commands to inspect its state and contents. While it takes various methods to access these database files, interacting is exactly the same on all when using the sqlite3
tool.
1 2 3 |
|
1 2 3 |
|
1 2 3 4 5 6 |
|
1 2 3 4 5 6 7 |
|
This is only a very small sampling of quick things you can check to find the current state of your SQLite databases. For more details on the full functionality of the sqlite3 command, be sure to check out the full documentation.
I’d highly suggest taking the time to learn the CLI and the syntax of SQLite itself. If, however, you prefer a GUI…
Honestly, I’m not a huge fan of Firefox, but it has one nice thing going for it: SQLite Manager. SQLite Manager is a Firefox add-on that provides a simple, clean interface for interacting with SQLite databases. Not much in the way of bells and whistles, but hey, this is SQLite, there’s not a lot of bells and whistles in the first place. The nice part about it is it’s free and it will work anywhere Firefox will.
You can choose and SQLite app you like, but I recommend this one for the sake of its price, availability, and simplicity. If you aren’t a command line warrior, this is a solid tool to lean on.
]]>Back before before joining the Appcelerator team about a year and a half ago, I was working a typical 9 to 5 enterprise development job. While this was nothing more than a paycheck, it did afford me copious amounts of time to experiment on personal projects before I finally fell in love with cross-platform mobile development. My first true love in this experimental coding was interactive 3D using Flash and Away3D.
I had always been a back-end dev, mostly C/C++, working on Linux servers for about the first 7 years of my career. With these experiments, I wanted to get way out of my comfort zone. I wanted to not just learn a new programming language and tooling, but entirely new concepts for interacting with computers. To this end, I dove head-long into learning Away3D with the express purpose of developing demos that had no goal other than pure coding fun.
While I never really became much more than a novice-intermediate 3D developer, I did crank out of a bunch of cool looking demos, not to mention made tons of friends and contacts in the Flash/Flex/AS3 world. If it wasn’t for those guys, I wouldn’t be the Twitter junkie I am today, which directly led to my current job with Appcelerator (just ask this guy). In short, these seemingly purposeless experiments led to the most amazing experiences thus far in my professional career.
And without further ado, dug up from the archives of my old blog I present the aforementioned experiments in Flash and Away3D. Enjoy*!
These are not optimized for mobile and probably won’t run properly even on mobile devices that support Flash.
]]>For about a week there my MMA fighter app for Android, Knucklehead, has been out of commission. The reason is that the site that I scrape for data, Sherdog was completely redesigned. I needed to rework a lot of my PHP-based screen scraping code to make it work. My PHP is rusty, but fortunately, my regular expression chops are always sharp. In any case, it’s back to working order now.
Maybe with a little luck I can get people to re-rate those 1-star ratings I got while it was down. If not, perhaps I can guilt people into giving me good ratings by saying that it’s my newborn son’s fault I didn’t get to it sooner. I mean, really, are you going to give the father of this child a hard time? Don’t be so heartless. :)
As we all know, screen scraping is pretty much the most volatile way to supply your apps with data. While no amount of planning can permanently future-proof your screen scraper, there’s some things you can do to make it easier.
That’s just a couple things that made fixing my scraper a lot less painful. You guys out there have any tips? I’d love to hear them. All things being equal, I hope I never have to screen scrape for data ever again. But since that’s pretty unlikely, it’s good to be prepared for the inevitable obstacles that scraping will present.
]]>Yep, another cross-post from the Appcelerator blog. This time it shows off how I managed to implement the dynamic and unique Path menu in Titanium. From a single code base the menu is fully functional, with native performance, on both Android and iOS.
Here’s the 10 second summary of each part:
I’ve tried not to overpopulate this blog with Appcelerator content ever since joining them as a platform evangelist. I think I’ve earned an Appcelerator post though after talking exclusively about PhoneGap and Adobe in my last one though. ;-)
So if you haven’t heard yet, Adobe acquired Nitobi, the company that is responsible for PhoneGap. This was announced at Adobe’s big MAX conference. If you are unfamiliar with PhoneGap, then this post is going to be wildly uninteresting to you. At a high level, they provide a cross platform mobile development solution that leverages native webviews with HTML5, CSS, and Javascript to create native mobile apps.
Well, for one thing, Adobe was obviously hedging its bets on Flash/Air’s viability in the long term with mobile when they started introducing HTML5 capabilities through Edge. I mean, if Adobe’s planning to offer interactive, Flash-like development with HTML5, who is going to believe that Flash itself has a real future with mobile? Or as Gizmodo put it, Adobe Edge may become the beginning of the end for Flash. Yeah, it will likely always exist, but it is not the de facto standard for delivering interactive web (or mobile) content anymore.
And of course there’s the whole Adobe Air for mobile thing. Android was obliging enough to make Air a first class citizen. Install Air, run Air apps… simple. And while the Adobe Air install is a bit hefty, it’s hardly something worth worrying about with today’s storage capabilities on mobile devices.
“Flash has been labeled an outlaw and Air is smuggled in like an illegal immigrant”
The more harrowing journey for Adobe has been iOS. Basically, Flash has been labeled an outlaw and Air is smuggled in like an illegal immigrant. There’s been a staring contest between Adobe and Apple for a while now, but I think it’s safe to say Adobe blinked. Apple has continually proven that is has the most marketable mobile devices available, and has done so without any back pedaling on what they will and will not allow (minus letting 3rd parties build apps).
Something had to give if Adobe was going to get a real foothold in the mobile world, and it obviously wasn’t coming in the form of their current solutions. Enter PhoneGap…
PhoneGap fills a lot of holes for Adobe, but its going to need a lot of help itself. I think PhoneGap has gone about as far as it can on its own. It has achieved its goal of abstracting most native functionality for many different mobile platforms, but starting developers are wanting more.
PhoneGap has no user interface components. This is not fun for new developers… or veteran ones for that matter. You need to build everything from scratch or go out and find a UI framework that works for you. The 2 front-runners, Sencha Touch and jQuery Mobile, bring their own glitches and idiosyncrasies. Also, now you find yourself learning 2 frameworks that have a noticeable lack of cross-over documentation.
There’s also a seemingly purposeful lack of direction in terms of tooling and best practices. New developers, often web developers, are left to their own devices to find the workflow that works best for them. There’s no sanctioned IDE or set of tools suggested from PhoneGap to build your mobile apps. Infinite flexibility can be a real drag when you just want to know the most effective way to get things done.
What are the pros and cons of PhoneGap?
Pros | Cons |
|
|
And what are the pros and cons of Adobe?
Pros | Cons |
|
|
Anyone else seeing a pretty clear yin-yang thing going on here?
Well, for one thing, it means PhoneGap is becoming an Apache project. Yep, they are donating PhoneGap to Apache, which puts them one step closer to their altruistic goal of PhoneGap itself becoming obsolete. PhoneGap’s own Brian Leroux stated in his PhoneGap 1.0 presentation that:
“The purpose of PhoneGap is for PhoneGap to cease to exist”
Why, oh why, did Adobe buy it then? I think it’s because they want to be your one stop shop for purchasing IDEs, frameworks, professional services, etc… Adobe is likely banking on the ongoing popularity of PhoneGap and web-based native mobile development. “Web-based native”… sounds a little like an oxymoron, but whatever.
Sounds like a perfect match. The 2 companies seem to complement each other very well. But…
There’s just a few questions I still have regarding the acquisition. Rather than drone on any longer inserting my own conjecture, I’ll just list my questions here and leave them as talking points for you, my readers.
“I can already hear the `It’s back to AS1` complaints starting…”
I have no clue, but it’s sure to be interesting. I’m hoping for good things on both sides as it’s only going to make mobile development in general more exciting.
Will Adobe’s ability to create great tools translate to mobile success? Will PhoneGap’s strict adherence to the open web model jive well with Adobe’s history of closed, proprietary tools? Will the inevitable merge of the open web and existing Adobe community be a bumpy one?
Stay tuned…
]]>Let me start by saying that among the 250+ new features added in Lion, there are some really useful ones. Some of my favorites include:
In addition to these nicer features, Lion did some really annoying stuff to user interaction and the user interface. I’m all for change for the better, but most of these fall under the category of “If it ain’t broke, don’t fix it.” Fortunately, there’s ways to get back the settings you expect. Here’s 5 I specifically ran into.
For whatever reason, Apple decided to hide your ~/Library path. This is a real pain the ass if you find yourself in there a lot. For example, Appcelerator installs its SDK and other files in ~/Library/Application Support/Titanium. I’m constantly tinkering in that directory and it would be nice to see it in Finder.
Execute this line in Terminal and you’ll have your Library visible once again. USERNAME is your username:
1
|
|
Lion has included “natural” scrolling. I use quotations around “natural” because it feels anything other than natural for the average user. The content you are scrolling will now move in the direction you scroll, which is essentially the opposite of how it has always worked.
I have no problem with this functionality. What I do take issue with is that this was made the default behavior. To set scrolling back to the way most of us expect it, open System Settings, go to Trackpad/Mouse, and in the Scroll/Zoom tab uncheck “Scroll direction: natural”.
The trackpad gesture I use more than any other is navigation using 3 finger swipes. I don’t even remember the last time I manually pressed the back button in a browser. No wait, yes I do. It was when I got my MacBook Air and it had Lion on it.
Turns out Apple mapped 2 finger horizontal swipes to its “Swipe between pages” functionality by default. Unfortunately, unless you switch this value to use 3 finger horizontal swipes, it won’t work for browser navigation. Check out the image below to see how:
If I wanted what is effectively a “Show Desktop” button combined with an applications list, I’d use Windows. Just remove that thing from your Dock and be done with it.
Do yourself a favor. If you really want an effective way to find and run apps, check out Alfred or Quicksilver. You can thank me later.
I don’t know about you, but I reboot my Mac really infrequently. When I do, though, it’s generally because I want a clean slate. I want all my apps closed and everything to go back to a fresh state. Lion disagrees with me.
By default Lion will remember every app you had open and make sure everything is just as you left it when you restarted your computer. For those of you who would also like a fresh restart, open System Settings and go to General. In there you just need to uncheck the “Restore windows when quitting and re-opening apps” checkbox.
]]>OK, well I just did a post on how to use Android Intent Filters with Appcelerator, so why not the other side of the coin. This time you’ll learn how you can send Intents instead of receiving them. With this powerful native functionality you’ll be able to leverage existing apps on your Android device to do some of your heavy lifting, like sharing images, sending text, and a whole bunch of other things.
Here’s just a cross post of my first tutorial on the Appcelerator Developer Blog. It details how you can use Android Intent Filters to make your Appcelerator apps receive Intents from other Android applications. For example, I’m sure if you are an Android user you are familiar with the SEND Intent list:
With this blog post I’ll show you how you can add your app to that list. It’s a great example of how Appcelerator still leverages powerful native functionality, both visual and non-visual, while it provides a cross platform solution.
]]>For the sake of not repeating myself I’m going to refer to the phrase “code once, run everywhere” as CORE from here on in. Who knows, maybe it’ll catch on. And on to the blog post…
So as you may have heard by now, I’ll be starting my new job as an Appcelerator platform evangelist on Monday. If you’ve read some of my past blog posts, you’ve probably noted that I’ve been pretty critical of cross platform mobile solutions. From a developer’s perspective, we are expecting the coveted CORE, but are often left wanting.
What you’ll quickly find in the world of mobile development is that cross platform does not always equal CORE.
Rather than bemoan the shortcomings of each mobile framework, I’d rather talk about something I heard Kevin Whinnery say during the Appcelerator online training videos. He stated that Appcelerator does not aim to be a CORE technology, but instead a “code once, adapt everywhere” one. Not quite as sexy, but perhaps an even more intriguing philosophy. Let’s discuss why.
For a quick summary of how Appcelerator is fundamentally different than web-based cross platform mobile frameworks, read here.
Aside from near-native performance, what’s the biggest advantage of using Appcelerator over web based mobile frameworks like Phonegap or Rhomobile? Its ability to use the device’s native UI components. And no, I don’t mean it has UI components skinned to look like native components, like many of the web-based solutions. I mean it actually uses the platform’s native, performant UI in the app.
With native UI we can build apps that are indistinguishable from apps built with Objective-C or Java. The look, feel, performance, and behavior will be exactly what is expected of the given platform. Plus, we don’t have to build them ourselves.
To achieve this level of quality, though, you need to be willing to adapt your app, not just design for the lowest common denominator, as is often the mentality with CORE apps. Sure, you can use the iPhone’s slick Navigation Controller bar on all versions of your app, but is that what Android users are expecting? Nor would an Android Spinner be befitting of an iPhone app.
You see, in some cases, CORE apps come at the expense of the most important factor: the user experience.
Many people, particularly proponents of web based mobile development, are of the opinion that native UI components are not necessary to deliver a high quality user experience. I agree, in certain circumstances. Games, novelty utilities (think Flashlight), and otherwise simple apps are good examples that probably don’t benefit much from a native experience.
In my opinion, though, it’s a necessity for more complex apps, particularly ones leveraging native APIs, to use the UI that is familiar to the device. They need to work in a simple, intuitive manner as mobile users can be quick on the trigger in deeming an app unfriendly. Those who have spent time developing for multiple platforms understand that the users of each platform have different expectations.
I don’t want a navigation bar in my Android app. I want my tabs at the bottom on iPhone, the top on Android. I want to press my menu button on Android to get my app’s options. I want my system buttons to look familiar. I want to pull to refresh on my iPhone.
Let me be clear that both Appcelerator and web-based frameworks have the ability to adapt their apps to supported platforms. And I don’t just mean churning out a basic app, I mean creating a high quality, native app. Depending on your point of view, however, one may be much more appealing than the other.
With web-based solutions, the app exists in a web view container. This means that you are effectively building a native app that consists of only a web view which hosts a web application. You have no native components with which to work. This leaves us with 2 options for building the UI of the app (super quick assessment coming):
So as you can see, web based mobile development encounters many of the same issues that traditional web development does. And the problem is compounded when you are trying to make these web based solutions look, feel, perform, and behave natively.
Appcelerator apps are built differently. The extremely short version is that Appcelerator Javascript code is mapped to native symbols of the target platform. Any code that can’t be mapped to a native symbol is run through a Javascript interpreter. Jeff Haynie, CEO of Appcelerator, does a much better job of explaining it in this StackOverflow post.
What this means that there are no 3rd party tools or special code necessary to create totally native components. You want a button that has native appearance and behavior on both iPhone and Android?
1
|
|
There you go, an Android and iPhone button respectively. How ‘bout a table view populated with sample data?
1 2 |
|
Yep, it’s that simple. The iPhone table will even have the bounce scrolling users expect. You have the same simplicity that web based UI frameworks solutions provide, except you are additionally getting native look, feel, performance, and behavior. The components are even designable as you would expect them to be.
The one drawback to this simplicity is that without careful attention to your code, you can end up with a mess of interlacing UI and logic. Android has XML for layout, iOS has .nib/.xib files, web based solutions have HTML/CSS. Appcelerator, for the time being, relies solely on your Javascript code. Javascript MVC frameworks, like PureMVC, and attention to best practices (as mentioned in the online training videos) can mitigate this risk. There are even some vague rumblings of a more declarative syntax for UI design in the future…
So now that we know how UIs are built in both Appcelerator and web-based frameworks, how do we adapt them in such a way to deliver a native user experience? Despite the differences between the frameworks mentioned so far, the solution is fairly common among all frameworks.
While I will confidently say that Appcelerator has the abstraction that delivers the most familiar and device-specific experience, it too needs to account for usability that is not necessarily CORE. And even saying it is not CORE can be a bit of a misnomer as the same code base can be used by multiple platforms. It just requires the clever and judicious insertion of platform specific code facilitated by your mobile framework’s device identification APIs.
Let’s take a quick look at how Appcelerator identifies your device and can act on the information:
1 2 3 4 5 6 7 8 |
|
For a more in depth example of how you can use this logic to create truly cross platform components and functionality, check out the 6 minute screencast “Forging Titanium: A Cross-Platform Navigation Controller.” Or just watch this:
And for reference, let’s look at PhoneGap’s adaptation method as well, just to show the similarities:
1 2 3 4 5 6 7 8 |
|
Very similar indeed, but you need to consider the 2 prior “Attending to the UI” sections before calling them equal. Its the frequency with which you are required to apply this and other types of adaptation that affects the maintainability of your app as it grows.
It doesn’t take an expert software engineer to see that conditional checks on the device’s platform throughout your code isn’t ideal. It gets harder to maintain the more conditionals you include. It becomes apparent that we need our development framework to do most of this work for us.
In the case of Appcelerator, the need for conditional adaptation is minimized by the fact that you can utilize native UI components. Look back at our examples of the buttons and table views. There was no conditional code, no special handling. You get system specific components with no extra effort.
You really only need conditional code when you want to leverage native components that don’t have an equivalent on your other target platforms. For example, if you haven’t already, check out the Cross-Platform Navigation Controller video above. It shows how you can use these conditionals to create navigation code that you can use seamlessly between iOS or Android.
Web based platforms also do a great job of creating an abstraction so that you don’t need to use conditionals for each supported platform. The problem, as discussed earlier, is that these abstractions don’t represent actual native components. They most often represent HTML/CSS/JS that are attempting to mimic native components. Worse yet, sometimes they are components that have no relation to existing native components, yet find themselves in native apps. As I said, this is a point of contention among mobile developers, and I’ll leave further discussion for the comments if necessary.
What web based frameworks can’t give you in native components, they provide in CSS, often applied dynamically via Javascript. The use of CSS is a double-edged sword. On one hand, you have a method of styling that not only allows you to skin your whole app, but also affords you the opportunity to gracefully degrade the styling based on the user’s device. This is why web based solutions typically support more platforms than ones like Appcelerator. Add all the bells and whistles like rounded corners, drop shadows, webkit transitions, etc… and if the device doesn’t support them, they will disappear without interrupting the user experience.
On the other hand, unless you are a CSS wizard with existing knowledge of CSS3 and how it applies to mobile, using it can be difficult. You can find yourself with mountains of CSS attempting to mimic components that are created with a single line of code in Appcelerator. For example, here’s a shiny iPhone button in pure CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
It does the job, but man, it is really cumbersome. Again, this is all a factor of wanting to create a native experience. Some will contest that it does not need to be this complex, that as long as the UI is uniform it does not need to conform to the native expectations. This mentality, though, is typically only held by those who back mobile frameworks that are incapable of delivering that native experience. As the local radio sports caster in Pittsburgh likes to say, “Not hatin’, just sayin’.”
You can’t beat web based mobile development for platform compatibility. Every mobile device has a browser that supports HTML/CSS/JS, right? You can create UIs that work on many platforms and degrade gracefully to handle lower end devices. Quality, usable apps are totally possible with these frameworks.
But the user doesn’t care how compatible your app is. They just want it to work, as they expect it to, on the device of their choice. In this respect, Appcelerator is unparalleled in the realm of cross platform solutions.
I have a strong suspicion that web based mobile technologies are only going to get better. I mean, let’s face it, the web isn’t going to be disappearing anytime soon. It will get faster, more functional, and closer to the expectations of the mobile user, just like desktop web browsers. And I, as a soon-to-be Appcelerator employee, welcome this.
As web based mobile development ups it game, so shall Appcelerator. Whether you’re an Appcelerator, web based, or native developer, it’s an exciting time… no matter what side of the fence you’re on.
]]>