Some time ago, Hoppinger took on an interesting challenge. An old Windows Forms application, which had been developed for about ten years, needed a new development partner. The owners of the company were looking for a partner that could take them to the next level in digital transformation. Previously, a less careful competitor had already tried a rebuild without a proper analysis of requirements and failed at it. That's when Hoppinger came into play.
When we started looking at the application code, we were immediately clear on two things:
- it was a huge application full of valuable features;
- the code was very messy, and the documentation (both readme as well as code structure) was simply absent.
As we dove into the code, the application being on-premise started making sense: the application needs to interact with a series of physical local resources that require an actual USB cable (think legacy handheld devices). Still, the presence of a local MS SQL database meant local backups, messy old-school migrations, and complex synchronization procedures to a legacy server in the cloud. The worst offender, though, was the code itself. Having grown instead of ever being properly architected, it resembled a big ball of yarn. All of the usual suspects were there: concerns were all over the place, with most pieces of code being a huge mix of many different logical aspects, no single responsibility principle, and no meaningful modularization.
Let's dive into a useful visual. Below is a color coding of an actual block of code from the application (without the code for, well, privacy and secrecy reasons!!!). Each line of code is coloured based on its purpose: blue means business logic (such as deciding which action to perform), green means data (such as SQL queries and the related fetching/parsing), whereas orange means a resulting action (such as writing something to the DB, showing a prompt, or sending an email). First of all, this is a lot of code in a single function. Second, the concerns are mixed. You either understand all three full pages of code, or you might miss crucial details when debugging. This sort of code is hard to extend, and even harder to debug: a developer cannot abstract any details away, and must think about all details at the same time, all the time.
The good news is: we can fix this! The most important tool in order to repair this is a relatively straightforward, old technique known to software engineers as separation of concerns. Separation of concerns "untangles" the code, separating data fetching, data processing, business logic, and the resulting actions. A very good combination of frameworks that allows us to achieve this is the introduction of a data access layer/object (DAL or DAO), accompanied by CQRS to further split read and write operations.
The DAL/DAO now groups all of the data-related operations, which is most of the green bits plus a bit of blue (sometimes some post-processing or a bit of business logic needs to go to the data layer). This refers to the Q (query) of the CQRS pattern. Under "actions" we find all the operations that produce some output or permanent data change as a result of business logic applied to some data. This refers to the C (command) of the CQRS pattern. Finally, the specific logic of the application is isolated. Each block of business logic features reading data, processing it, and finally performing a resulting action.
Notice that the code has been split into files, and even into smaller code units within the files (the black separators denote different code units such as classes and functions). This refers to the RS (responsibility segregation) of the CQRS pattern. "Untangling the mess" does not just produce a better piece of code. Indeed, we can further partition our code into multiple files, code modules, and ultimately services that can even be migrated to the cloud when possible in order to simplify governance and the lifecycle of the application!
The final result is a codebase that is easier to maintain, so that developers time and effort can be dedicated to adding value instead of compensating for issues in the code, but also an on-premise application that is easier to setup, easier to backup, with better security and the possibility to roll out features one client at a time by just flipping a switch in the cloud. Talk about win-win!
At Hoppinger we do love a challenge. Do you have a legacy application that still holds significant business value, and are you looking for a strategic partner to bring it to the next level? Drop me a line!
Schrijf je in voor onze nieuwsbrief en laat ons jouw gids zijn in een complexe digitale wereld.