Howard Lewis Ship's complete blog can be found at: http://tapestryjava.blogspot.com

Items:   1 to 5 of 111   Next »

Friday, April 20, 2012

Spock's built-in mock object capabilities are just a dream to use ... unlike other systems I've used, it doesn't get in your way, or force you to think backwards or inside out. Once again, some listings. These are for tests of Tapestry IoC's AspectDecorator service, which is used to create a wrapper interceptor around some other object. The test below shows how a supplied MethodAdvice callback object is invoked by the interceptor, if the advice is associated with the invoked method.

TestNG with EasyMock (Java)

Even this example is a bit streamlined, as some of the mock object capabilities, such as methods newMock(), replay() and verify() are being derived from the TestBase base class.

Spock

Spock's wonderful when: / then: blocks organize the behavior into a stimulus followed by a response; using EasyMock, you have to train the mock objects for the response before introducing the stimulus (the method invocation). Further, with EasyMock there's one API for methods that return a fixed response, a second API for methods that throw an exception, and a third API for methods where the result must be calculated; in Spock the value after the >> operator is either a literal value, or a closure that can do what it likes, such as the one attached to MethodAdvice.advice() that checks for the expected method name, and then proceed()s to the delegate mock object's method.

I think that a reasonable developer, even without a thorough understanding of Spock, would get the gist of what this test does (perhaps with a little side note about the interaction system inside the then: block). On the other hand, I've seen when training people with TestNG and EasyMock that it very rarely sinks in immediately, if at all.


Thursday, April 19, 2012

I'm gradually converting a back-log of existing tests to Spock ... and some of them convert so beautifully, it hurts. Here's an example:

Before (Java and TestNG)

After (Spock)

What a difference; the data-driven power of the where: block makes this stuff a bit of a snap, and you can see in once place, at a glance, what's going on. IDEA even lines up all the pipe characters automatically (wow!). It's obvious how the tests execute, and easy to see how to add new tests for new cases. By comparison, the TestNG version looks like a blob of code ... it takes a bit more scrutiny to see exactly what it is testing and how.

In addition, the propertyMissing() trick means that any property (including public static fields) of Calendar is accessible without qualification, making things look even nicer. This is what they mean by writing an "executable specification", rather than just writing code.

I can't say this enough: using any other framework for testing Java or Groovy code would simply not be logical.


Saturday, March 10, 2012

One of the fears people have with Node is the callback model. Node operates as a single thread: you must never do any work, especially any I/O, that blocks, because with only a single thread of execution, any block will block the entire process.

Instead, everything is organized around callbacks: you ask an API to do some work, and it invokes a callback function you provide when the work completes, at some later time. There are some significant tradeoffs here ... on the one hand, the traditional Java Servlet API approach involves multiple threads and mutable state in those threads, and often those threads are in a blocked state while I/O (typically, communicating with a database) is in progress. However, multiple threads and mutable data means locks, deadlocks, and all the other unwanted complexity that comes with it.

By contrast, Node is a single thread, and as long as you play by the rules, all the complexity of dealing with mutable data goes away. You don't, for example, save data to your database, wait for it to complete, then return a status message over the wire: you save data to your database, passing a callback. Some time later, when the data is actually saved, your callback is invoked, and which point you can return your status message. It's certainly a trade-off: some of the local code is more complicated and bit harder to grasp, but the overall architecture can be lightening fast, stable, and scalable ... as long as everyone plays by the rules.

Still the callback approach makes people nervous, because deeply nested callbacks can be hard to follow. I've seen this when teaching Ajax as part of my Tapestry Workshop.

I'm just getting started with Node, but I'm building an application that is very client-centered; the Node server mostly exposes a stateless, restful API. In that model, the Node server doesn't do anything too complicated that requires nested callbacks, and that's nice. You basically figure out a single operation based on the URL and query parameters, execute some logic, and have the callback send a response.

There's still a few places where you might need an extra level of callbacks. For example, I have a (temporary) API for creating a bunch of test data, at the URL /api/create-test-data. I want to create 100 new Quiz objects in the database, then once they are all created, return a list of all the Quiz objects in the database. Here's the code:

It should be pretty easy to pick out the logic for creating test data at the end. This is normal Node JavaScript but if it looks a little odd, it's because it's actually decompiled CoffeeScript. For me, the first rule of coding Node is always code in CoffeeScript! In its original form, the nesting of the callbacks is a bit more palatable:

