In part 3, I listed the criteria we used for deciding which products to create. In this part, I describe the activities that took place in the first few months of development. Things like marketing, pricing, and other such stuff are left out because they're outside the scope of this series.
For each product, I had a good idea of the differentiators that would allow it to gain popularity in the marketplace. In every case, ease of use was always the main differentiator, but there were generally one or two other things that were almost as important, such as performance or portability.
Before staffing a team and incurring the associated expense, I always prototyped a skeleton version of the product that proved that the main differentiators could be achieved. The prototype phase generally lasted between one and three weeks and was always incredibly good fun; it is hard to beat the feeling of building something quickly!
When planning the prototype, I started by picking two or three common use cases that would demonstrate the product differentiators. For example, in the case of the Glue web services platform, the most common use cases were (1) publishing a Java object as a web service, and (2) binding to a remote web service and then invoking it. I determined that in order to differentiate the product, publishing an object should require just a single line of code and should not require the Java object to be modified in any way, binding to a service should take just a single line of code, and that performance should be around 1000 messages per second. I figured that if I demonstrated these features early on, I’d have confidence that the rest of the features could be implemented in a timely fashion.
When implementing software, I always follow the same basic philosophy. The first step is to enumerate use cases. A use case describes a particular task that the product allows a user to accomplish, such as “publish a Java object as a web service” or “bind to a web service and then invoke it”. The second step is to define the user experience, which is how the product is used in each particular use case. For a developer product, the user experience typically involves the use of one or more APIs and/or a user interface. The third step is to define the architecture that supports the user experience. This three-step approach might sound obvious, but it’s very tempting as a developer to start working on the architecture prematurely, and indeed I find myself doing this even to this day.
With Glue, the use case of publishing a Java object had the following user experience:
// publish object at specified name
Registry.publish( name, object );
Later on, I added several variations of publish(), but during the prototype phase, only one version was needed. Similarly, the use case of binding to a web service and invoking it had the following user experience:
// bind to service at the specified URL
IFoo foo = (IFoo) Registry.bind( url );
// invoke operation on service referred to by foo
foo.bar( 42 );
For each use case, I wrote a set of simple examples that formed the backbone of the early documentation. The examples also acted as a simple form of early test code, and the prototype was deemed to work when all the examples worked. I’ll talk more about real testing later on in this series.
In the case of Glue, the prototype took a couple of weeks and implemented the two common use cases for very simple web services (sync calls with primitive arguments only) and would support around 1,000 web service invocations per second using SOAP over HTTP. The prototype implemented a tiny subset of the relevant standards such as WSDL, XML, HTTP and servlets, and used no third party software at all. The reason for not using existing libraries like Tomcat and Xerces was because none of this software supported the performance that I was striving for, and performance was one of the main differentiators I wanted to demonstrate.
Prototypes were packaged with some minimal API docs, a few pages of user documentation that described how to install and run the examples, and zipped up into a single file. This allowed us to give a prototype to pretty much anyone and get them up and running in a short amount of time.
Prototypes were lean and mean, with fairly decent code quality. I’m a big believer in keeping code clean and simple, even during early development, because it’s a good discipline, allows the design and code to be easily understood, and sets the overall quality tone for the project. I really hate delving into code that is contorted and sloppy, and would be personally embarrassed if team members that joined the project felt that way about my own code.
In the next part, I'll describe what happened after the first prototype was completed.