As an architect or a lead developer responsible for the structure of a code base, you spend time creating a clean structure for your code. The challenge is to make sure that the intentions you had when creating the structure won’t be violated in the future, what is often named design erosion or architecture erosion.
Let’s take a real-world application such as Octopus Micro Finance Suite, an open-source application developed by the Octo Technologies company. Typically, in such a 3 tiered application, the UI code shouldn’t access directly the database. Concretely, the code of the assembly Octopus.GUI shouldn’t use directly the class Octopus.Shared.DatabaseHelper.
As shown in the screenshot below, with NDepend you just have to right-click the cell on the Dependency Structure Matrix that represents the dependency that is forbidden, and select Generate a CQL constraints that warns if this dependency exists. The CQL rule generated basically says:
I’ll warn if there is an assembly named Octopus.GUI that is using directly a type named Octopus.Shared.DatabaseHelper
As in every deny system, there is also a possibility to have some permit only CQL rules. Maybe, the architects of the Octopus project want to make sure that the assembly System.Drawing is only used by the assembly Octopus.GUI. Here, the CQL rule says that:
I’ll warn if there is an assembly that is not named Octopus.GUI and that is using directly an assembly named System.Drawing.
The CQL language presents some smarter usage conditions to write smarter constraints. For example, the architects of the Octopus project might want to make sure that no SQL connections are created outside the type System.Data.SqlClient.SqlConnection. Here, the CQL rule says that:
I’ll warn if there is a method declared outside the type Octopus.Shared.ConnectionManager that is creating an instance of the class System.Data.SqlClient.SqlConnection.
Another usage conditions is the derivation. The following CQL rules says that: I’ll warn if there is a class declared outside the assembly Octopus.GUI that derives from System.Windows.Forms.Form.
In the same spirit, CQL supports the Implements condition to constraint which
classes implements a certain interface.
Finally, another very useful usage condition is the field writing one. As shown in a previous post, you might want to ensure that the only way a field is written is by calling its corresponding property setter. Doing so, it is easier to maintain and debug the field state, you don’t have to put breakpoint everywhere the field is assigned.
CQL rules are stored inside the NDepend project file. You can also store CQL rules directly in the source code as shown here. All rules will be verified each time NDepend will analyze the project and if some rules are violated, they are enumerated in the report built during the analysis.
All resemblance with the way how xUnit tests tools are working is intended. xUnit tests test the code to prevent correctness regression. CQL rules test the structure to prevent architecture erosion.