Resource Oriented Computing (ROC) has been touted by NetKernel (1060) as “highly suited to modern business processing systems” that it will bring the web into your applications and separate the architecture from the code.
Groovy on the other hand claims only to be “an agile and dynamic language for the Java Virtual Machine”. The advantages it offers are more in the area of rapid development rather than improved performance.
The choice between these two platforms now faces my current client. As a developer with intimate knowledge of NetKernel and limited Groovy experience, I will add my $0.02 here.
Let the Russian’s have outer space we’ve got ROC and Roll
In the late 1950’s the U.S. was content with the status quo and it cost the initial lead in the “Space Race”. Now ROC offers us the ability to remain content with re-using archaic code modules because they contain the “secret sauce”. This offer only allows us to make the same mistake as the U.S. did in 1959. ROC claims to bring the web into your application, and my practical experience with ROC is that is does indeed follow through on that promise. It brings the complexity, confusion and quagmire that the web has become right into your own architecture. This makes developing within a NetKernel framework a constant struggle to make sense of a complex system. The most unfortunate thing is that it does not come with it’s own Google to provide a way to find pre-existing resources. It shows the prospective user a simple diagram of rows of boxes representing their architecture that belie the complexity lurking in those boxes.
The services boxes can map to a java jar with entry points to web services specified in the xml document that defines the module. These services may depend on other services and may be addresses using a variety of URL patterns. It is this architecture that encourages the kind of spaghetti coding that I have not seen since my C++ days. I am thinking of the mile long chh files (c++ headers) that reference other chh files that could in turn include circular references, so that all header files had to contain the <IF NOT DEFINED> compiler directive. Unfortunately this old trick has not migrated to NetKernel and the circular references have to be rooted out by hard tedious trial and error.
Thankfully maven and the groovy analog of maven have made dependencies in the java (or groovy code) much more manageable. The Groovy rapid development capability eliminates the need for re-use that drives the complex dependencies found in ROC. ROC prides itself in ambiguity but it is this ambiguity that makes the application difficult to maintain debug or build upon. Groovy prides itself on simplicity by eliminating the “boiler-plate” code that is required for the routing of requests to their logical and correct responder. It is this simplicity that allows for much faster application development and ease of debugging existing code.
What is in a name?
‘When I use a word,’ Humpty Dumpty said, in rather a scornful tone, ‘it means just what I choose it to mean — neither more nor less.’ This appears to be the attitude taken by ROC in that the naming of their resources is arbitrary. Here is a quote from their own work that condemns them more than Lewis Carroll can, In summary, a crucial difference between ROC and physical computing is the use of indirection through logical addresses instead of direct access to physical memory data locations. This indirection comes with the cost of resolving logical identifiers for each request. I would comment that the last time I used physical memory addressing was in my Assembly language programming class in college and even then we used a “Virtual Machine” so that we actually never addressed real memory. On second thought, I think my last chance to directly access physical computer memory was when I PEEK’ed and POKE’d my Apple II+ in high school, while this proved good for hours of entertainment, it was not serious computing. Clearly all programming languages have used “logical addresses” over time to access information stored in “physical memory”. So if logical addressing is common to all programming languages, how is ROC different? My firm belief here is that ROC has adopted illogical addressing and here is my support. When processing a single web service request, NetKernel scans nearly every deployed module available, because any deployed module may contain the desired resource. Here is just a small taste of a NetKernel log showing the complexity of the lookup process:
Entering Parent Module urn:org:ten60:netkernel:ext:introspect
Checked Unmatched Mapping ffcpl:/entrypoints.xml THIS
Checked Unmatched Mapping ffcpl:/org/ten60/netkernel/introspect/.* THIS
Checked Unmatched Mapping ffcpl:/mi+.* to accessor org.ten60.netkernel.introspect.moduleicon.GetIconAccessor
Ignoring pre-checked Mapping (many) to import urn:org:ten60:netkernel:mod:docxter
Checked Unmatched Mapping (many) to import urn:org:ten60:netkernel:ext:kernel
Checked Unmatched Mapping (many) to import urn:org:ten60:netkernel:ext:entrypoint
Checked Unmatched Mapping (many) to import urn:org:ten60:netkernel:ext:xsecurity
Checked Unmatched Mapping (many) to import urn:org:ten60:netkernel:ext:sys
Ignoring pre-checked Mapping (many) to import urn:org:ten60:netkernel:ext:layer1
Ignoring pre-checked Mapping (many) to import urn:org:ten60:netkernel:ext:dpml
Ignoring pre-checked Mapping (many) to import urn:org:ten60:netkernel:ext:xml:core
Ignoring pre-checked Mapping (many) to import urn:org:ten60:netkernel:ext:xml:ura
Checked Unmatched Mapping (many) to import urn:org:ten60:util:image
Checked Unmatched Mapping (many) to import urn:org:ten60:netkernel:lib:xlib
Matched on Mapping (many) to import urn:org:ten60:netkernel:ext:install
Entering Import Module urn:org:ten60:netkernel:ext:install
Rewriting Request to ffcpl:/org/ten60/netkernel/ext_install/pub/status.xml
Checked Unmatched Mapping active:(?:install|postInstall) to accessor org.ten60.netkernel.ext_install.InitAccessor
Checked Unmatched Mapping ffcpl:/(entrypoints.xml|SessionPolicy.xml) THIS
Matched on Mapping ffcpl:/org/ten60/netkernel/ext_install/.* THIS
To use a database analogy, this is like doing a full table scan for every simple query. It is no wonder that they have built in caching of all resources, they have to in order to achieve a reasonable modicum of performance. This indirection that they pride themselves on makes finding any resource a virtual hunt through a haystack to find the needle we desire.
URL or URN, What’s the diff?
Simply put a Uniform Resource Name (URN) tells you the name of an object, and the Uniform Resource Locator (URL) tells you how to find it. This is the distinction that ROC has capitalized by adding multiple URL’s (paths) to the same object. The name of the object should give you an idea of how to find it, in fact it should give you the fastest route to it. Google has made millions and millions of dollars by simply turning names into URL’s, because that is the purpose of a search engine. Search engines are required because the internet has not adopted the single standard human readable addressing scheme dreamt of by the pioneers in computing. If they had, then www.the.answer.to.life.the.universerse.and.everything would resolve to 42. But ROC would also demand that 42 also be resolved by www.the.third.primary.pseudoperfect.number. My argument for simplicity is that both of the URLs could return 42 without returning the same 42. This, in my mind, is the core difference between ROC and Groovy. ROC encourages re-use through ambiguous addressing. By using simplicity in addressing, Groovy allows you to start over and build a new service in less time than it takes to figure out what pre-existing resource is presumably already providing the service you seek to build.
ROC, the Residence of Cards
In practical terms, roughly a third of the time I have spent developing NetKernel based web services was spent getting the compiled java code to deploy. This is after writing the code, writing the unit tests and fixing any coding errors discovered in unit testing. (Side Note: I like to write code before tests, so I have an idea what I am testing but that to me is a matter of taste). The deployment time is spent just getting NetKernel to start successfully with the new or updated module. The aforementioned chain of dependencies in the “header” files is responsible for the fragility of the working container. If one module fails to deploy then all of the modules that reference it, also fail to deploy. Sometimes these failures are unrelated to any new code introduced and this is one of my major frustrations with NetKernel and ROC in general. The log messages listed above only hint at the extraordinary verbosity of their logs, and there are a multitude of “acceptable failures”, making the deployment task a real search for a needle in a haystack. This is where Groovy can really improve the process and more importantly the time to market that is so key to development success.
With groovy you can go from coding business objects to testing the deployed app in a few simple commands. Not only does groovy simplify the code, it also simplifies the deployment process. This whole process can improve time to market, even if it involves re-writing from scratch all of the legacy code you hoped to “re-use”. This re-writing process may seem a waste of time at first, but in the real world, the application development market is highly fluid. It seems that developers switch jobs (or positions, or assignments …) more frequently than Basketball players. With this market reality in mind, it makes good sense to revisit the “legacy code” periodically to make sure that it really does what it is advertised to do. It is a good bet that your current development staff has no idea what the legacy code should do but still will be able to find something to keep from the legacy code. Groovy simplifies the re-writing process and allows your developers to focus on learning and coding the core business concepts rather than debugging legacy code and fixing the NetKernel residence of cards.