How to write a Software Architecture Chapter?

If you need to document your planned or existing software architecture, it’s often difficult to know where to start. And even if you have thought about it some time, you probably don’t know how to structure your text so that a novice reader is able to follow you.

There are a few books out there whose autors describe very well how to write such software architecture desciptions. For example, have a look at XXX. They explain in detail which contents are required in which order. However, who has time to read these books and find the relevant paragraphs?

For this reason, I put together the most important parts below. Of course, this overview is from my point of view. Nevertheless, it should give you a faster introduction to this topic compared to finding and reading the relevant paragraphs of interest in a book of many hundreds of pages.

I like templates, although I do not like to cook or bake using a recipe. Templates ease the start to write. They give you a predefined structure that you could easily follow. In this way, you know what to write and in which order. So, here is my templates for describing a certain software architecture:

Introduction (without a section title)

  1. Introduce the domain of application of your architecture so that the reader knows what he or she should expect from your description. Otherwise, if you do not give context, the reader might expect everything, but probably not what you want him or her to tell.
  2. One sentence about the content of each following subsection so that the reader knows what you will describe in which order.

Architectural Drivers

  1. Requirements on your architecture, including corresponding justifications
    1. Use phrases like
      • “we expect from your architecture …” or
      • “our architecture must be able to …” or
      • “our architecture should …”
  2. Constraints of your architecture, including corresponding justifications
    1. Your software architecture will not represent the one-and-only architecture which matches to all of the problems in the world. Hence, you should name the constraints of your architecture.

Components of your Architecture

  1. Describe each component in a separate section
    1. Give it a name
    2. Describe what the component represents (and, if useful, what it does intentionally not represent)
    3. Describe the structure of your component, including corresponding justifications
    4. Describe the responsibilities of your component, that means, what are the specific tasks of the component, including corresponding justifications
    5. Describe what tasks are intentionally not part of the component

Progress Monitoring of Loops

When coding a loop, we often insert some logging code for debugging or progress monitoring purposes. The following code snippet shows an example:

for (int i = 0; i < invocations.size(); i++) {
  // loop body begin
  ...
  // loop body end
  System.out.println("current index: "+i); // pure java
  currentTimeInMs = ...;
  if (currentTimeInMs % 1000 == 0) {  // log every econd
    logger.debug("current index: {}", i);    // slf4j
  }
}

Disadvantages of the Naive Approach

However, this approach has some disadvantages. First, the logging code is executed by the same thread which executes the loop body. If the logging code causes an exception, for example, due to a NullPointerException, the execution of the loop body is interrupted. Thus, the execution of the application can break because of some fault in the logging code.

Moreover, the executing thread is thwarted by the addtional logging code. Remember that executing I/O operations, like printing to the console or to a file, is slower by several orders of magnitude. Especially for performance critical code regions, this approach is not recommended.

Finally, the logging code is executed in each and every iteration of the loop although it is often sufficient to log the loop’s state every second or every minute. If you now think of a solution similar to the one shown above in Line 5, then remember that this additional if statement causes even more runtime overhead and further increases the potential for errors.

A Better Approach

A less intrusive, less error-prone, and faster approach is the following. First, we declare a volatile field progressIndex which represents the current index of the loop we want to monitor. For this purpose, we update the value of this field as shown in the following code snippet. We do not insert our original logging code here.

for (int i = 0; i < invocations.size(); i++) {
    progressIndex = i;
    // loop body
}

Instead, we create an additional thread which executes our logging code now. This thread performs a do-while loop as shown in the following code snippet from Line 7 to Line 28. We use `Thread.sleep()` to implement a user-defined time interval (here: 1000 ms). The thread reads the current index of the loop under monitoring indicated by the variable progressIndex in Line 13. As we declared it as volatile, it is synchronized between our new monitoring thread and the application thread(s). We cache the progressIndex as local variable, since the value of this variable can change on each subsequent read-access. In this way, the value is consistent within an iteration of the do-while loop.

To avoid interfering with the application, we declare our new monitoring thread as a deamon. In this way, the thread is automatically terminated by the JVM when all application threads have terminated.

The rest of the do-while loop computes the remaining execution time of the application and executes the domain-specific logging code. In this example, we print out the current number of NoSql queries which were already executed by the application loop.

Thread progressMonitoringThread = new Thread(new Runnable() {
    @Override
    public void run() {
        long lastTimestamp = System.currentTimeMillis();
        int lastProgressIndex = progressIndex;
        
        do {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            final int localProgressIndex = progressIndex;
            
            long currentTimestamp = System.currentTimeMillis();
            long durationInMs = currentTimestamp - lastTimestamp;
            int count = localProgressIndex - lastProgressIndex;
            if (count <= 0) continue;
            long durationInMsPerElement = durationInMs / count;
            
            long remainingDurationInMs = durationInMsPerElement * (numQueries - (localProgressIndex + 1));
            String message = String.format("Executing query %s/%s (%s sec. remaining)", localProgressIndex + 1,
            numQueries, Duration.ofMillis(remainingDurationInMs).getSeconds());
            System.out.println(message);
            
            lastTimestamp = currentTimestamp;
            lastProgressIndex = localProgressIndex;
        } while (progressIndex < numQueries);
    }
});
progressMonitoringThread.setDaemon(true);