What you have there is a count, remaining, and a single callback that is invoked for each Quiz object that is saved. When that count hits zero (we only expect each callback to be invoked once), it is safe to query the database and, in the callback from that query, send a final response. Notice the slightly odd structure, where we tend to define the final step (doing the final query and sending the response) first, then layer on top of that the code that does the work of adding Quiz objects, with the callback that figures out when all the objects have been created.

The CoffeeScript makes this a bit easier to follow, but between the ordering of the code, and the three levels of callbacks, it is far from perfect, so I thought I'd come up with a simple solution for managing things more sensibly. Note that I'm 100% certain that this issue has been tackled by any number of developers previously ... I'm using the excuse of getting comfortable with Node and CoffeeScript as an excuse to embrace some Not Invented Here syndrome. Here's my first pass:

The Flow object is a kind of factory for callback wrappers; you pass it a callback and it returns a new callback that you can pass to the other APIs. Once all callbacks that have been added have been invoked, the join callbacks are invoked after each of the other callbacks have been invoked. In other words, the callbacks are invoked in parallel (well, at least, in no particular order), and the join callback is invoked only after all the other callbacks have been invoked.

In practice, this simplifies the code quite a bit:

So instead of quiz.save (err) -> ... it becomes quiz.save flow.add (err) -> ..., or in straight JavaScript: quiz.save(flow.add(function(err) { ... })).

So things are fun; I'm actually enjoying Node and CoffeeScript at least as much as I enjoy Clojure; which is nice because it's been years (if ever) since I've enjoyed the actual coding in Java (though I've liked the results of my coding, of course).


Friday, March 9, 2012

One of the fears people have with Node is the callback model. Node operates as a single thread: you must never do any work, especially and I/O, that blocks because it will block the entire process. Instead, everything is organized around callbacks: you ask an API to do some work, and it invokes a callback function you provide when it is done, at some later time. There are some significant tradeoffs here ... on the one hand, the traditional Java Servlet API approach involves multiple threads and mutable state in those threads, and often those threads are in a blocked state while I/O (typically, communicating with a database) is in progress. However, multiple threads and mutable data means locks, deadlocks, and all the other unwanted complexity that comes with it.

By contrast, Node is a single thread, and as long as you play by the rules, all the complexity of dealing with mutable data goes away. You don't, for example, save data to your database, wait for it to complete, then return a status message over the wire: you save data to your database, passing a callback. Some time later, when the data is actually saved, your callback is invoked, and which point you can return your status message. It's certainly a trade-off: some of the local code is more complicated and bit harder to grasp, but the overall architecture can be lightening fast, stable, and scalable ... as long as everyone plays by the rules.

Still the callback approach makes people nervous, because deeply nested callbacks can be hard to follow. I've seen this when teaching Ajax as part of my Tapestry Workshop.

I'm just getting started with Node, but I'm building an application that is very client-centered; the Node server mostly exposes a stateless, restful API. In that model, the Node server doesn't do anything too complicated that requires nested callbacks, and that's nice. You basically figure out a single operation based on the URL and query parameters, execute some logic, and have the callback send a response.

There's still a few places where you might need an extra level of callbacks. For example, I have a (temporary) API for creating a bunch of test data, at the URL /api/create-test-data. I want to create 100 new Quiz objects in the database, then once they are all created, return a list of all the Quiz objects in the database. Here's the code:

It should be pretty easy to pick out the logic for creating test data at the end. This is normal Node JavaScript but if it looks a little odd, it's because it's actually decompiled CoffeeScript. For me, the first rule of coding Node is always code in CoffeeScript! In its original form, the nesting of the callbacks is a bit more palatable:

What you have there is a count, remaining, and a single callback that is invoked for each Quiz object that is saved. When that count hits zero (we only expect each callback to be invoked once), it is safe to query the database and, in the callback from that query, send a final response. Notice the slightly odd structure, where we tend to define the final step (doing the final query and sending the response) first, then layer on top of that the code that does the work of adding Quiz objects, with the callback that figures out when all the objects have been created.

The CoffeeScript makes this a bit easier to follow, but between the ordering of the code, and the three levels of callbacks, it is far from perfect, so I thought I'd come up with a simple solution for managing things more sensibly. Note that I'm 100% certain that this issue has been tackled by any number of developers previously ... I'm using the excuse of getting comfortable with Node and CoffeeScript as an excuse to embrace some Not Invented Here syndrome. Here's my first pass:

The Flow object is a kind of factory for callback wrappers; you pass it a callback and it returns a new callback that you can pass to the other APIs. Once all callbacks that have been added have been invoked, the join callbacks are invoked after each of the other callbacks have been invoked. In other words, the callbacks are invoked in parallel (well, at least, in no particular order), and the join callback is invoked only after all the other callbacks have been invoked.

In practice, this simplifies the code quite a bit:

So instead of quiz.save (err) -> ... it becomes quiz.save flow.add (err) -> ..., or in straight JavaScript: quiz.save(flow.add(function(err) { ... })).

So things are fun; I'm actually enjoying Node and CoffeeScript at least as much as I enjoy Clojure; which is nice because it's been years (if ever) since I've enjoyed the actual coding in Java (though I've liked the results of my coding, of course).


Tuesday, February 28, 2012

Plastic is Tapestry's built-in Aspect Oriented Programming library, which primarily operates at the byte code level, but shields you from most byte code level thinking: normally, your code is implemented in terms of having method invocations or field reads and writes passed to callback objects that act as delegates or filters.

Sometimes, though, you need to get a little more low-level and generate the implementation of a method more directly. Plastic includes a fluent interface for this as well: InstructionBuilder.

This is an example from Tapestry's Inversion Of Control (IoC) container code; the proxy instance is the what's exposed to other services, and encapsulates two particular concerns: First, the late instantiation of the actual service implementation, and second, the ability to serialize the proxy object (even though the services and other objects are decidedly not serializable).

In terms of serialization, what actually gets serialized is a ServiceProxyToken object; when a ServiceProxyToken is later de-serialized, it can refer back to the equivalent proxy object in the new JVM and IoC Service Registry. The trick is to use the magic writeReplace() method so that when the proxy is serialized, the token is written instead. Here's the code:

To kick things off, we use the PlasticProxyFactory service to create a proxy that implements the service's interface.

The callback passed to createProxy() is passed the PlasticClass object. This is initially an implementation of the service interface where each interface method does nothing.

The basic setup includes making the proxy implement Serializable and creating and injecting values into new fields for the other data that's needed.

Next, a method called delegate() is created; it is responsible for lazily creating the real service when first needed. This is actually encapsulated inside an instance of ObjectCreator; the delegate() method simply invokes the create() method and casts the result to the service interface.

The methods on InstructionBuilder have a very close correspondence to JVM byte codes. So, for example, loading an instance field involves ensuring that the object containing the field is on the stack (via loadThis()), then consuming the this value and replacing it with the instance field value on the stack, which requires knowing the class name, field name, and field type of the field to be loaded. Fortunately, the PlasticField knows all this information, which streamlines the code.

Once the ObjectCreator is on the stack, a method on it can be invoked; at the byte code level, this requires the class name for the class containing the method, the return type of the method, and the name of the method (and, for methods with parameters, the parameter types). The result of that is the service implementation instance, which is cast to the service interface type and returned.

Now that the delegate() method is in place, it's time to make each method invocation on the proxy invoke delegate() and then re-invoke the method on the late-instantiated service implementation. Because this kind of delegation is so common, its supported by the delegateTo() method.

introduceMethod() can access an existing method or create a new one; for the writeReplace() method, the introduceMethod call creates a new, empty method. The call to changeImplementation() is used to replace the default empty method implementation with a new once; again, loading an injected field value, but then simply returning it.

Finally, because I feel strongly about including a useful toString() method in virtually all objects, this is also made easy in Plastic.

Once the class has been defined, it's just a matter of invoking the newInstance() method on the ClassInstantiator object to instantiate a new instance of the proxy class. Behind the scenes, Plastic has created a constructor to set the injected field values, but another of the nice parts of the Plastic API is that you don't have to manage that: ClassInstantiator does the work.

I'm pretty proud of the Plastic APIs in general; I think they strike a good balance between making common operations simple and concise, but still providing you with an escape-valve to more powerful (or more efficient) mechanisms, such as the InstructionBuilder examples above. Of course, the deeply-nested callback approach can be initially daunting, but that's mostly a matter of syntax, which may be addressed in JDK 8 with the addition of proper closures to the Java language.

I strongly feel that Plastic is a general purpose tool, that goes beyond inversion of control and the other manipulations that are specific to Tapestry ... and Plastic was designed specifically to be reused outside of Tapestry. It seems like it could be used for anything from implementing simple languages and DSLs, to providing all kinds of middleware code in new domains ... I have a fuzzy idea involving JMS and JSON with a lot of wiring and dispatch that could be handled using Plastic. I'd love to hear other people's ideas!


Items:   1 to 5 of 111   Next »