A story why software templates generally suck at OOP’s (Object Oriented Programming) Separation of Concerns and Single Responsibility Principle in real systems.
And I don’t mean only Microsoft’s templates, but generally templates provided by big IT corporations for us to start new software projects. In this article I’m going to describe the problem using Microsoft’s ASP.NET MVC template, official recommendations and techniques just as an example of a broader problem. I wonder if this is how they code in their production software. If they do – shame on them.
Microsoft addressed one of the common problems with the new ASP.NET Core templates where Dependency Injection and containers are implemented by default and included at least in one template. So I won’t rant about it, although templates are full of tight couplings.
The Evil Templates
My educated guess is that templates are intended for a smooth start for someone who is not very familiar with particular technology or with development at all. So one can download template, change ‘hello world’ into whatever text they desire and run it quickly with their favorite IDE. Takes 5 minutes. Max. Great. Except it’s not.
Already at the very beginning, these templates teach bad practices, and put people in paradigms that they can’t get away from. At least not quickly and not without pain. I mentioned tight couplings in MVC templates that existed and still exist for many, many years. One was removed in ASP.NET Core: the tight coupling between controller and repository (data access layer). But ASP.NET Core is very new and still does not have all necessary elements to use it in enterprise level systems, so anyway you will probably start a new project using older MVC version. You don’t want to use tools that are in preview state for production environments, right ? (Or do you ?)
In fact most of templates are counterproductive in the long run and have nothing to do with real challenges we face in real world systems.
Real world challenges
One of the most annoying problems is validation of data coming from UI. Common examples and practices include:
- database level of validation, typically by throwing an exception if you break Unique index, Required/Not null constraint, or Foreign Key constraint. Must write own code to cope with DbEntityValidationException and pass meaningful information to UI or other components
- sometimes developers put additional validation in controllers (or in separate business layers) or by using custom attributes in model in order to extend validation conditions, e.g. to check if a date is past or future date, or one date is greater than an other date
But how about addressing these common problems :
- passing validation attributes between connected ViewModels, DTOs (Data Transfer Objects) and Models (by inheritance); basic object oriented inheritance between classes does not work or work poorly with Code First migrations, model bindings or WCF proxy creation. You have to use magic for very basic OOP standards, or create thousands of lines of repeated code in case you have similar classes that could easily share some code in base class. Haven’t seen any solution for this in ASP.NET Code yet (maybe there is, but not clear), but in older ASP there are partial classes and special attributes to work around these problems (looks nasty)
- concerns regarding shift of business logic from model to SQL (e.g. checking uniqueness of a field, or checking if not null, letting it throw an exception after SQL CRUD command). Where is your business logic after all ? In C# or in SQL ?
How about huge state machine problem:
- visibility of buttons to change state of an object (e.g. in classic case of tech ticket application, with tech ticket states: case open, case assigned, case closed, cased deleted etc). In some states buttons should be active in some should not.
- behavior when action/trigger to change state is received, e.g. after button click (do we allow an action to change state? and if not how to report it ?)
- some fields may be updated only in particular states
- one may try to do state machine at model level (again by using validation attributes), but may prove to be too much of overhead, and raises concerns about model: is it a model or a business layer already ? (by the way validation attributes are really very developer unfriendly, similarly to model binding overriding). Also state machine libraries typically are not very friendly for models used for Code First migrations.
And another vast problem, which is authorization:
- access to some entities, fields, buttons/triggers/actions can be limited to some authorization levels / roles. Commonly you can find authorization checks in HTML/Razor or/and in controller (as authorization attributes). Which again leads to access check in multiple places and files for one single model
- proactive authorization check (check if authorized for some action before actually trying to do anything, should be reported to audit table)
- real authorization check (just before performing real action, also should be reported to audit table)
Every web application is by default a multi-threaded application where multiple users can operate on same data at the same time, but nothing is addressed in templates and best practices:
- simple proactive check for uniqueness of some field (e.g. customer name) does not work in multi-user/multi-threaded environment (would require blocking, queuing of inserts/updates on app server level, possibly message/command bus). Your colleagues may be inserting same records at the same time
- trying to insert same customer twice, in parallel, or updating same customer record in two separate threads parallel would cause concurrency exception or doubled customer in database
- data in UI is never up-to-date because basic templates have no active AJAX controls and building AJAX controls is pain in the ass in ASP.NET (yes they work, only for very basic, unrealistic scenarios)
If you are familiar with ASP MVC templates and typical ASP MVC techniques you know that they don’t address almost any of this classic problems we face in production environment. Templates are good only for school classes to learn basics. But it’s not only templates. If you face any of these problems you end up searching StackOverflow because there are no answers in Microsoft’s documentation for ASP nor in their recommended practices documents. Well, there are answers but only if you already know them and know what to search for (e.g. search particular function by name for description). There are some hidden functions or attributes which we learn about only because somebody else found them before and gracefully put them in StackOverflow.
No OOP in ASP MVC
So, there is no single place to check if something went wrong at production in standard ASP MVC templates. Let’s say a button is disabled or web form is not saved due to validation error. As you can see from my text above bug can happen in one of many validation/state/authorization levels which are all interconnected. In typical situation there is no single class/file to look for error/bug/problem. Not to mention multi-threaded (but every web app is multi-threaded!) and/or distributed systems (every web app on Azure, with more than one node is distributed). Most templates and tutorials are wrong and against OOP principles. This is not software to improve in continuous way. This is not software to maintain cheaply and efficiently. What’s funny (or not) this architecture is encouraged and recommended by Microsoft. Validation for one UI screen is spread in several files and classes, even in case of simple one model. Madness.
Other open questions that templates and recommended practices don’t answer:
- is model a model only for Code First database creation/migration procedures or full validation/state manipulation system
- if model has all business logic in attributes and functions located in the same model class, why would you need separate business logic layer then ?
- or maybe we should move some of business logic to model binding or insert just before saving to database ? or all of logic (and keep model as simple DTO with no attribute decoration?)
- but what about basic validation conditions like Required if we require data only in one state and not require in other state? (yes, one can create conditional Required version of attribute, but it then conflicts with database NOT NULL constraint)
- if only some validation is located in model and other validation checks is located somewhere else then why do we call it Object Oriented Programming and we say we really care about Separation of Concerns ? Seems we don’t
- if we agree that some basic validation is in model as attributes, and some validation is in other classes/places how to set a clear rule saying which is an attribute-based validation and which is extended one to go to some other areas of application structure ?
Summary of challenges
So let’s summarize most interesting business and technical challenges that we’re missing in typical multi-layer web templates, documentation and best practices:
- clear one place for data validation rules (what validation goes where and why)
- clear one place for state machine rules (what we can do in certain entity state)
- clear one place for authorization check rules (what can we do having particular role)
- basic multi-threading rules (concurrency in saving data with certain data and state)
These challenges are not extraordinary or rare. These are basic rules for a web application for multiple users. Show me one web commercial system, where you have no entity states, no roles nor authorization, single thread, only simple data validation in model. Show me one. We can solve these challenges by buying some commercial MVC framework or creating it ourselves or maybe you find several opensource pieces and put them together. But don’t you dare use standard templates and techniques for commercial purposes.
In the next article I will try to address some of these issues by creating real code.
Thanks for reading 🙂
CEO, .Net developer, software architect at Creative Yellow Solutions (formerly Indesys)
If you need help with your software project, or need customized software for your company, contact me at: dominik.steinhauf (at) cys.biz.pl