Category Archives: Web Programming

Pitfalls with “Convention over Configuration”

The paradigm Convention over Configuration is a great way to develop software (web) application. I like it…IFF it is implemented well.

Problem

Unfortunately, many frameworks which rely on this paradigm are hard to work with. One example is Spring Boot. Users who are new to Spring Boot must read many pages of documentation to learn the “sensible defaults”. These defaults are often not intutive to new users because the users do not yet know the underlying concepts for which the defaults are ment to be. Hence, the first steps with Spring Boot take time – more time than necessary.

Moreover, the defaults seem to work in a magical way – just by putting some new annotations at a class or a method. The javadoc often does not explain how the annotations work. It’s so easy to add a short text that describes that Spring searches the classpath for annotations.

Furthermore, annotations can also cause incompatibility issues with other annotations and conventions. For example, the annotation @DataJpaTest disables full auto-configuration such that you wonder why auto-wiring is not working anymore. Although the javadoc mentions this issue, it is unnecessarily complicated. I wish that adding annotations only adds behavior.

Finally, you can often do one thing in more than one way. Usually, basic annotations are provided which are used by aggregated annotations to cover recurring use cases. This approach often results in annotated classes which have several basic annotations twice or thrice. Although this approach does not influence the functionality, it is really confusing for (new) users who need to write some piece of code: when should I use which (aggregated) annotations? Users who read the code could ask themselves: why did the author of this code add these annotations more than once?

Proposed Solution

  1. Uncover all conventions, e.g., by a configuration file with default values, such that the conventions are visible for (new) users. In this way, the user can read through the config file and learn what features and conventions are provided by the framework. We follow this approach with our framework Kieker.
  2. Each annotation should explain how it is processed. If you have a bunch of similar annotations, either copy and paste the same text or add a javadoc link to the processing engine where the approach is described once at a central place.
  3. Let annotations only add new behavior. Let them not disable other features.
  4. Only provide one way to do something to reduce confusion and time to read/understand. When the (new) user has several possibilities to do the same thing, it is laborious to understand when to use which approach. If there is no other choice, provide at least recommendations when to use which approach.

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.