Prototypal Inheritance & Strategies for Debugging Tough Problems

I recently ran into an issue on app-UI where child views were having their touch/mouse event listeners removed once another view was pushed onto the stack in the ViewNavigator component.

If you haven’t seen it yet, app-UI is a collection of reusable “application container” components for building native-like mobile experiences for apps built with web technologies.   It is still in the very early stages of development, and I’m actively working on it… so please let me know if you run into any issues or suggestions.

I scoured through all of my application and framework code, but just couldn’t seem to figure out why/where event listeners were being removed.   What I needed to do was simple, figure out where “removeEventListener” was being invoked.  “removeEventListener” is a native function, so you can’t set a breakpoint to see every instance where it is being invoked, right?

Actually, you can, but you have to look at the problem just a bit differently…

You can’t set a breakpoint on a native function, however, since JavaScript uses prototypal inheritance you can change the prototype of an object to change its behavior and override native functions.  Since you can modify an object prototype, changes to that object’s prototype will be applied to all instances of that object type.   So, you can add some debugging code to override the behavior of HTMLElement’s “removeEventListener” function.

First, make a copy of the original removeEventListener function on the HTMLElement.prototype:

HTMLElement.prototype.originalRemoveEventListener
        = HTMLElement.prototype.removeEventListener

Next, override the original removeEventListener function, add a console.log() statement, and then invoke the original removeEventListener function that you just made a copy of:

HTMLElement.prototype.removeEventListener = function(type, listener, useCapture)
{
    console.log('remove: ' + type);
    this.originalRemoveEventListener(type, listener, useCapture);
};

Now, every time that the HTMLElement’s removeEventListener function is invoked, you will get a console.log() statement.  Not only do you get console debugging, but you can now set a breakpoint inside of the new, overridden, removeEventListener function.   Using the breakpoint, you can use your developer tools to view the call stack and track down where the removeEventListener function is being invoked. Thus, you can track down the root of your issue.  I use the Chrome developer tools, but similar tools are also available in Safari, FireFox, IE, and Opera.

Using the call stack, I was able to track down that I was inadvertently calling jQuery’s remove() function on the view’s DOM element, instead of jQuery’s detach() function.  Both remove() and detach() will remove your elements from the page’s DOM, however remove() also gets rid of any event listeners to prevent memory leaks. When I made the one-line code change from remove() to detach(), everything resumed working as expected. I then removed the debugging code.

Here’s the complete code in one snippet for overriding removeEventListener:

HTMLElement.prototype.originalRemoveEventListener
        = HTMLElement.prototype.removeEventListener;

HTMLElement.prototype.removeEventListener = function(type, listener, useCapture)
{
    console.log('remove: ' + type);
    this.originalRemoveEventListener(type, listener, useCapture);
};

Prototypal inheritance gives you the ability to change the behavior of objects at runtime, and it can be incredibly powerful in building your HTML/JS applications.

Transcript from Open Session on PhoneGap

Yesterday Raymond Camden and I hosted an open session on PhoneGap. It was an opportunity for the community (you) to ask us questions. There was a great turnout, and we’ll likely be hosting another one of these sessions in the near future. Thanks to everyone who attended!  Check these links to see the full Q&A transcript, and the full chat transcript, or download them directly from Ray’s blog.  (Please excuse the typos, we were answering these live, in real time, without any edits.)

Many of the questions were around the roadmap for PhoneGap/Cordova. You can access the PhoneGap/Cordova roadmap at: http://wiki.apache.org/cordova/RoadmapProjects

Feel free to post any additional questions, and stay tuned for the next open session.   If you have any feedback on how we could improve this session, please let us know!

A Response to “Shell Apps and Silver Bullets”

There is an article floating around the web today, warning against “Shell Apps” and tools like PhoneGap.  The logic in this article has a few arguments that are misleading, and I’d like to introduce some counter arguments as they relate to PhoneGap and HTML experiences for comparison.

The “Silver Bullet”

First, the “Silver Bullet” argument… I have never seen it stated anywhere that PhoneGap is a “Silver Bullet” that will solve every problem for every application developer.   PhoneGap is a tool for developing applications.  It enables developers to build applications in situations where they may not have otherwise, including:

  • No knowledge of native development
  • Existing web development skills
  • Reuse of assets across platforms or leverage existing code/assets
  • Lower barrier of entry in the mobile app world

PhoneGap isn’t a “magical” solution to end all other solutions.  It is a toolset that enables you to build & bundle natively installed applications using web technologies.  For more detail on what exactly PhoneGap is, see this post “PhoneGap Explained Visually“.  If you’d like to understand the motivations behind PhoneGap/Cordova, then look no further than the PhoneGap blog.