progressMonitoringThread.start()

This approach does not break the execution of the application if the logging code is faulty. In the worst case, our monitoring thread terminates – no interfering with the application. Moreover, the runtime overhead is reduced to a minimum. We only set the progressIndex in each iteration of the application loop. Finally, the approach allows to log the state of the loop at a user-defined time interval. We are not forced to log it on each iteration anymore. Hence, we have changed the type of notification from an event-driven style to a time-driven style.

Join Points and their Pointcuts in AspectJ

In the following list, we name each join point with its corresponding pointcut because it was initially not apparent to me how to capsure all calls (or executions). You cannot use one single * wildcard to match all method and constructor calls. You need to define a composite pointcut which capsures on the one hand all method calls and on the other hand all constructor calls. This differentiation by AspectJ is not directly reflected by the documentation, but only by AspectJ’s different pattern syntax for call (or execution). To capsure method calls, you need to use MethodPattern. To capsure constructor calls, you need to use ConstructorPattern. The complete syntax for all patterns of AspectJ can be found here.

  • method-calls: call(MethodPattern)
  • method-execution: execution(MethodPattern)
  • ctor-calls: call(ConstructorPattern)
  • ctor-execution: execution(ConstructorPattern)
  • static init: staticinitialization(TypePattern)
  • preinit: preinitialization(ConstructorPattern)
  • init: initialization(ConstructorPattern)
  • field-reference (a.k.a. field-read): get(FieldPattern)
  • field-set (a.k.a. field-write): set(FieldPattern)
  • handler: handler(TypePattern)
  • advice-execution: adviceexecution()

Aspect-oriented Programming with AspectJ

AspectJ is an open-source framework that allows you to write Java code following the aspect-oriented programming (AOP) paradigm. AOP provides an alternative way of programming in the following situation:

Let us assume you want to implement some functionality which is required at multiple locations in your application’s source code. If we follow the object-oriented programming (OOP) paradigm, we would proceed as follows. First, we declare a new class. Then, within this class, we declare a new method which implements the required functionality. If necessary, we add some associated fields. Afterwards, we place an invocation of the method (together with the class instantiation) at each of the required locations in our source code.

If we follow the AOP paradigm, we would proceed as follows. First, we declare a new aspect which is similar to a class. Then, within this aspect, we declare a new advice which corresponds to the method from above. If necessary, we add some associated fields to the aspect. So far, we have proceeded exactly as if we had followed the OOP paradigm – only with different terms. But now, we do not place an invocation of the advice at each of the required locations. Instead, we write down these locations in our aspect and pass it to an additional compiler – the AOP compiler. This AOP compiler reads in the aspect and automatically places an invocation of the advice at each of the designated locations. Thereby, it also handles the instantiation of the aspect. The set of our locations is called a pointcut and is associated with our advice. In this way, the AOP compiler knows which code it should place at which locations. However, most AOP compilers cannot insert advices at arbitrary locations, but only at well-defined locations. For example, the AspectJ compiler can insert advices at method calls and field accesses, but not at loops or if-statements. Such well-defined locations are called joinpoints. Thus, a pointcut is not a set of arbitrary locations, but a set of joinpoints.

Hence, an aspect is not instantiated and accessed directly from within your source code. Instead, it is automatically inserted into your source code by the AOP compiler. For this reason, we do not term it class, but aspect. In summary, the AOP paradigm allows to insert some functionality at multiple locations in your application without the effort of touching the source code at each individual location by hand. In this way, it provides a clean modularization of crosscutting concerns and thus serves as a complement to the OOP paradigm.

AOP terms in short:

  • A jointpoint is a location in code at which the AOP compiler is able to automatically insert new code either before, after, or around (i.e., before and after). Valid joinpoints in AspectJ are, for example, method declarations, method calls, and field read/write accesses. So far, AspectJ does not support inserting code at loops and if-statements. So, AspectJ does not consider these constructs as joinpoints.
  • A pointcut is a set of joinpoints at which we want to insert the same new code. This set of joinpoints is not described as an enumeration of each and every individual joinpoint, but instead as a single compact expression similar to a regular expression.
  • An advice contains the new code which we want to insert at multiple joinpoints in our application’s source code.
  • An aspect contains one or more advices and their associated pointcuts. By default, AspectJ creates and uses one instance per aspect. So, you can consider an aspect as singleton. However, you can change this behavior to a per-object or per-joinpoint base (see aspect instantiation for more details).

