Thursday, May 21, 2009

Domain Models (continued)

Throughout my life as a software engineer I have participated in many different projects in various domains. Needless to say, I encountered some deja vu experiences in those projects, also known as war stories. One remarkable example always has been the problem domain itself. Even in projects with lots of experienced participants the problem domain had been often root of misunderstandings and misconceptions.  In large projects with outsourcing partners, external partners and other suppliers common knowledge of the problem domain is essential. A project  with lack of problem domain knowledge among the stakeholders is doomed to fail. Remember the tower of babel where lack of communication and insufficient common understanding lead to lethal catastrophe.

As I am mostly acting as software architecture mentor and coach or technology expert I am often master of the solution domain, but not of the problem domain. For me it is inevitable to obtain a detailed knowledge of the problem domain. This is even more important when developing product lines or platforms, because in that case lack of common understanding influences more than one product or solution.

How could we address that problem? My recommendation is to introduce a domain model. Of course, I am referring to the problem domain in this context.  A domain model is not just a glossary of terms – a common misconception I am often facing.

A domain model consists of all core concepts (actors, subsystems, components, services, …) relevant within that domain as well as the relationships and interactions between these core concepts.

 

A large domain typically consists of subdomains. For example, a telecommunications domain for Unified Communication might introduce subdomains such as basic communication or presence. As a consequence, the domain should be partitioned hierarchically into subdomains.  

There are different ways to descible a domain model, from informal approaches to strictly formal definitions such as a domain-specific language. In all cases, stakeholders might select textual or graphical representations, whatever is more appropriate.

Note that I have not assigned the responsibility of introducing a domain model to software engineers. Defining a common domain model should rather be a joint endeavor of all stakeholders, maybe driven by requirements engineers and architects.

If you have ever read definitions of software architecture like the one by ANSI/ISO, you might recognize that architecture definitions match closely with my definition of domain models. First of all, those architecture definitions are insufficient (due to their genericity). Secondly, a domain model is a good starting point for creating the architecture. Take the use cases (black box view) and specify their dynamics using the domain model entities (white box views). Supplement this architecture core with design tactics for non-functional requirements. This will lead to the architecture baseline. Using the domain model also helps you staying focused on the problem domain instead of diving to the solution concepts too early.

Eventually, a domain model defined, understood and agreed by the various stakeholders such as requirements engineers, developers, testers, architects, product managers, customers serves as a fundamental mean for architecture design and communication. 

Of course, the solution domain itself can also be expressed by a domain model. This is why the main task of an architect consists of mapping a problem domain to a solution domain.

Formalizing both to a sufficient extent helps automating this process using model-based software development approaches. Such automation, however, might be too expensive for one-off applications or smaller product lines.

Whenever you are participating in a development process in the presence or future: do not forget to specify the domain model if not already available.

Sunday, May 17, 2009

Podcast on Software Architecture

For those of you capable of understanding German, I’d like to point you to our new Podcast on Software Architecture called Software ArchitekTOUR. You may also search in the ITunes Store for the podcast and find it – for example, search for ARCHITEKTOUR in the podcast category.

The Podcasters are

  • Markus Völter (freelancer, associated with ITEMIS)
  • Stevan Tilkov (innoQ)
  • Christian Weyer (thinktecture)
  • Michael Stal (Siemens)

To stay in touch with reality we have split up the podcast in three subcategories:

  • General Architecture Topics (sponsored by IBM)
  • Java and Software Architecture (sponsored by innQ, itemis, thinktecture and Siemens)
  • Microsoft Technologies and Architecture (sponsored by Microsoft)

There are already 4 episodes available. Episode 0 is more intended to introduce ourselves. Episodes 1-3 cover patterns in general, as well as patterns in Java respectively .NET.

 

Listen, enjoy, and give us feedback

Tuesday, May 12, 2009

Simplicity rules

Many architectures are overwhelming. Not that they shine due to their excellent quality. Rather they appear as a big ball of mud. I already mentioned what I am calling design erosion in the context of architecture refactoring.

To keep an architecture small, expressive and simple we can do a couple of things as software architects.

For example:

  • Each and every design decision must be based on an architecturally-relevant requirement. There is no decision without documented reason. Of course, this requires architects to feel responsible for the quality of these architecture requirements, but not for requirements engineering, of course! It is recommended practice to keep track on where in the architecture which requirements are “located”. Requirements traceability is an essential value, especially when assessing, refactoring or evolving a system. I am assuming here that architects already checked for the feasibility and essence of the requirements from a business perspective. Availability of 99.99999% is not reasonable in a project with a budget of 100k bucks. 
  • Introduce symmetry and conceptual integrity. This includes the prescription of specific patterns, the introduction of design and coding guidelines, as well as the introduction of guidelines for (at least the most important) non-functional qualities. This prevents that the same problem is solved in various ways within the same solution space and it makes sure, we are applying best practices from experts instead of reinventing the wheel. War story: A system where designers have introduced dozens of ways for fault handling will be inexpressive and complex.
  • Don’t consider technologies as toys. Many projects play with technologies. They base their decisions on a technology-first approach. This is human and we as software engineers like to experiment with the new hip operating system or SOA middleware. But in practice, we should first create an appropriate architecture meeting the requirements (see first bullet point) before we should start introducing new technologies. The business and the requirements drive the architecture, not technology.
  • Test technology. The previous point does not mean we should not care about technology – only that we first address the requirements. Every technology must be checked for its appropriateness. If your task is to build a high performant messaging backbone, then you better check whether EJB is really the proper platform to use. Don’t trust any vendor’s promises here! They do not know your problem context and system environment. Building throw-away prototypes is the best way to check technologies.
  • Apply a test-driven development approach: this is to introduce a kind of safety net. Emphasize testability in your architecture design, e.g., by proper modularization, interfaces, and service contracts. Test-driven in this sense also includes regular design and architecture assessment where you try to identify architecture smells.
  • Regular architecture refactoring helps address architecture issues early. When a dependency cycle has just been introduced unintentionally, it is not a big issue to detect this kind of design erosion early with architecture reviews or architecture analysis tools. You are then able to get rid of the problem early by architecture refactoring. The more you wait, the more architecture entities will make it difficult to address the problem without heavy impact. Thus, do regular architecture reviews and refactorings.
  • Strategic before tactical design. Don’t try to introduce over-generic solutions with myriads of configuration options. First address all strategic requirements (functional requirements and operational requirements) before dealing with tactical issues such as modifiability. Use the Open/Close principle to open your architecture for variation.
  • Introduce priorities for all requirements/features. The priorities help decide which requirement to address first in architecture design. If security is more important than performance, you’ll end up in a completely different solution architecture, then wheny performance has the higher priority.
  • Follow an approach of piecemeal growth. In all but the most trivial applications a big design upfront approach will be doomed to fail. Thus, assign requirements depending on their priorities to iterations and build your system incrementally.

 

These are only a handful of recommendations. Certainly, there are even more. Any tipps from your side?