The Network is the Container

Friday, August 28, 2009

One of the standout features of Spring, with its declarative approach to so-called "cross-cutting concerns", has been to help separate infrastructure minutiae from day-to-day programming and allow a cleaner focus on business logic. However, that only lasts up until the time the application has to be deployed.

With the acquisition of SpringSource by VMWare, the Spring team has set a new goal to abstract infrastructure details away from day-to-day operations.

"VMware and SpringSource plan to further innovate and develop integrated Platform as a Service (PaaS) solutions that can be hosted at customer datacenters or at cloud service providers."
Deploying and managing enterprise applications is hard, and what makes "enterprise" applications "enterprise-y" is not just about how much they integrate or how critical they are to how many lines of business. "Enterprise" applications operate in an enterprise context, that is, they conform to consistent, independent infrastructure capabilities that serve many applications: authentication and single sign-on, authorization, transaction management, fault and performance monitoring, data security, audit compliance, routing, caching and more.

These common capabilities are built to economies of scale such that the net investment required to make them common is a good deal less than the cost for each application to provide them on its own. The downside is they are highly tailored for the local environment, difficult to port into and out of, and create significant overhead for testing and deployment.

The traditional application server is little more than a bridge into this environment; the real "container" for enterprise applications is the network on which they operate, and the promise of commoditized platform-as-a-service will not be realized until more of these common capabilities and their configuration can be virtualized and automated to the same degree as hypervisors have for the O/S.

In his frequently quoted blog entry on the acquisition, Ovum analyst Tony Baer writes:
"The fact is that providing a virtualization engine, even if you pad it with management utilities that act like an operating system, is still a raw cloud with little pull unless you go higher up in the stack. Raw clouds have their appeal only to vendors that resell capacity or enterprise large firms with the deep benches of infrastructure expertise to run their own virtual environments."
And later:
"VMware isn’t finished however. The most glaring omission is need for Java object distributed caching to provide yet another alternative to scalability. If you only rely on spinning out more VMs, you get a highly rigid one-dimensional cloud that will not provide the economies of scale and flexibility that clouds are supposed to provide. So we wouldn’t be surprised if GigaSpaces or Terracotta might be next in VMware’s acquisition plans."

They certainly have already have the strategic relationship with Terracotta. That covers caching, and the earlier acquisition of Hyperic by SpringSource covers operations management to some degree.

It's not clear to what extent outright acquisitions are needed to build out this distributed "container". For example, the Cisco Nexus 1000v is an independent software switch product, and there is even an open source competitor to same (not for for the faint of heart, presumably.)

Another interesting and underrated problem area is data service security. Certificates expire, passwords change frequently, and both tend to be managed through manual processes. That's a serious obstacle to on-premises dynamic provisioning, much less when operating in external clouds. Something like Digital Vault technology from CyberArk might fit the need.

Comments welcome. What else is needed to make PaaS into a product, or suite of products, that can be "installed" on-premises? Can you achieve dynamic database capacity without affecting existing DB-backed applications? Where does identity management fit in? What technologies would have to be acquired, and where will partnerships suffice?

(Disclaimer: The above opinions are mine alone and do not necessarily represent the views of current or former employers.)

Falling Up the Stairs, Part 1: A Line-by-Line Conversion

Monday, July 13, 2009

As I noted in the first of these articles, I plan to dive right in rather than teach Scala from scratch as if to new programmers. So I'll begin with a translation of a simple, real-world development problem from Java to Scala, just to give the flavor of the language and highlight a few key capabilities & differences from Java.

The problem, taken from an old unit test suite, is to generate a web application directory on the fly for use by an embedded servlet container. We'll focus on one aspect, the creation of web.xml. Our code will allow a test suite to specify servlet context parameters, servlet classes and URL bindings, and return the appropriate web.xml file as a string. Here's how it's used:


WebXmlGen gen = new WebXmlGen();

gen.addParam("initConfig", "WEB-INF/myconfig.xml");

gen.addServlet("main", "myapp.tests.Mainervlet").bind("/");
gen.addServlet("test", "myapp.tests.TestServlet").bind("/test");