For more information, we refer to the official Getting Started and the mapping of join points and pointcuts.

Writing your own custom PMD rules: PMD, Eclipse, Maven

How to write an own PMD rule?

  1. Create a new class (called rule in the following) that extends the PMD class AbstractJavaRule (see PMD documentation: How to write a rule class?).
    1. Override the visit methods which represent the Java syntax elements you want to analyze.
    2. Use the addViolation() methods within the visit methods to indicate a violation of your rule.
    3. Use the definePropertyDescriptor() method in the constructor to define a configuration parameter for your rule. Use the getProperty() method to read a configuration parameter within the visit method.
  2. Add your rule to a custom ruleset xml file (see PMD documentation: How to write a PMD rule?). Let us assume it is stored in a/b/c/my-ruleset.xml.
    Example ruleset file:

    <?xml version="1.0"?>
    <ruleset name="chw's custom rules" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
    
    <description>Christian Wulf's custom rules</description>
    
    <rule class="de.chw.MissingPluralVariableName" name="MissingPluralVariableName"
    message="The variable {0} is not named in plural although its type {1} represents a collection.">
    <description>
    A variable that represents a collection (incl. set and list) should be named in plural form.
    </description>
    
    <priority>1</priority>
    
    <example>
      <![CDATA[
      List<Stage> stages;
      Collection<String> words;
      ]]>
    </example>
    </rule>
    
    </ruleset>
  3. Package your compiled rule and the ruleset file (into an archive file, e.g., zip or jar).
  4. Now, you can include your ruleset archive into an arbitrary project ruleset file by inserting the following line:
    rule ref="a/b/c/my-ruleset.xml"

How to let the PMD Eclipse plugin recognize your own rule?

Short answer: Build an Eclipse fragment plugin for the PMD Eclipse plugin (see this link).

The most important paragraphs of the link are:

  1. Creating the plugin fragment in Eclipse
  2. Packaging and distributing the new rule
  3. Installing the new rule

How to check your own PMD rule via Maven

  1. Add the maven-pmd-plugin as plugin to your pom.xml.
  2. Add (your own) custom ruleset archives as a <dependency> of the plugin.
  3. Add your project-specific ruleset in <configuration><rulesets>....
  4. Define what goals should be executed in which phases in <executions>....

Example excerpt of a pom.xml:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-pmd-plugin</artifactId>
  <version>3.4</version>
  <dependencies>
    <dependency>
      <groupId>de.chw</groupId>
      <artifactId>pmd.ruleset</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/conf/quality-config/pmd/CustomPmdRules_1.0.0.201505130542.jar</systemPath>
    </dependency>
  </dependencies>
  <configuration>
    <rulesets>
      <ruleset>${project.basedir}/conf/quality-config/pmd-ruleset.xml</ruleset>
    </rulesets>
    <linkXref>true</linkXref>
    <includeTests>true</includeTests>
    <targetJdk>${java.version}</targetJdk>
    <failOnViolation>true</failOnViolation>
  </configuration>
  <executions>
    <execution>
      <phase>test</phase>
      <goals>
        <goal>pmd</goal>
        <goal>cpd</goal>
      </goals>
    </execution>
  </executions>
</plugin>

 

What is a UML Software Component?

Introduction

Since I work at the Kiel University, I teach UML to the students in the 3rd and 4th semester of computer science. At the latest when they need to work out a UML component diagram and a corresponding deployment diagram, the following questions arise:

What is a UML software component? What is the difference between a class, a package, and a component?

For this reason, we address these questions in this post. First, we look at some definitions to distinguish a component from other UML entites.

Component vs. (Class, Package, and Library)

Let’s start with the most important message of this post: Consider a component as a composition of classes, packages, and sub components that is accessible only by other components and only via interfaces.

TODO

Communication within and between components

TODO UML notation

Example Component Diagram

When creating a component diagram, remember that it must depict additional semantics compared to all other diagram types such as class and package diagrams. Otherwise a component diagram is useless and can be thrown away.

TODO diagram with components (android, server, db) and sub components: A3, User, Role, ORM, …

Example Component Representations in Java

Since the Java programming language does not provide the abstraction of components, we need to represent it with the means Java offers us.
Hence, we discuss the three following representations of a component possible in the Java universe.

  1. The class-based approach
  2. The package-based approach
  3. The library-based approach

Due to Java’s direct support for interfaces, we represent a component’s interface by one or more Java interfaces.

The class-based approach

In this approach, we represent a component by a class that implements all interfaces the corresponding component should provide.

 

The package-based approach

TODO

The library-based approach

TODO

Ajax-based Form Tag

Limitations of Current Approaches

