Craig Cleaveland, Software Consultant

Domain Engineering

Domain Engineering is a process for creating a family of programs so that programs in the family can be created efficiently. Most often the motivation for doing domain engineering is to achieve a significant increase in software productivity within the chosen domain. Domain engineering is the fundamental process that has been used to create application generators (or program generators), tools for creating user interfaces, database systems, application frameworks, and wizards of all kinds. Each such successful program family typically results in productivity increases on the order of 10 to 100 times.

Domain Engineering is often divided into two parts:

In the remainder of this page, I provide a short description of some of the key concepts and principles of domain engineering.

Decisions

Any development process is a series of decisions. Decisions are made during requirements, software architecture, interface development, software design (algorithms, data structures, data representation), software coding and testing, and application use. According to Fred Brooks, the hard thing about software is making the decisions, not coding them. The hard thing about domain engineering is figuring out what the important decisions are and who and when they should be made. In the domain engineering process we distinguish between different times, in particular we note the following major times:

Commonalities

A commonality is a decision during domain engineering. It represents something that is common across all programs in the family of programs. Because commonalities represent the common parts of such programs, they represent the potential savings of this approach. The set of commonalities represent the portion of the software that will be reused in each member of the program family. However, at the same time, commonalities also represent the limitations or boundaries of the program family because they represent the set of assumptions that must be made by each application created in the program family.

Variabilities

Variabilities are decisions that are explicitly deferred during domain engineering time to either application development or application use. Variabilities represent the extent that individual members of the program family vary from each other.

Tradeoffs between Commonalities and Variabilities

The hard thing about domain engineering is deciding who and when a decision should be made. Which decisions should become commonalities? Which decisions should be variabilities? A commonality represents increased productivity at the possible expense of a smaller program family.

A certain balance between commonalities and variabilities is usually found. A situation in which almost everything is a commonality typically results in a small program family and is almost equivalent to a single application. The opposite situation in which there are virtually no commonalities results in very little software reuse and consequently is also little different from building applications one at a time.

Another way of thinking about whether to make a decision a commonality or a variability is to ask whether the decision should be standardized or parameterized. Standardizing creates commonalities. In many efforts standards are often used to effectively and easily create program families. Standardization processes are examples of domain engineering. Standization may be an external or internal process. Internationally recognized standards are often used in combination with an organization's internal standardization process. For example, an organization may decide to adopt the XML standard in combination with standardizing on a platform independent internal standard to create an XML tool set based on Java.

Domain engineering is typically an iterative process that will typically change commonalities and variabilities over time. Some commonalities may become variabilities when it is discovered that the program family is too small. Alternatively, a variability may evolve to a commonality (for example as a result of an organization's standardization process).

Separation of Concerns

Once the domain analysis is performed, the next major step is domain implementation. After domain analysis is completed we know what decisions must be made by whom and at what time, but we don't yet know how we are going to let this happen without a lot of chaos. Without domain engineering techniques, software systems are often produced that mixes all these decisions together making it difficult for people to make decisions independently of others. Separation of concerns is a concept that structures systems so that decisions can be made independently of each other. There are many techniques for doing this and good software engineers have been doing these things for a long time. A classic example is the separation of machine dependent code from the machine independent code. For example, in C, one often finds separate files that deal with all the machine dependencies. This makes it much easier to port the application to a new platform.

Although domain engineering might be a new term to many people, its basic concepts have long been embodied in good software engineering practices. Parameterization of programs, functions, and objects, putting build-time attributes in header files, and replacing mystery constants with named constants are examples that lend themselves to a "poor man's" approach to domain implementation. Software architecture is intimately linked to domain engineering, particularly in the area of abstractions and application frameworks.

A more sophisticated technique are program generators. These tools separate what you want from how you do it. Program generators typically accept a specification that represents the set variabilities -- the set of decisions made by an application developer, and the program generator combines these decisions with the set of commonalities to create a customzied program.

Specification-Driven Tools and Program Generators

Tools and techniques for creating program generators, application generators, and other specification-driven tools typically begin with a specification. A specification is an expression of the information for a particular program in a program family. Typically a specification is written in some textual language and program generators (or other similar tools) are used to read the specification and generate a program and perhaps other related outputs such as documentation and test cases.

Such tools are difficult to build from scratch. Fortunately, there are a variety of tools that can be used to efficiently build such systems. MetaTool is one such tool that I created while at Bell Labs that has been widely used for building a wide variety of program generators. MetaTool can be licensed from Harmony Software. The design of a textual language requires both technical skill and knowledge about arcane parsing techniques as well as an art where the feel of the language is easily understood and used by its users. I began designing languages since my undergraduate days at UCLA and have literally designed hundreds of languages, from full blown programming languages to small languages for narrow domains.

Non-textual Specifications

A specification does not have to be expressed in a textual language. Finite state diagrams, entity-relationship diagrams, wysiwyg tools, and many diagrams and graphics are often a superior way of visualizing and editing a specification. Diagrams combined with property sheets (as used in most popular visual programming tools) is an excellent alternative to textual languages.

Other alternatives include the use of databases to store specifications as relations or the use of XML to represent specifications as an information structure.

System Modeling

One of the more powerful techniques of a domain engineering approach is to use the set of tools to create a system modeling environment. This means supplementing the program generator with other features to allow the complete or partial simulation of the system. This simulation could be used to see the system behavior and performance. This permits a rapid iterative development of a system.