If you were building a house, would you use a butter knife to drive nails?  Or, would you use a sledgehammer for finishing touches? If you needed lumber for your house, would you go cut down a tree, cut some beams out of it for use in your house frame?  No, You wouldn’t do any of these.  You would use the right tool for the job, and you would use raw materials that you already have available or are easily accessible.

Chances are, if you are building an app, you would do the same thing.  There are cases where PhoneGap is not the best choice, but that does not mean there aren’t a huge number of cases where PhoneGap is a great choice (if not the best).  It does not make sense to have to rebuild everything from the ground up, or have to learn completely new skills just to build apps for a mobile platform.

Increasing Complexity

The article also makes claim that HTML/JS based apps are more complicated than native apps:

At first things are easy. For simple screens, using a webview might be faster than writing a native implementation. As you add functionality to the webview, the complexity increases until you give up and write everything native.

This is far from the truth.  There are 2 facts that are completely overlooked in this statement:

  1. You can write a “bad” or overly-complex application in any langauge.  Native development is not a silver bullet that prevents you from building “Bad” apps.
  2. Native applications can also be extremely complicated – they are not inherently more simple.

Regardless of the underlying technology, the more features, views, data models, and components that you have within an application will add to the overall complexity of that application.  This is precisely why people apply model-view-controller (MVC) development paradigms and software design patterns.

PhoneGap and hybrid/web development techniques are no exception to this rule.  You can create really simple apps very quickly without a high degree of computer programming skill, but creating complex applications requires real software development processes.  MVC, abstraction, encapsulation, separation of concerns, etc… all apply.  You can absolutely build complex applications with web technologies, but you must approach them in a structured manner – just as you would approach an enterprise-quality native application. If you do not approach a complex problem with proven software design principles from the beginning, you risk setting yourself up for failure regardless of the underlying technology.

I have significant experience in developing native applications, interactive development, HTML/JS, as well as developing with cross platform technologies.  Based on my own experience, I am far more productive with HTML & JS/PhoneGap than I am with native development, and I can create applications that are just as complex.

That does not mean everyone will be the same as me.   A developer who comes from either the Objective-C or Java worlds and does not know HTML will likely be more productive with native development – once they learn the libraries and paradigms for native mobile development. Likewise, developers who are already proficient with interactive development for the web will be more productive using web technologies.  One cannot make generalizations about a software tool or productivity when the use cases and developer skills are so widely varied.

The Framework Tax

The article makes the claim that you end up paying a “tax” by using frameworks such as PhoneGap:

You could use an open source shell-app framework like PhoneGap, but that leaves you at the mercy of their schedule. If the native platform introduces a new API, or you run into an edge case that requires extending the shell framework, it could be months before you can implement your own app’s functionality.

Again, this is not entirely accurate.  The goal of PhoneGap is not to recreate & mirror every native API on every platform.  Rather, to provide a consistent API for building your applications across multiple platforms, using familiar web development skills, and to push the web forward.   There are certainly APIs on all platforms that it does not support.

Luckily, PhoneGap is built on top of an extensible architecture, so that if you wanted to take advantage of a new API, you can create your own native plugins (yes, in native code) to expose that functionality for use within your PhoneGap applications.  If you do not want to wait on the PhoneGap/Cordova open source initiative, then you can build it yourself without delay.  You do not need to fork the framework for this, rather you extend it within your own projects.   There’s also a good chance that someone has already written a native plugin and posted it on github that you can reuse.

Browser Fragmentation

Well, you have a point there… to a point. There are definite browser fragmentation issues.   Webkit on iOS != Webkit on Android != Webkit on BlackBerry != IE/Trident on Win Phone, etc…  However, this is generally related to presentation styles, not core browser functionality.  It is important to use tools like caniuse.com when you are evaluating your development strategy and modernizr during implementation phases (for graceful degradation).  While there are variations in the browsers, it doesn’t mean that your architectural patterns, your business logic, or your data model are going to be different.

Different browsers on different platforms also have different performance metrics, and you need to build your application experience based on what you are trying to create. Do not try to force a slow browser to be fast; that will never work.

Versioning

The versioning argument in that article sates “hybrid apps allow you to update” is not entirely true:

Shell app let you update content without requiring a full app release by serving your pages off a server. In the process, you lose release atomicity, the assurance that whatever you ship to clients comes in one complete, unchanging bundle.

Yes, you can serve web pages, and if you have native content around the web content, then it could be mismatched.  However, it is important to understand that you can’t create apps with HTML technologies that update their own code withinin the local app bundle on the device based off of code downloaded from a server.

If you build an app that bypasses Apple’s App Store and updates itself automatically, it will get rejected.   You may be able to pull down data/content or images and cache them locally, but a “full app release” is not possible.   The Apple Developer Agreement explicitly says in section 2.7:

