Validators, transformers and injectors

Most software developers tends to inflate the complexity of their own business logic, to the point where the cognitive context required to understanding their product, becomes so overwhelming, that maintaining their code base becomes literally impossible. When this happens, it is referred to as “the big ball of mud”.

If the GoF taught us one thing in their famous book “Design Patterns”, it was that language helps us understand and categorize problems, which again results in better structure, due to making the code more easily recognized, and possible to speak about, within a common terminology, easily understood by everyone agreeing upon the vocabulary – Hence, I propose the following language additions to our vocabulary as we create methods taking input intended to be somehow stored.

  • Validators, validates input data before the data is stored
  • Transformers, mutates data before the data is stored
  • Injectors, adds to the input data before it is being stored

Most developers have probably heard of validators. These are for instance objects that prevents us from registering at some website unless we provide a valid email address, etc. However, I don’t think anyone have proposed the other two elements previously. Hence I will explain them below.

A transformer is something that takes one of your input fields, and somehow mutates it, to become something different. The typical use case is storing a password from some website. You never want to store the password in plain text though, typically you want to hash it using for instance BlowFish or something similar. This is just one example, and there exists hundreds of other similar concepts, such as for instance always storing data as UPPER CASE or only lower case for that matter. Cleaning up sentences with correct punctuation and sentence capitalization, or making sure names are stored correctly with capital letters. The creative mind can probably come up with dozens of additional similar constructs, but they can all be categorized into the “transformer” category.

Injectors are not part of the input data, but somehow retrieved from some other source, yet still needs to be associated with the data you want to store. From my own industry, which is FinTech and trading systems, a typical example is the trading accounts. When a user registers as a trader in my system, I often want to create a trading account and associate with the user record somehow. This process is typically done by an external system, often the trading platform itself, and then as I persist the user, it becomes associated with that user. Other examples might include storing the IP address during a registration process, or using the IP address to lookup the country of origin the user is registering from, and storing its three letter abbreviated code. All of these can be referred to as “injectors”. Basically, an injectors adds data to the existing input before the object is stored.

The point of this exercise, is that once you realize that the above three simple concepts and words probably includes 95% of your existing business logic, you have a language to use as you speak about your logic, making it much easier to convey your meaning. Basically, it becomes the software development equivalent of what Domain Driven Design refers to as “bounded context”. Or, to be more specific, it becomes the bounded context for storing data from input given by another client somehow.

As you realize that these are generic constructs, you can start dividing your business logic into reusable blocks of code, where 95% of your existing business logic is replaced by three simple interfaces, with some 3-5 different implementations each.

  • IValidate (field)
  • ITransformer (field)
  • object IInjectable ()

At which point everyone can easily see what your code does, and the cognitive requirement to understanding it, is significantly reduced – Making it much more maintainable and easy to debug. In fact, one could even imagine constructs such as these.

class Client
{
   [Validator(Type = typeof(EmailValidator))]
   public string Username { get; set; }

   [Transformer(Type = typeof(BlowFishTransformer))]
   public Username { get; set; }

   [Injectable(Type = typeof(TradingAccountInjectable))]
   public string TradingAccount { get; set; }
}

Allowing you to 100% declaratively see what happens to the data by simply inspecting your model. The above of course illustrates how logic can be associated with your data, to increase data integrity, using an AOP type of syntax – While making the code 100 times more easily understood and maintainable – At which point your specialized business logic implementation is effectively reduced to ZERO lines of code!

Business logic you said? Sorry, we don’t do that here … đŸ˜‰

Published by servergardens

Create .Net Core CRUD APIs wrapping your SQL database in seconds