Although Grails provides the tag to send an HTML formular via AJAX, it is not recommended to use it for at least two reasons:

Introduction

Suppose we already have a web project with some views that contain some <form>ulars. We now want to replace their default submit behavior with an ajax-based one.

For this reason, we show in this post how to define an ajax-based HTML formular with the help of jQuery.
First, we define the requirements we impose on such a concept. Then, we describe our solution and show an example implementation.

Requirements

  1. Less modification: We want to modify an existing form tag as less as possible to minimize the modification effort
  2. Less code: We do not want to encapsulate the ajax functionality within an own tag to keep our project’s code size small and its complexity as simple as possible

A Solution

If we want to ajaxify an existing <form>, we first need to declare it to use ajax—of course.
Moreover, we need to define where the ajax response should be written to.
A common approach is to replace the contents of an html element with this response.

In order to meet requirement 1 (Less modification), we add a CSS class to the target form tag (we name it ajax) indicating that this form should use an ajax-based request on submit.
We then bind an onsubmit event handler to all form tags that belong to this CSS class.
In this way, we simultaneously meet requirement 2 (Less code) because the event handler with the ajax logics needs to be declared only once at a central place, e.g., in a javascript file.

An Example Implementation

$(function() {
    $(document.body).on('submit', 'form.ajax', function(event) {
        event.preventDefaults();

        $.ajax({
    
        }).done(function(data) {
        
        });
    });
});

 

Auditing & Approval of a Database Entity

In this post we address a problem in the web programming context. Imagine our customer wants us to develop a web application that provides a standard CRUD user interface for a very important, very special, mission-critical entity: a Book.

class Book {
  String title
  String isbn
  Date releaseDate
  List<String> authors
}

Ok, that’s quiet easy. Start your favorite IDE with your web framework of choise and use its scaffolding capability to generate the CRUD controller and the CRUD views.
Now, suppose our customer wants a book to be traceable. That is, when creating, updating, or deleting a book, the corresponding editor and the modification date must be accessible in addition to the modification itself.

There are several approaches to achieve this goal. We discuss the following ones in more detail:

  1. The “active flag” approach
  2. The “history table” approach

The “active flag” approach

In this approach we extend the Book entity by the following attributes:

class Book {
  String title
  String isbn
  Date releaseDate
  List<String> authors

  boolean deleted

  String editor
  Date modificationDate
  long traceId
  boolean active
  long versionNumber
}

First, we add the deleted flag to indicate that the given book was deleted.
Without this flag, we would not know whether the latest version should be displayed or not.

In addition to the required editor and the modification date, we add the traceId attribute.
It represents a constant identifier that is generated by the initial version of a Book instance and passed to all its following versions.
In this way, we can trace modifications of a Book instance.

For example, when sorting all Books of a particular traceId by their modificationDates in descending order, we get the latest version at the top and the first version at the bottom.

Basically, we are finished now.
The four new attributes fully implement our customer’s requirements (apart from the missing implementation logics).
However, it is common practice to add an active flag and a versionNumber attribute to ease the writing of database queries and to increase the query performance.
The active flag indicates that a given book instance is the latest version and is not marked as deleted.
The versionNumber attribute represents the version number of the given book instance. It is not necessary for the approach to work properly. However, it could be useful for the user in order to know how often the book has already be modified.

The “history table” approach

In this approach we extend the Book entity by the following attributes:

class Book {
  String title
  String isbn
  Date releaseDate
  List<String> authors

  boolean deleted

  String editor // a user which could have also been deleted
  Date modificationDate
  // removed traceId
  // removed active
  long versionNumber
  OldBook predecessor
}

The attribute predecessor of a book refers to the book’s previous version in the new table OldBook. This table contains all previous versions of all books and thus represents the books’ history. It has the same structure as the Book table.

class OldBook {
  String title
  String isbn
  Date releaseDate
  List<String> authors
  
  boolean deleted

  String editor // a user which could have also been deleted
  Date modificationDate
  long versionNumber
  OldBook predecessor
}

This approach works as follows. Everytime a book is being modified, its attributes (before the change) are stored in a new OldBook instance. Afterwards, the modification is applied to the book and its predecessor is set to the new OldBook instance.

The main difference to the previous approach is the separation of the current version and all its old versions. This approach requires a less complex query to list (a subset of) all current books. Furthermore, it does not require to index an attribute to perform this query in a fast way. In contrast, the previous approach needs to index the active attribute for an efficient execution. Finally, it is a modular approach. If you want to introduce versioning for your existing book table, you do not need to change your queries to list all current books. You only need to add the attributes, necessary for versioning, to the Book table and the OldBook table.

Moreover, we directly represent the order of modifications by using the foreign key predecessor in the OldBook table. However, you can stick to the traceId  attribute, if you like.