Archive

Learning Calatrava

Jason / February 12, 2014

I’ve been playing around with Calatrava recently, and it’s been pretty interesting. The most exciting aspect of it is their approach to cross platform. They push for re-usable middleware (e.g., shared applicaiton logic) while leaving the UI layer native.

Shared Logic

Interestingly enough, the shared logic is in CoffeeScript. Thusly it can even be shared across other platforms such as Ember.js and Node.js – provided the logic was reusable enough by nature.

My only complaint so far is the project’s poor documentation. For example, Calatrava supports native UIs on both iOS and Android, but the sample app generated by running calatrava create MYAPP only shows a native UI on iOS. The Android app generated is using a web view.

For starters, you’ll need to change the ConversionForm class (located in droid/MYAPP/src/com/MYAPP/) to inherit from com.calatrava.bridge.RegisteredActivity. So, this:

Becomes:

Next, you’ll mostly gut the existing implementation of ConversionForm (leave the getPageName method, everything else goes) and override getFieldValue and render:

The getFieldValue method serves as a bridge between CoffeeScript and native. Specifically it allows Calatrava to know what values are currently on the screen. So, for a text field, it might look like:

((EditText)this.findViewById(R.id.my_field)).getText().toString();

So, in order to write this method you’ll need to create a layout file. Call it conversion_form.xml and place it under droid/res/layout:

Now revisit the action, and override onCreate:

If you run the app right now by running rake droid:deploy you’ll be greated with your custom view, but it’s not functional yet. With that out of the way, let’s revisit our getFieldValue method.

If you look at the iOS sample app you’ll get an idea of how this method should be implemented:

Alternatively you could have looked at controller.converter.coffee under kernel/app/converter and looked for all calls to views.conversionForm.get to see which view controls are referenced by this controller. In this case, it’s referencing:

  • in_currency
  • out_currency
  • in_amount

Let’s wire those up to our layout by implementing the getFieldValue method:

For now, let’s just hard code the input and output currency type. We have, however, implemented the in_amount field so we are actually bridging our native view to Calatrava (albeit just in one direction). In order to fire events in the CoffeeScript view controller, we’ll use the com.calatrava.bridge.RegisteredActivity.triggerEvent(String event, String... extraArgs) method. Luckily for us, our activity is a RegisteredActivity and we can therefore call triggerEvent on this. Doing this will directly call a CoffeeScript method, passing in any arguments. In our case we want to call the convert method, and we don’t need to pass in any arguments. Wrapping this up in a similarly named method gives us:

And, finally, the last piece of the puzzle is to fully implement the render method so that values can be passed from Calatrava into your native view. On Android Calatrava will supply a String containing JSON, it’s up to the implementation of Render to parse it. Other than that small difference between iOS and Android, looking again at the ConversionFormView.m reveals the intent of this method:

Looping over the key/values, the render method will attempt to match each key to the name of a UI element and bind it’s value. An implementation for Android would look like:

Unfortunantly running this code as-is results in a runtime error. Seemingly Calatrava calls render from a non-UI thread, resulting in the following crash:

E/AndroidRuntime(13246): org.mozilla.javascript.WrappedException: Wrapped android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. (calatrava/scripts/bridge.js#34) read more

Archive

Hacking Bluetooth LE

Jason / February 10, 2014

Inspired by recently reading an article on Hack a Day about emulating Bluetooth LE with a cheap nRF24L01+ module, I decided to take the plung and order some off eBay. I ended up spending $11.96 for ten units with shipping included, so about $1.20 per unit. More than enough extras to have some fun 🙂 read more

Archive

A New Blog

Jason / February 9, 2014

After having been out of the blogging space for some time now, I figured I was overdue to start my blog back up again.

I’m using Jekyll and Github Pages to power this site. So far it’s been a pretty simple process, and I’m impressed with how flexible this system is. Working with complex systems on a daily basis, it was nice to know that I could get my blog back up and running without messing with web hosting (and monthly costs), a database and webserver to configure. Not that I couldn’t, and not that I haven’t in the past, but the simplicity of Jekyll is refreshing. read more

.NET, Archive, Software Design

Software Design Tip of the Fortnight: Tip #2

Jason / December 20, 2008

For this second installment of Software Design Tip of the Fortnight I want to talk a little about exceptions. Exceptions in .NET provide an excellent means of handling errors. We all know not to use exceptions for flow control, but there are many other ways to abuse exceptions.

Abusing exceptions can be anything from throwing the base Exception class, to throwing more than just exceptions. But the most common abuse of exception handling is to simply suppress them. We have all seen applications that do something similar to:

SomeBusinessObject bo = SomeBusinessObject.LoadWithId(4);
try{
    bo.SomeIntValue = int.Parse(txtSomeTextField.Text);
}catch{
   //the value wasn't int... so ignore it.
}
bo.Save();

The problem with suppressing exceptions is that most components don’t just throw them for the fun of it, there is some underlying reason why the exception was thrown in the first place.

The above example appears innocent enough. Int32’s Parse method throws an exception if it cannot parse the input string. But what if in the future another developer decides that the business object’s SomeIntValue needs a certain business rules that limits the acceptable values.

public class SomeBusinessObject{ //other class code public int SomeIntValue{ get{ return _someIntValue; } set{ if(value < 0) throw new BusinessRuleException("Invalid value for SomeIntValue."); _someIntValue = value; } } } read more

Archive, ASP.NET

Comparing Deployed ASP.NET Sites With NDepend

Jason / December 15, 2008

Few things compare to the experience of inheriting an existing software project when (for whatever reason) none of the original developers are with the company. I have been in the situation a couple of times myself and it never fails, you inherit the code base just in time to fix a bug or implement a new feature.

One of my concerns whenever this happens is whether the deployed version of the website matches the latest version in source control. In an ideal world the source control system would have been tagged when the last deployment took place and their would be little guess work. But live is seldom this ideal. In reality their is often no indication of when and what was last deployed into production short of the binaries residing on the server.

Fortunately NDepend has a lot of powerful features that help with this exact predicament. For those of you who have never used NDepend it is a very powerful static code analysis tool for .NET, and contains more features than I could possibly do justice to here. For those interested Scott Hanselman wrote a great review here, and there are also several screencasts on the NDepend website.

Comparing Binaries

To demonstrate this I am going to compare my currently deployed blog (which I happen to know is running dasBlog version 2.3) to a known version of dasBlog 2.2. To get started make sure you have local copies of both sites you want to compare, and fire open your copy of NDepend.

To compare source files you do not need to even create a project file. You simply need to select “Choose Assemblies or Analysis to Compare” from the “Compare” menu of the Visual NDepend GUI.

For this demonstration I am going to compare only the newtelligence assemblies shipped with dasBlog, but you will want to compare the assemblies to represents you own custom code. For example, if you consumed the NHibernate ORM you wouldn’t want to necessarily compare NHibernate.dll.

Once you have selected the assemblies you want to compare and clicked “OK” NDepend will begin the process of analyzing the assemblies. Depending on the number and size of the assemblies this could take a few moments. But as a reward for your small wait you will be soon greeted by more than enough code metric to keep even the most scrutinizing of people happy.

Mining The Results

Once the code analysis has been performed we can begin the task at hand of finding the differences between the two versions of the site. For this task their are two areas of the main screen that are of concern. The Class Browser and the CQL Queries window.

The Class Browser is very intuitive for anyone familiar with Visual Studio and simply provides a high level overview of Assemblies, Namespaces, and Types. For instant gratification NDepend kindly provides via a context menu option. From the Class Browser right-click on one of the assemblies you compared and select “What was changed?” and then “SELECT METHODS FROM ASSEMBLIES … WHERE CodeWasChanged”. In place of the Class Browser you will see a list of methods that are different between builds.

Behind the scene NDepend issue what it calls a CQL (Code Query Language) query against its internal database it compiled during the code analysis. This database contains all kinds of helpful information about your source code. Using CQL we can do much more than just select methods that have changed. We can apply any number of constraints to what is returned. For example, you may not be concerned about unused methods even if they do differ. Using CQL you can word that like:

SELECT METHODS FROM ASSEMBLIES "newtelligence.DasBlog.Web" WHERE CodeWasChanged AND ( MethodCa > 0 OR IsPublic OR IsEntryPoint OR IsExplicitInterfaceImpl OR IsClassConstructor OR IsFinalizer ) read more