new FileWriter("WEB-INF/web.xml").write(gen.webXml());

For the Java code, we'll need a list to hold the servlet configurations, another list for the context parameters, and helper classes for each we'll call ParamInfo and ServletInfo.


import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.jdom.DocType;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Text;
import org.jdom.output.XMLOutputter;

public class WebXmlGen1
{
private List<ServletInfo> servlets = new ArrayList<ServletInfo>();
private List<ParamInfo> params = new ArrayList<ParamInfo>();

The webXml method will use JDOM for generating the XML, and will delegate to XML-generating methods in ParamInfo and ServletInfo:


public String webXml() throws IOException
{
Element root = new Element("web-app");
Document doc = new Document(root);
doc.setDocType(new DocType("web-app",
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"));

for (ParamInfo ps : params)
ps.addXml(root);
for (ServletInfo ss : servlets)
ss.addServletXml(root);
for (ServletInfo ss : servlets)
ss.addMappingXml(root);

XMLOutputter xo = new XMLOutputter();
StringWriter output = new StringWriter();
xo.output(doc, output);
return output.toString();
}

The helper class for holding parameter information is straightforward, just a place to stash the parameter name & value. Its addXml() method adds the <context-param> element to the JDOM Document.


private class ParamInfo
{
String name;
String value;

ParamInfo(String name, String value) {
this.name = name;
this.value = value;
}

void addXml(Element root) {
Element paramName = textElement("param-name", name);
Element paramValue = textElement("param-value", value);
Element param = new Element("context-param")
.addContent(paramName).addContent(paramValue);
root.addContent(param);
}
}

Given this definition, here is the addParam method:


public void addParam(String name, String value) {
params.add(new ParamInfo(name, value));
}

Next, there is the ServletInfo class; it holds the name and class of the servlet, a list of URL patterns to map to the servlet:


private class ServletInfo
{
String name;
String klass;
List<String> patterns = new ArrayList<String>();

ServletInfo(String name, String klass) {
this.name = name;
this.klass = klass;
}

void addServletXml(Element root) {
Element servletName = textElement("servlet-name", name);
Element servletClass = textElement("servlet-class", klass);
Element servlet = new Element("servlet").addContent(servletName)
.addContent(servletClass);
root.addContent(servlet);
}

void addMappingXml(Element root) {
for (String pattern : patterns) {
Element servletName = textElement("servlet-name", name);
Element urlPattern = textElement("url-pattern", pattern);
Element mapping = new Element("servlet-mapping").addContent(
servletName).addContent(urlPattern);
root.addContent(mapping);
}
}
}

Here is the addServlet method. To avoid exposing the ServletInfo class to callers, we define an interface that supports the bind() method shown earlier, and return an anonymous class instance that implements the interface.


public interface UrlBinder {
UrlBinder bind(String pattern);
}

public UrlBinder addServlet(String name, String klass) {
final ServletInfo info = new ServletInfo(name, klass);
servlets.add(info);
return new UrlBinder() {
public UrlBinder bind(String pattern) {
info.patterns.add(pattern);
return this;
}
};
}

Finally, there is a convenience method for building elements containing a single text node.


private Element textElement(String name, String text) {
return new Element(name).addContent(new Text(text));
}

Easy enough. Let's begin the translation and introduce some of Scala's improvements. Here are the first few lines of the class as expressed in Scala:


import java.io.StringWriter

import scala.collection.mutable.ListBuffer
import scala.xml.XML
import scala.xml.dtd.{DocType, PublicID}

class WebXmlGen2
{
private var servlets = new ListBuffer[ServletInfo]()
private var params = new ListBuffer[ParamInfo]()

The class definition is familiar enough; it works the same way as in Java, however the default modifier is public. As you also may have guessed, type parameterization uses square brackets, not angle brackets, so you write ListBuffer[ParamInfo] rather than ListBuffer<ParamInfo>.(ListBuffer is one of Scala's collection classes; you can also use java.util collections.)

What's clearly missing here is the "double declaration" boilerplate found in Java. Because of Scala's type inferencing, you needn't declare the type of a field or method if Scala can intuit it from an initializer or a return value; just use "var" or "val" to indicate whether the field is mutable or not (can change after assignment.)

Also missing are explicit line terminators; it's hardly ever necessary to put a semicolon in Scala code.

Next we'll translate the addParam and addServlet methods. These also are straightforward:


def addParam(name: String, value: String) =
params += new ParamInfo(name, value)

trait UrlBinder {
def bind(pattern: String): UrlBinder
}

def addServlet(name: String, klass: String) = {
val info = new ServletInfo(name, klass)
servlets += info
new UrlBinder {
def bind(pattern: String) = {
info.patterns += pattern
this
}
}
}

New concepts:

  • Names and types in declarations are reversed, a la "name: type" rather than "type name".
  • Instead of interfaces, Scala uses traits, which can express both function contracts and behavior. More on this in another post; in this case, our use of a trait is the same as the use of an interface in Java.
  • Functions are introduced using the def keyword. Braces are optional around functions because the body of a function is simply an expression, and in Scala a block of statements is also an expression. It can be used anywhere, not just for lexical structuring purposes as in Java. The value of a block expression is the value of the last contained expression, so a return statement is optional in this case.

Note again that we haven't declared the return type of these functions: Scala has inferred them from the return values. OK, nothing too revolutionary so far; next we redo the webXml() method:


def webXml = {
val nodes =
<web-app>
{params.map(p => p.toXml)}
{servlets.map(s => s.servletXml)}
{servlets.map(s => s.mappingXml)}
</web-app>
val out = new StringWriter()
XML.write(out, nodes, "utf-8", true,
DocType("web-app", PublicID(
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"), Seq()))
out.toString()
}

Whoa... this is different. Lines 38-41 are just serialization code from Scala's standard XML library, but what about lines 32-36?

This is Scala's support for XML literals at the language level. Writing XML from Scala means... just writing XML. The compiler checks the XML for well-formedness and converts it to an internal runtime representation. You can interpolate application data in elements or attributes using curly braces, as shown here.

Inside the braces, we see the use of function literals, a great source of flexibility that was regrettably, along with closures, dropped from Java 7. Function literals allow function definitions to be used as values and passed around just like instances of built-in and user-defined types. The syntax of function literals is

(arg1: type, ..., argN: type) => expression

Parentheses may be left off the arg list if there is only one argument whose type can be inferred. So the expression

params.map(p => p.toXml)

is the same as

params.map((p: ParamInfo) => p.toXml)

because Scala knows the argument list of a function passed to ListBuffer[T].map is of type (T). What this says, then, is "Take each element of params, apply the toXml method, and return a sequence of the results." Since the type of each sequence member is in turn inferred to be an XML node (because ParamInfo.toXml returns XML) Scala will add those elements as children of the <web-app> element; likewise with the XML for the servlet definitions.

Continuing on, you will now probably not be surprised by the definition of the ParamInfo class:


private class ParamInfo(name: String, value: String)
{
def toXml =
<context-param>
<param-name>{name}</param-name>
<param-value>{value}</param-value>
</context-param>
}

Or maybe you will be... where's the constructor? It's created automatically by appending an argument list to the class name as shown. More boilerplate gone; no need to populate member fields by hand.

Finally, there's the updated ServletInfo, and no new surprises this time:


private class ServletInfo(name: String, klass: String)
{
val patterns = new ListBuffer[String]()

def servletXml =
<servlet>
<servlet-name>{name}</servlet-name>
<servlet-class>{klass}</servlet-class>
</servlet>

def mappingXml =
patterns.map(pattern =>
<servlet-mapping>
<servlet-name>{name}</servlet-name>
<url-pattern>{pattern}</url-pattern>
</servlet-mapping>)
}

What have we accomplished so far with Scala? We've eliminated useless boilerplate at several points, because the Scala compiler will intuit information that the Java compiler forces the programmer to specify. We've used expression-oriented syntax to describe operations on collections more concisely than in Java. We've generated XML in the most natural way possible: using XML syntax, instead of through an API. We've reduced the code size by about a third.

Best of all, the result of compiling the Scala version is plain old Java bytecode. The Scala version of WebXmlGen can be instantiated from Java, deployed in a JAR, debugged in Eclipse, or profiled for performance tuning.

SOA's Funny Hat

Sunday, January 11, 2009

One of our frequent failings in IT is the inability to recognize when what looks like a shiny, new, exciting and difficult problem requiring great innovation and finesse is really a stodgy, old, well-understood problem wearing a funny hat.

Service-oriented architecture is this in spades. SOA isn't the real problem; it's the funny hat. The real problem is software reuse.

At one time, ten years ago and more, we dreamed of composing applications from libraries of modular business components, built by domain experts, offering that magical combination of being just specific enough for our needs, and just general enough for everyone else's.

It didn't happen. Bedeviled by the intricacies of requirements variance, platform incompatibility, code dependencies, and a host of management headaches, we moved on. Instead, we now dream of composing applications from modular business services.

Technically, the idea isn't as far-fetched as it once was, as SOA offers two critical advantages over direct code reuse: platform independence and location independence.

If I want to reuse code as a component, I am obliged to use the hosting platform and framework / container, else it won't give me the time of day (even if it's a time-of-day component.) Otherwise, I have to shoehorn the framework into my established, pristine application architecture, or jettison mine and rebuild.

If I want to reuse code as a service, it's different. With web services, for instance, I send an XML message over HTTP.

And I'm done.

The impact on my application is minimal. I can use only what I need and ignore the rest. The code can be hosted anywhere and I can call it from anywhere else. You can upgrade the code a hundred times a year, change development platforms, push it out into the cloud or drag it back in-house; if the interface contract is honored, my client won't care. (Well, it won't care, modulo the odd glitches from half-wit SOAP stacks.)

Small wonder people remain excited about SOA, that even after ten years of hype and high-profile failures, we are still willing to beat our heads against this wall. It's worth the effort. When you get it right, the cost to reuse is nearly zero.

Technically, that is. SOA may have taken most of the platform issues out of software reuse, but it has done nothing to solve the far more challenging issues in managing reuse. These are well understood, but they still give reuse all the approachability of a feral pig. SOA is a beast for much the same reasons.

  • Reuse isn't just a different style of programming. It takes a highly disciplined approach, like feature-oriented domain analysis, to partition application functionality and identify critical reusable parts, and then focus investment on those parts. In SOA, it's about partitioning business functions and business processes, potentially re-engineering what's broken, and investing in those with the greatest potential.
  • Reuse brings disruptive change to the development organization. Talent is split between component builders and application builders, creating competition for who builds what. Same with SOA: you have service providers and service consumers.
  • Vendors are eager to portray technology as the solution. Reuse is achievable if only you will use our repository product, our base framework, our architecture planning tools, our software assessment suite. Likewise SOA: you can have it out of the box if only you purchase our ESB, our service registry, our governance solution, our data integration engine. Always eager for silver bullet solutions, IT managers get suckered time and again.
  • Reuse demands a different funding model. Component consumers are developers, not business users, and business sponsors are loath to pay for development of software that customers can't see and touch, or that isn't tied to specific projects. Developing an effective ROI model requires a high level of maturity in project management and accounting. The same goes for services.
  • Reuse also demands changes in business product planning. IT can't just be an order taker for the business, building applications in silos. Long-term ROI demands the reusable component base be a foundation for future products, and product planning must run in parallel with a roadmap for the components. Same with services.
Common pitfalls abound: trying to run the reuse teams like any other project , instead of like an internal product organization; use of shady ROI metrics like # of lines of code reused; failure to train developers and architects in new skills; ambitious executives over-selling pet platforms and methodologies as the key to success.

It's all too familiar. Sadly, SOA is just different enough from component reuse that we see it as a unique problem, and costly lessons from the halcyon days of software reuse go unheeded.

We ought to take another look at SOA and say, "Wait a minute… I recognize that guy."