Solving Business Problems and Remaining Hip
Developing best-of-breed software components
By Magnus Lönnroth and Peter Larsson
Table of content
1Introduction
2Solving Business Problems
2.1Development Methodology
2.1.1Applied Extreme Programming
2.1.2Summary and conclusions
2.2Common Systems Functionality
2.2.1Drutt Framework
2.2.2Technical Highlights
2.2.3Summary and conclusions
2.3Model Driven Development
2.3.1Drutt MGEN
2.3.2Technical Highlights
2.3.3Summary and conclusions
2.4Rendering
2.4.1Drutt Rendering
2.4.2Oracle technologies used
2.4.3Technical Highlights
2.4.4Summary and Conclusions
2.5Service Integration and Orchestration
2.5.1Drutt 3PI
2.5.2Oracle Technologies used
2.5.3Technical Highlights
2.5.4Summary and Conclusions
3Remaining Hip
3.1Summary and Conclusion
1Introduction
This paper presents some of the technical areas that should be of interest to anybody wishing to design and/or implement very high-volume middleware systems using Java.
We will provide an overview of the technical strategy and implementation tactics employed by Drutt Corporation for developing two main product lines for the Telco industry. We have been successful in the sense that we are a profitable software company in the mobile Internet segment, and our products are quite widely deployed and relatively unchallenged.
Since we have a marketing budget of zero, our success is largely due to engineering (and sales of course, something our CEO never tires of reminding us), but either way the purpose of this paper is to offer some insight into the mechanics of applied software development that really seem to work for us. Hopefully they can work for you too.
The following topics are of particular interest and will be covered individually:
- Development methodology. You may have heard of Extreme Programming, and to us the most important aspect is incremental and frequent release cycles. This isn’t just a way of avoiding bloated code and dicey software projects (both worthwhile causes), but also important for maintaining a sound business.
- Persistent objects. Yes, there’s an Oracle database at the heart of this, but quite a lot of logic is needed for optimization purposes. We’re constructing databases that have to support several millions of users. Drutt has developed a model generator that produces all persistent logic, and this along with the required runtime will be explained in detail.
- Rendering. This is all about XML and XSLT, but again, although the Oracle XML parser provides essential core capabilities, designing a high-speed delivery pipe for millions of users is a challenge. Furthermore, one size does not fit all in this space, and we will discuss how to handle multiple content models and delivery channels efficiently.
- Service integration and orchestration. This is all about interfaces and integration technology. This is a huge topic that includes favorites like CORBA, EJB, Web Services, etc. Drutt has chosen the narrow path here: keep it simple, make it fast, and make it very flexible.
Obviously, this paper will only scratch the surface of each topic, all of which individually merit substantial research.
2Solving Business Problems
After working 15+ years in the software industry, the number one insight we have gained is this: nothing beats solving a real business problem. To be a bit more explicit:
- Developing awesome software that is not used for anything is no fun. What we mean here is that we have seen a lot of effort going into developing things that may be elegantly architected and well designed, but have no practical use.
- Developing garbage that generates revenue is no fun. A common marketing axiom is that the best solution doesn’t always win, and this is often used as a pretext for throwing together a pathetic excuse for software and using a powerful marketing engine to sell it. Well, this may be a way of solving the problem "how do I maximize my short-term profits?", but it really has nothing to do with solving business problems for the customer, which is the theme of this paper.
Solving business problems means solving a real problem for a customer related to their business. We are software engineers, so we want to limit the number of problems (dramatically) by only considering the ones that have a reasonable chance of actually benefiting from involving a computer.
Well, in the rapid moving world of Internet technology, emphasizing the need of focusing on real customer problems doesn’t do much for your hip-factor. What it will do is keep your pay-checks coming. Starting out with that in mind, it may come as a surprise to learn that the technology involved in solving real problems can be pretty hip too. That’s what this paper is about.
2.1Development Methodology
Here’s a great introduction to development methodology from"Extreme Programming – a Gentle Introduction" by Don Wells [
A software methodology is the set of rules and practices used to create computer programs. A heavyweight methodology has many rules, practices, and documents. It requires discipline and time to follow correctly. A lightweight methodology has only a few rules and practices or ones which are easy to follow.
In the late 1960s and early 1970s it was common practice for computer programmers to create software any way they could. Many programmers excelled at creating software too complex for anyone to understand. At that time it was a miracle if a program ran without any bugs. Making computers useful was considered a worthy quest and not unlike an adventure into the old west.
In 1968 Edsger Dijkstra wrote a letter to CACM entitled "GOTO Statement Considered Harmful". The central ideas of software engineering were being born. At that time we believed that bigger, more disciplined methodologies would help us create software with consistent quality and predictable costs. The lawless cowboy coders were being reined in.
The 1980s were good times for computer programmers. We had a few rules and practices to create software that was far superior in quality to what we were creating only a few years earlier. It seemed like if we could just create enough rules to cover the problems we encounter we could create perfect software and be on time. We added more and more rules and practices to cover all the potential problems.
Now in the 21st century we find these rules are hard to follow, procedures are complex and not well understood and the amount of documentation written in some abstract notation is way out of control. Trying to come up with a bigger and better methodology was like a California gold rush; everyone headed west only to be disappointed.
We created software to help us create software. But this quickly got out of control and dreadnought CASE tools were born. These tools, originally created to help us follow the rules, are too hard to use themselves. Computer programmers find it necessary to cut corners and skip important practices to stay on schedule. No one is actually following the heavy methodologies we have handcuffed ourselves with. The cowboys have returned and we find ourselves back at the OK Corral.
When programmers ignore the rules of their methodology they are instinctively moving away from heavyweight methodologies and back toward an earlier, simpler time of lightweight methodologies when a few rules were enough.
But we don't want to forget what we have learned. We can choose to keep the rules that help us create quality software and throw away those that hinder our progress. We can simplify those rules that seem too complex to follow correctly.
We don't want to return to the early days of cowboy coding when there were no rules at all. But instead let's stop at just enough rules to keep our software reliable and reasonably priced. Instead of cowboy coders we have software sheriffs; working together as a team, quick on the draw, armed with a few rules and practices that are light, concise, and effective.
Extreme Programming (XP) is one of several new lightweight methodologies. XP has a few rules and a modest number of practices, all of which are easy to follow. XP is a clean and concise environment developed by observing what makes software development go faster and what makes it move slower. It is an environment in which programmers feel free to be creative and productive but remain organized and focused.
2.1.1Applied Extreme Programming
At Drutt, we are still trying to learn how to use the XP methodology. We have adopted the basic approach but are still cutting some corners. Our main focus to date has been on developing software incrementally with frequent releases: typically one major release per quarter plus one or two revisions per month.
In our view, XP encourages focusing on "solving business problems" very well. The first step in any XP project is to create a set of "user stories" that describe (in non-technical terms) how the system will be used. Functionally, this is similar to use-case analysis, but is much less formal and enables customers to participate actively.
Once the initial user stories are nailed, developers can start building test-cases that verify (the future) system’s behavior. This is a good approach for two reasons: first, it forces the developer into a state of mind where they have to focus on a (simple) solution rather than fancy technology, and second, it ensures that unit- and integration-testing can progress smoothly once the system is implemented, since the tests are already in place.
At this stage, coding can begin and enter the first of several short iterations towards a final release. One cycle is typically 3-4 weeks followed by a few days of testing and reviews (preferably with the customer).
2.1.2Summary and conclusions
From a technical point of view, XP is a wonderful methodology that not only simplifies systems development greatly, but also tends to generate superior solutions (superior, because they are simple, lean, and to the point).
From a business perspective, our greatest difficulty is matching XP with market requirements for fixed-price consulting engagements. However, this can be managed by actually simulating a traditional project with detailed functional specifications. With detailed project specifications, a fixed price is easily negotiated.
So our conclusion, and this is somewhat counter-intuitive, is that XP is actually easier to implement in product development than in consulting, despite the fact that the benefits of using XP would seem greater in consulting.
Where to learn more about XP:
2.2Common Systems Functionality
All software solutions have to deal with common systems functionality, and even if the Java platform has improved this functional area, there is still a gap to fill. Examples of common functional areas valid for each product component are:
- Configuration
- Logging
- Persistence
- Error handling
- Version Tracking
- Monitoring and management
At Drutt we have an internal architecture to deal with these areas, and the software components are used in all of our product components.
2.2.1Drutt Framework
The Drutt framework consists of well-known and verified design-patterns, and also of common implementations and APIs.
These components are not intended to be sales objects (i.e. "products") - their existence is simple motivated by a need to make Drutt software better and reduce the life-cycle cost of our products.
Everybody in the development organization is permitted to maintain and improve the framework, but only a couple of senior developers have the authority to approve changes and build new releases.
2.2.1.1Configuration
A configuration manages a set of typed parameters, but there are also a couple of other aspects regarding systems functionality that need to be addressed. In Java there is no standardized pattern to manage configurations of components.
Even if J2EE has deployment descriptors, which can be used to configure components from a business point of view, this mechanism lacks the following important requirements:
- Distinction between a locally defined and a default setting (fallback).
- Support of a "hot" re-configuration at runtime.
- A common factory pattern to plug-in different API implementations.
- Expression support to manage simple rules (transient closed).
- Support for different configuration locations: databases, files, URLs, etc.
Therefore, J2EE descriptors are (by themselves) not suitable for configuration of dynamic business components.
Management of plug-ins is important since programmable logic needs to be supported from a configuration point of view, even if declarative parameters still are valid (see comparison between parameters and programmed logic below).
The diagram above illustrates the relative cost of one change with a specific complexity. As complexity increases, using parameters will make it harder and more expensive to maintain the functionality.
2.2.1.2Logging
Logging functionality can be divided into the following areas:
- Activity log, compare to a Web Server CLF log.
- Error and/or debug log to be able to diagnose a malfunctioned component, compare to Oracles process dump files.
- Trace, trace all systems activity.
All are of great importance, and common systems functionality can be utilized to manage different log destinations (database, file, syslog), but also to support creation of debug and trace logs.
For a developer, debugging tools are enough to really trace what’s going on in the system, but it’s always hard to connect an online debug tool to a production instance, and therefore it must be possible to dynamically activate debug and even trace logs for a limited amount of time.
Drutt has an internal log API (listener pattern), which can be highly customized according to customer requirements on format and messages, and also architectural support to create debug and trace logs (dynamically). The Java proxy pattern is used to generate a detailed trace of all method calls carried out by a component, and this proxy can be activated and deactivated dynamically by using the configuration pattern described above.
It’s also possible to plug-in existing implementations like Apache log4j (file logger) etc.
2.2.1.3Persistence
Persistence is a functional area which is very suitable to encapsulate, and at Drutt we have selected the model-driven approach. See the section about Drutt MGEN for details.
Persistence is a bottle-neck in many systems. In fact, it’s probably the functional area containing most errors (sloppy programmers). Proper use of Oracle databases and standardized components such as JDBC can significantly improve the overall system behavior.
Important systems functionality:
- Optimized for the kind of transactions supported by the system.
- Batch all operations (read, write, update), i.e. piggy-back everything.
- Pool transactions and connections.
- Pool and re-use statements (cursors).
- Optimized sequence functionality.
- Robustness when database fails entirely.
Even if all of these areas are obvious, it remains a quite complex and error-prone area, and therefore all these functions shall be managed by the framework.
2.2.1.4Error handling
The Java platform provides an excellent exception mechanism. The issue is whether to use checked exceptions or not. A lot of APIs use the checked exception approach, including J2EE, and the issue arises when linking in such components into an application: should the checked exceptions be propagated or not in the users API.
The simple conclusion is to not use checked exceptions (since at the top level all kinds of exceptions must be managed anyway). This rule is valid at least when the component is intended to be used by other components.
Typed exceptions are of course still valid, and all Drutt APIs throw a nested runtime exception to get rid of low-level checked exceptions, and an application exception of the type runtime is also declared to handle all known errors.
The Drutt framework also manages generation of error classes including an error code and a message with parameters.
2.2.1.5Version Tracking
Although this seems to be a small issue, it’s essential when supporting the installed base.
Therefore the framework includes support to stamp versions during build time, and also report versions of all dependencies when executing the applications. The version is generated at build time and included both as a Java class in the actual JAR/WAR/EAR and also in the manifest file of the component.
2.2.1.6Monitoring and management
Monitoring and management of application needs to be designed as well as other systems functionality. There are of course tools that can monitor an application at a macro and functional level, but to really be able to know what’s happening, the actual application must have knowledge about internal data structures.
The Drutt Virtual Network Management component includes;
- A customizable internal (embedded) agent.
- A proxy agent that connects several application agents to an external SNMP console (Drutt MIB) or a Drutt Web console.
- Drutt Web console.
The agent samples information, and has built-in support to monitor health, transaction and state information including configuration. It’s also possible to manage the application and issue commands such as shutdown, reconfigure, enable/disable debug etc.
By using our own light-weight distributable objects, different kind of monitors can be defined by the client and these can be sent over to the application agent. The actual monitor listens (in-process) for the specific event and signal an event or SNMP trap back to the console when the condition has been met.
2.2.2Technical Highlights
Configuration of a runtime component
Here is an example of a configurable component:
// Fragments...
import com.drutt.util.*;
import javax.xml.parsers.*;
//
public class ExampleImpl implements Example, Configurable {
// config parameters
static final String P_DB_FACTORY = "documentBuilderFactory.class";
static final String P_TIMEOUT = "timeout";
static final String R_XML = "xml";
static final String R_TRACE = "trace";
// configurable state.
private DocumentBuilder documentBuilder;
private int timeout;
private boolean trace;
public void configure(Configuration config) {
timeout = cpnfig.getInt(P_TIMEOUT);
trace = config.getBoolean(P_TRACE);
// uses module xml, get config record
Configuration c = config.getRecord(R_XML);
DocumentBuilderFactory df;
df = (DocumentBuilderFactory) c.getFactory(P_DB_FACTORY).create(c);