Application vs. service vs. library
One problem that comes up as you keep developing an application is that it keeps swelling as you throw new features into it, sometimes along with the new technologies you need for them. A classic example is a web application's WAR file, gobbling everything up like Otesánek, the glutton from the Czech folktale. It seems to me that hardly anyone talks about how to deal with the problem, and everyone has to learn from their own mistakes. I'll try to describe the problem with the glutton and how I think we can solve it. I'm looking at it from the perspective of our development work at GoodData, where we provide software as a service.
The glutton model
Also known as the monster.
Description: The application logic has a local interface from the JVM's point of view. All libraries must be on the classpath and must be configured and initialized properly at application startup. Calls between parts of the application are always synchronous. Code reuse happens at the library level.
Classes of problems
Deployment
Initialization time is proportional to size, particularly to the amount of configuration for application logic and the libraries in use. If we can't run the old and new versions in parallel, initialization time can increase application downtime. A deployable package in the tens of megabytes is slow to distribute if, for example, we want to deploy it across a cluster all at once.
A single class loader space dictates the use of the same library versions, especially third-party libraries. If we need a newer library version, we may have to modify and test parts of the application that the change wouldn't otherwise touch.
Runtime
Memory demands can run wild. We can't allocate memory separately to each part of the application, so the parts can interfere with each other. If one part uses more memory, the rest of the system can suffer. The same goes for virtually any resource shared at the JVM level.
Synchronous calls between parts of the application block the caller. That makes it hard to respond to a failure in a part of the system that's unnecessary for completing the request, such as audit logging or notifications.
Maintenance
When an application does too many things, taking it offline, fixing a bug or restarting it for maintenance is difficult because any of those affects the whole system. Monitoring is harder too. It's essentially a black box with a ton of responsibilities.
Solution
If parts of the application logic don't depend directly on each other, for example through a transaction context, and remote calls between them won't be a performance problem, we can encapsulate them as services. Services let us build a more loosely coupled system. That gets rid of many of the problems tight coupling causes, across deployment, runtime and maintenance. One welcome result is that we can run with a reduced set of services. If there's a problem, we can take noncritical services offline and preserve the system's main purpose. In an online gaming system the main purpose is to let players play. If a secondary system, say registration for new players, starts failing, there's no reason it should take existing players down with it.
Services can be used from other languages as well as from the ones they were written in. Their use is limited practically only by their interfaces. That gives us much better reuse. Each service can set its own terms of use in an SLA, covering things like response times or the maximum number of requests served.
Of course, running part of the application logic as a service exposed through REST or messaging introduces a different class of problems. Designing and developing a service interface can be quite expensive, for REST for example. Communicating over a network also brings reliability problems. The only thing you can rely on is that nothing is reliable. The design and implementation of each service have to account for that.
I'm hardly reviving the overused term SOA. It rubs me the wrong way, and there's so much baggage around it that it's hard to picture anything concrete. This is a lesson I learned over time.
Related articles
Related CZ Podcast episodes
- #261 · Leadership
On leading people and teams. · Czech audio
- #3 · Java 6 SE, Vývoj webových aplikací
Dagi and Filemon discuss Java 6 and web application frameworks. · Czech audio
- #1 · Vývojová prostředí v Javě
The first CZ Podcast episode looks at Java development environments. · Czech audio