Apps that download code in any way or form will be rejected

Likewise, “Users may wait weeks or months to update apps” applies to native development as well. If your users don’t update, then they don’t update.  In this case the mobile branding may not match the website branding.  This happens regardless of technology choice.

The Uncanny Valley

There is merit to the uncanny valley argument (html based apps don’t always feel “right”), but that does not mean it is impossible to build native-feeling applications using HTML and JavaScript.  The trick is that you must design these apps to feel like applications, not like web pages.  Here are a few apps that are built using HTML-based technology: Apple StoreFacebook, LinkedIn, Wikipedia, Mafia Wars, US Census Browser, Bit Timer, Untappd, and even the “revolutionary” iAd advertising experience from Apple are all built on top of HTML.  (This is by no means a definitive list of all HTML-based apps either.)

Some of these apps you might already use on a daily basis. The “uncanny valley” argument really comes down to UX design, and giving your HTML application a first-rate experience.  If you do not invest in your user experience, it will not feel right.  Some of these apps show up in Apple’s recommendation lists… would Apple recommend bad apps to us in the “walled garden” that they have worked so hard to curate?

Performance

Again, this is a question of using the right tool for the right job.   You would likely not build a 3D modelling application using HTML/JS, but you could easily build a word game experience, an enterprise data reporting front-end client, or content-centric experience using HTML & JavaScript.  There are things that you need to do to make sure your HTML-based experiences perform well, such as using touch events instead of mouse events (mouse events in web views can have an OS lag up to 3-400 MS, where touch events do not).  Or, using CSS3 translate3D transforms to enable GPU-rendering on DOM content. Perception of an application boils down to creating a proper user experience.  You can absolutely create a great user experience with HTML & related technologies, but I wouldn’t use it for super-computing tasks.

If your app requires intense data crunching for a computationally intensive task, you can always drop down to a PhoneGap native plugin to perform the heavy lifting for you.

Write Once, Run Everywhere

When was the last time you saw a computer or device that could not render HTML content?   I have several devices at my disposal for work: 3 Android devices, 2 iOS devices, 1 Windows Phone, 1 Blackberry, and a Macbook.  None of these devices is incapable of rendering web content.  HTML is the most widely distributed and pervasive means of presenting digital information in a visual manner, and it has been around for decades.

The Right Tool

As mentioned in the original post, use the right tool for the job. Don’t force a solution that doesn’t fit, but also don’t over-generalize your technology decisions based upon incorrect assumptions. I can build a responsive layout with dynamic content far easier in HTML than I can in native Objective-C, but building a triple-A quality game isn’t even close to achievable in HTML. It all depends on context:

  • What are you trying to build?
  • Who are you building it for?
  • What are the UX requirements?
  • Who is building it, and what are their skills?
  • What is your budget?

There is no doubt or question in my mind – You can absolutely build incredible app experiences that truly feel like apps using web based technologies.

Open Session on PhoneGap

Curious about PhoneGap? Have questions? Tomorrow, fellow Adobe Evangelist Ray Camden and I are hosting a 2 hour Adobe Connect session on PhoneGap. This will be an open session for your questions, not a presentation. The Connect URL is: http://my.adobeconnect.com/adobehtml. The date/time is Tuesday 2PM EST to 4PM EST (11AM PST to 1PM PST).

Debugging App-UI with Adobe Shadow

Adobe Shadow has been out for over a month now, and I’ve finally had a chance to start integrating it into my development workflow.  Shadow is a new tool that provides you with a synchronized desktop & mobile browsing experience, and it even lets you inspect & modify the HTML DOM on the remote devices.  Basically, you just connect the devices, then navigate your content on any of the connected devices for a synchronized browsing experience. Fellow Adobe employee Christian Cantrell has a great video overview of Adobe Shadow on his blog, if you’d like to learn more.

I’ve been focusing on multi-platform HTML-based solutions, especially with the app-UI framework/library.  Shadow has become very handy when testing features on multiple devices.  App-UI is a free & open source collection of reusable “application container” user interface components that may be helpful to web and mobile developers for creating interactive applications using HTML and JavaScript.

Basically, I just point the desktop Chrome browser at the page I want to test on my devices, and all devices will navigate to that particular page.  Quick, easy, and to the point.   Check out the video below where you can see the synchronized browsing experience in action.

In my examples that have browser history integration you can even see that selecting an item in the list causes all devices to navigate to the selected item (starting at 25 seconds into the video).  It does not yet necessarily solve every issue around button clicks and scrolling, but it certainly helps streamline the testing of a single page/experience on multiple devices.

Enjoy!