Tuesday, November 26, 2013
Quality Software and Safe Refactoring Done Right, (Hint: You need a lot of tests)
Tuesday, November 19, 2013
The DataPhilly Meetups:
Thursday, October 31, 2013
5 Tips for Big Software Projects
Friday, September 20, 2013
Come to Chariot's Data I/O Event on October 30th and learn about all-things data
We are holding an all-day event on October 30th, downtown in the Philadelphia Cira Centre, that shines a light on large-scale data processing and application management. In this article I'm going to explain a bit about the event's goals, and some information on the speakers and talks we've been lining up.
First, the logistics. You can find out the full details and register on this page, but here are the basics:
Date/Time, etc
When: October 30, 2013Where: The Cira Centre, Philadelphia, PA Cost: $80 - includes breakfast and lunch
Speakers include
- Camille Fournier - Camille is Head of Engineering at Rent the Runway, and a committer for Apache Zookeeper. She's focused on open-source infrastructure. Zookeeper is a set of glue services that keeps a distributed application platform like Hadoop running across multiple nodes.
- Lars George - Lars George is speaking about big data from experience. He's been working on the HBase, a Hadoop database tool, since 2007, serving as the EMEA (Europe, the Middle East, and Africa) Chief Architect for Cloudera. He also authored HBase - the Definitive Guide.
- Lance Ball - The word on the street lately has been all about node.js and Javascript. Node uses a great event-driven model to process web requests. However, while Node has gotten all the hype, Vert.x has been quietly creating a storm. Vert.x is also event-driven, but it easily scales - using the JVM and the Hazelcast-based clustering mechanism to quickly expand and manage application nodes. Vert.x isn't just programmable in Javascript, but in Java, Groovy, Ruby and even Python. It can run stand-alone, in clusters, even embedded in your own applications. Lance is the creator of Vert.x, which recently moved to the Eclipse Foundation where it enjoys a vendor-neutral standing. It is girded by the Java Netty fast native-I/O API. Come see how you can get Polyglot programming, Java, Javascript, AND scaling all in one platform.
- Max De Marzi - Max is passionate about graph-based data. Any items that can be related together in a relational model usually have inferred hierarchy, but are stuck in the world of the Tuple. In neo4j, the Graph-based database from Neo Technology, you design your datasets using objects and relationships in a graph-oriented way. Max will review some key use cases, such as social networking, recommendation engines, personalization, and a number of others to see how you can leverage Neo4j to quickly handle large, interconnected datasets.
- Claudia Perlich - Claudia was a keynoter at Chariot's 2013 Emerging Technologies for the Enterprise conference, where she talked about data science as an industry. She has a strong data analysis background, holding a PhD in Information Systems from NYU, and is the Chief Data Scientist at Media Six Degrees. Claudia holds several patents, has spoken at dozens of conferences and is an author on a number of papers, journals and books.
- Grant Ingersoll - As a founder of LucidWorks, he supports the active Lucene search community. He is a committer to Solr, which is an enterprise search platform that allows for full-text searching of large volumes of traffic.
- Eric Snyder Amazon Redshift is a SQL-based clustered data warehouse with instant on-demand scaling and pay-as-you-use techniques. Eric will show you the pros and cons of this service.
- Walt Mankowski - Angle - Walt Mankowski will review several Python APIs that can do math and science calculations at the speed of C/Fortran, but with simplicity of scripting. There is NumPy, a math library that can deal with multi-dimensional data, and SciPy, which extends NumPy with scientific calculation features.
We are awaiting abstracts from a few of our speakers, but hopefully this gives you an idea of the types of topics they'll be speaking about. For $80 and a day of your time, we are providing you with a day of talks in a number of key data analysis and processing areas. Sign up today and secure your seat.
Details and registration links
Tuesday, July 30, 2013
Automated Testing of HTML5 Canvas/Single-Page Applications with Geb
The specific application I'm testing is sized for a tablet, and uses a combination of a Canvas taking up roughly 2/3 of the space and a set of JQuery Mobile widgets taking up most of the remaining 1/3 of the space (there's also a small space on top showing a read-only "status bar" with key statistics). The basic concept is an editable diagram in the Canvas, with specific edit controls in the JQuery Mobile area. You can hover, drag, and click parts of the diagram in the Canvas, which can change what's displayed in the edit area, and changes you make in the edit area can add, remove, or change elements of the diagram in the canvas as well as updating the values shown in the status bar.
My goals for the automated testing are:
- Make it easy to write tests
- Run the tests in a real browser, to ensure I'm testing what a user would actually see
- Make it easy to run a suite of tests and drill into specific test failures
- Make the tests run fast enough that it's not terribly onerous to run before every commit
- Be able to verify the visible state of the HTML showing on the screen (e.g. in the edit area, in the status area)
- Be able to verify the underlying diagram model that dictates what is drawn to the Canvas. (I haven't attempted to go as far as testing the actual Canvas state -- as in the pixel color at some specific coordinate. The bugs I get aren't that the Canvas is drawing something that does not accurately represent its model state.)
Summary of Geb
Good: All the advantages of WebDriver (which it uses under the covers), plus lots of syntactic sugar for writing tests, plus you can write functional tests in Spock or traditional tests in JUnit, TestNG, or etc. using the lovely Geb syntax. (WebDriver launches the browser and runs through the tests, clicking on various things on the screen, waiting for screens to appear, executing JavaScript as needed, etc.) Supports multiple browsers.Bad: There's no built-in way to record Geb tests by interacting with an existing Web site. Inherits the limited WebDriver support for interacting with a Canvas (requiring JavaScript workarounds). The documentation doesn't include the single simple step you need to drive single-page applications.
Bottom Line: All the advantages of WebDriver, plus fixes a lot of the WebDriver limitations. If I was considering WebDriver, I'd definitely use Geb instead.
Detailed Review
Instead of providing many language bindings like WebDriver, Geb focuses on producing an outstanding syntax using Groovy. On the one hand, it means that you have to learn and use Groovy. On the other hand, the syntax is really amazing. I think it's worth the trade.However, most of the Geb examples assume you are using Spock and writing functional tests. The tests I'm writing are probably best considered integration tests -- they're long sequences of browser activity and I expect it all to work. I find this to be a better fit for JUnit (run a long sequence of mixed actions and validations) than Spock (break up the tests into small given/when/then type groups). So for my purposes I chose to write JUnit tests.
Installing Geb
I chose to set up a Maven project so I could run my tests via "mvn test" as well as generating an IntelliJ project and using IntelliJ to write my test code. The POM has several entries to include Geb, Selenium, JUnit, and Groovy, and to enable the Groovy compiler:Geb JUnit Maven 3 POM
You should be able to run "mvn install" on that and at least confirm that the plumbing works.
Learning Curve:
Geb makes heavy use of Groovy closures, and the ability to invoke properties and methods that weren't explicitly defined. At first, I just followed the examples in the Book of Geb. Eventually things started to make a little more sense.I'm not going to describe all the Geb syntax here, as the manual does a decent job of it. I'm just going to hit the things the manual didn't cover for me.
Some of my issues were:
- The manual does clarify how to get Geb to work with single-page applications. The issue for me is that page transitions are animated and therefore are not instantaneous, so the "at checker" ran before the new page was actually visible (and therefore failed).
- I had to piece together the config file since I didn't see a complete example
- I wasn't quite clear on how to spread my tests and page object across Groovy source files
- I wasn't quite clear on whether to use inheritance or modules to reflect that fact that the Canvas is visible for every "page" (meaning a JQuery Mobile page) of the application
- It wasn't obvious how to handle a Canvas click that caused a page change, since the basic click operation in WebDriver is broken for the Canvas (as described in the previous article)
- I wanted to automate the recording of tests like I did for WebDriver directly
Config File
Here's my Geb config file for Firefox. The last two lines are necessary if you don't want to configure them as system properties for all the different ways you might run the tests. Note the code within the "driver" block is running against the WebDriver Java API.Single Page Applications
Since the browser never requests a new URL, there is no need to use "to" or "via" or set the URL for a page. You can simply point the browser to the base URL with go() and then navigate around within that.It doesn't mean you don't use multiple "pages" within the Geb tests, though. I created a Page object for every JQuery Mobile screen. I just handle the page transitions via "at SomePage" rather than "to SomePage" to tell the test that I now expect a different JQuery Mobile screen to be showing even though the URL hasn't changed.
My first stab at an "at checker" looked like this:
That doesn't account for the page animation, though. The fix turns out to be easy:
That gives the page 5 seconds (by default) to show up, more than enough. Putting the wait logic in the "at checker" is important because some other things call the at checker as a side effect, and that would have to be avoided if the at checker itself didn't handle the waiting.
Many Pages Sharing a Canvas
Since my Canvas is always visible, no matter what JQuery Mobile page you're on, I ended up creating a base Page class with all the Canvas logic (clicking on the Canvas, clicking various widgets within the canvas such as the menu button or toolbar buttons shown there, etc.). All my other Page objects inherited from that one (except the dialog pages, because you can't interact with the Canvas while a dialog is showing on the screen).Handling Canvas Clicks
I put my same JavaScript workaround for Canvas clicks in my base Page class:Then I wanted my toolbar clicks to automatically change the current Page and run the new page's at checker, just like you can do with regular clicks in Geb. I ended up invoking the Canvas click manually, and then returning some innocuous page element that Geb could use its click-and-change-page logic on.
Normal link or button that forwards to a new page:
Toolbar button in the Canvas:
Since the content entry returns a legitimate Geb Navigator object (after clicking the Canvas), you can call click() on the content entry. When you call click on it, it changes the page per the to: NewPage directive (including calling the at checker on the new page), even though the click on #someBoringElement did nothing at all.
And the test ends up looking like this:
That's not strictly necessary -- you could put in all the at checks explicitly, and I suppose it could make the test clearer. But I prefer to have them all run as a convenient side effect of navigating.
Source Code Organization
I ended up putting all my Page definitions in a single TestSupport.groovy file. They were all pretty short and closely related, and I didn't want to clutter up my project with lots of tiny files. I think a consequence of this is that I needed to do a "full build" more often since the dependencies across files weren't as obvious, but builds were fast and that didn't bother me.For my tests, I created several XYZTest.groovy files, since Maven by default runs tests with the *Test.* naming convention. It was easy to put several related tests in each file with the JUnit @Test annotation:
Recording Tests
There's an up side and a down side here. The up side is, I was able to record tests by including a custom "QA" JavaScript file in my app, which added listeners to buttons and links and pages and so on. It emits the appropriate Geb code to the Web console, which then I copy and paste into a test class. The down side is, it relies a lot on referencing page elements by their ID. That works fine, but it sort of misses the point of the PageObjects pattern. It's very easy in Geb to define all the page widgets in a content block, but when recording the tests, I know that an element with a particular ID was clicked, but I don't know what you decided to call that element in the content block of the page element.It's possible I could settle on a convention of always naming elements in the content block the same as their ID, but even that avoids some of the nice syntax available with Geb.
For instance, I have a screen with four items in a glorified list, but every time you go to the screen, the specific content of the four items might be different (one screen tries to pick the best four for you, another is the same screen no matter which of many categories you're viewing, etc.). So the IDs are pretty generic, like ListItem0, ListItem1, ListItem2, ListItem3. It makes it easy to loop over them and so on.
I can set up a content entry in Geb like this:
Then my test can click an item and cause an implicit navigation to the detail page and run the at checker for the detail page all very easily:
But again, the test recorder doesn't know about that, so it can only generate code like this:
Does it do the same thing? Yes. But it's more lines, uglier lines, and the test would break if the list IDs ever changed -- exactly the reasons the PageObjects pattern exists.
So I end up with a mix of somewhat uglier tests that I recorded, and somewhat prettier ones that I wrote by hand.
Here's what the recorder script looks like now:
And a generated test:
Whereas a handcrafted test might look a little cleaner:
Running Tests
Running tests is as easy as "mvn test" or right-clicking on a test file or test method in IntelliJ (or however else you prefer to run JUnit tests). I get a summary of tests run, passed, and failed, green or red bars, etc. I find that IntelliJ is a little better at putting the specific error in front of me for a test failure, whereas I have to hunt a little more with Maven, but either way works. It's a big improvement over plain WebDriver code.Thursday, July 25, 2013
PhoneGap 3.0
PhoneGap 3.0 was released at PhoneGap day in Portland, OR last week. There are some great changes with this new release. Historically PhoneGap and Cordova, the open source project behind PhoneGap, were almost identical. This has changed with the release of 3.0.
Prior to 3.0, PhoneGap was distributed as an archive which was downloaded and unzipped to install. Now, both PhoneGap and Cordova are distributed as command line tools, which are installed via the node.js package manager, npm. Both Cordova and PhoneGap can be installed on your machine at the same time.
$ npm install phonegap -g
$ npm install cordova -g
The command line tools provide scripts to create projects, add platforms (iOS, Android, BlackBerry, Windows Phone, etc), compile and deploy projects. The new structure makes it easier to support multiple platforms with one project.
$ cordova create hello com.example.hello Hello
$ cd hello
$ cordova platform add ios
$ cordova platform add android
$ cordova emulate
With 3.0, the Cordova distribution provides the core functionality to embed a webview (browser) into a native application. Cordova is distributed without any of the plugins installed. This allows you to only install the functionality you need, simplifies your code base, and reduces the amount of code in your app.
To use the Camera APIs, we'd install the camera plugin.
$ cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git
Raymond Camden's blog post about Cordova 3.0 for a list of core plugins.
PhoneGap is a distribution of Cordova, similar to how Safari and Chrome are based on Webkit. The PhoneGap distribution of Cordova come with all of the core plugins installed. Additionally the PhoneGap command line adds features like PhoneGap build support. If you don't have a native SDK installed, the compiling the project can be delegated to PhoneGap Build.
$ phonegap create example
$ cd example
$ phonegap run wp7
Overall these are great changes for PhoneGap, but may require a changes to your workflow. The payoff is that it's easier to create projects, manage plugins, and support multiple platforms.
Friday, July 12, 2013
Android Advanced Cursors
If not, you can head over to Lars Vogel's excellent tutorial website to see how it all works, or to get a refresher.
For many applications, the basic Cursor is all you need. But what about more advanced requirements? What follows is an overview of some of the more advanced cursor options.
CursorJoiner
If you need data from two or more database tables, the most straightforward thing to do is to use a SQL query that joins the two tables. However, sometimes you already have sources for two separate queries (such as a CursorLoader based on a ContentProvider), and you may wish to just re-use them, without creating a new query (without, e.g., modifying the ContentProvider).This is where CursorJoiner comes in handy. Unlike the other options listed below, CursorJoiner doesn't produce a new cursor. Instead, it provides an Iterable interface over the joined cursors.
If the only reason that you want to join the two tables is to produce a Cursor, say, for use by a CursorAdapter, then you should probably just stick with writing SQL that joins the two tables. However, if you just want to iterate the data once, then CursorJoiner can be very helpful.
One of the more interesting uses that I've seen for CursorJoiner is for determining what has changed when a
LoaderManager.LoaderCallbacks<Cursor> implementation gets an updated Cursor in it's onLoadFinished method.
You can use the CursorJoiner to join the 'old' cursor and the 'new' cursor on their primary key, and then compare them. As you iterate the CursorJoiner, you get a CursorJoiner.Result enum that indicates whether the current row exits in the left cursor, the right cursor, or both.
Here is some sample code that determines what has been added to or deleted from a ContentProvider as a CursorLoader driving a CursorAdapter is updated:
@Override
public void onLoadFinished(Loader<cursor> loader, Cursor updatedCursor) {
if(adapter.getCursor() != null) {
Cursor oldCursor = adapter.getCursor();
CursorJoiner joiner =
new CursorJoiner(oldCursor,
new String[] {Thing.ID},
updatedCursor,
new String[] {Thing.ID}
);
for(CursorJoiner.Result joinerResult : joiner) {
switch (joinerResult) {
case RIGHT:
int thingId = updatedCursor.getInt(
updatedCursor.getColumnIndex(Thing.ID)
);
String thingName = updatedCursor.getString(
updatedCursor.getColumnIndex(Thing.NAME)
);
Log.d(TAG, "new Thing added - id: " + thingId
+ ", name: " + thingName);
break;
case LEFT:
int thingId = updatedCursor.getInt(
oldCursor.getColumnIndex(Thing.ID)
);
String thingName = updatedCursor.getString(
oldCursor.getColumnIndex(Thing.NAME)
);
Log.d(TAG, "Thing deleted - id: "
+ thingId + ", name: " + thingName);
break;
case BOTH:
int thingId = updatedCursor.getInt(
oldCursor.getColumnIndex(Thing.ID)
);
String thingName = updatedCursor.getString(
oldCursor.getColumnIndex(Thing.NAME)
);
Log.d(TAG, "Thing unchanged - id: "
+ thingId + ", name: " + thingName);
break;
}
}
updatedCursor.moveToFirst();
adapter.swapCursor(updatedCursor);
}
MatrixCursor
MatrixCursor is useful if you have a collection of data that is not in the database, and you want to create a cursor for it. You simply construct it with an array of column names, and optionally an initial capacity. Then, you can add one row at a time to it by passing either an array of objects or an Iterable to its addRow() method. Then use it like any other cursor:
String[] columnNames = {"Column1", "Column2"};
MatrixCursor matrixCursor = new MatrixCursor(columnNames);
matrixCursor.addRow(new String[]{"value1", "value2"});
adapter.swapCursor(matrixCursor);
MergeCursor
MergeCursor allows you to present two or more cursors as a single cursor. You could get almost the same effect by doing a sql UNION query. However, MergeCursor allows you to have different columns in the various cursors, and still merge them.This is very useful if you are presenting a list of heterogeneous items. I've used it with Emil Sjölander's StickyListHeaders library, using a different cursor for each 'section', all presented to the StickyListHeader implementation as a single cursor via a MergeCursor.
One thing to be aware of when presenting heterogeneous items through a MergeCursor - you'll probably want to add a pseudo-column to each of the cursors to make it easy for your ListAdapter (or whatever will be using the cursor) to be able to determine which type of data it's dealing with on each row. A seemingly little-known trick here is that you can include literal columns when creating a cursor using the ContentProvider's query method (and similar methods in other database classes). Just include the literal in the projection parameter to the query:
String projection = {Thing.ID, Thing.NAME, "'TYPE_THING' as TYPE"};
Cursor c = qBuilder.query(mDb,
projection,
selection,
selectionArgs,
groupBy,
having,
sortOrder);
CursorWrapper
Finally, CursorWrapper is a Wrapper class for Cursor that delegates all of its calls to the actual cursor object. As the documentation stated, the primary use for this class is to extend a cursor while overriding only a subset of its methods.One example for the use of CursorWrapper is when you already have a cursor, but only want to present the first few rows of the cursor to a CursorAdapter. Override the getCount() method to return a number smaller than the actual cursor's count, and the adapter will only present that number of results. This is similar to what you would have gotten had you added a LIMIT clause to the sql that produced the cursor.
With this collection of advanced Cursor tricks, you should be able to accomplish whatever you want with Cursors and Adapters.