Monolith Application - Architectural Re-work

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
28,050
Reaction score
17,804
Hi ladies and gentlemen.

I have this up and coming long term project I will likely be tasked with modernizing and re-structuring. This entire solution is about 12 years old and still utilizes what I could guess is 3 layer philosophy. It comprises the following:

  • A single data access project using SQLClient.
  • Around 50+ WCF/WebAPI/MVC4 front end projects.
  • A massive "data layer" which is packed with SQL code, sql queries. Methods which seem to have numerous conditional statements to satisfy the requirements of the 50 odd front ends.
What I have created so far:

An onion architecture, single application (class) which is small. It simply has the dbcontext, entities and some infrastructure services such as SendGridEmailer and TwilioSMSSender. It is a database first approach. I had to scaffold the entire existing database up to get my context/entities.

After this is where the waters start getting murky for me. The Services.

I'm going to pick a very simple example of what currently is. 20 or so of these front end projects use, for example, a GetEmployeeById method by literally calling a static Employee.GetEmployeeById. But to satisfy the different requirements of the callers, as I said, scattered with conditional logic.

What I am aiming to do. Good or bad?

Have one project which is the one I have, purely a data access layer.
Have standard CRUD services in this data access layer for each entity type, returning only Dto's to keep entities out of the callers.
Have each project implement it's own service where it can determine what it wants to do with the data.
Each project simply injects the required service interface it needs and takes it from there.

Your thoughts on how to proceed and where I can improve are appreciated guys.
 
Hi ladies and gentlemen.

I have this up and coming long term project I will likely be tasked with modernizing and re-structuring. This entire solution is about 12 years old and still utilizes what I could guess is 3 layer philosophy. It comprises the following:

  • A single data access project using SQLClient.
  • Around 50+ WCF/WebAPI/MVC4 front end projects.
  • A massive "data layer" which is packed with SQL code, sql queries. Methods which seem to have numerous conditional statements to satisfy the requirements of the 50 odd front ends.
What I have created so far:

An onion architecture, single application (class) which is small. It simply has the dbcontext, entities and some infrastructure services such as SendGridEmailer and TwilioSMSSender. It is a database first approach. I had to scaffold the entire existing database up to get my context/entities.

After this is where the waters start getting murky for me. The Services.

I'm going to pick a very simple example of what currently is. 20 or so of these front end projects use, for example, a GetEmployeeById method by literally calling a static Employee.GetEmployeeById. But to satisfy the different requirements of the callers, as I said, scattered with conditional logic.

What I am aiming to do. Good or bad?

Have one project which is the one I have, purely a data access layer.
Have standard CRUD services in this data access layer for each entity type, returning only Dto's to keep entities out of the callers.
Have each project implement it's own service where it can determine what it wants to do with the data.
Each project simply injects the required service interface it needs and takes it from there.

Your thoughts on how to proceed and where I can improve are appreciated guys.
is this a new rewrite?
Have a look at MediatR and Vertical Slice Architecture. The MediatR Handler becomes your service and is injected into your endpoint as if by magic. You DI DbContext into the handler etc
 
is this a new rewrite?
Have a look at MediatR and Vertical Slice Architecture. The MediatR Handler becomes your service and is injected into your endpoint as if by magic. You DI DbContext into the handler etc

I think this is a rewrite. Having looked at it for a week now, refactoring is no longer practical.

It's funny you should Mediatr, I have been delving into that in the last month or so and strongly considering going the commands and queries route for this and have a basic practice project going with injecting the context into the handlers so we are on the same page there. I will take a look at Veritical slice. Thanks Spacerat
 
Sounds like you are on the right path. Something you didn't mention is handling the interim routing, how are you going to replace the existing functionality over time? This can be a huge time sink and its worth planning properly up front. With 50+ front ends there is going to be quite a bit of testing and collaboration going on for swapping each endpoint.
 
Sounds like you are on the right path. Something you didn't mention is handling the interim routing, how are you going to replace the existing functionality over time? This can be a huge time sink and its worth planning properly up front. With 50+ front ends there is going to be quite a bit of testing and collaboration going on for swapping each endpoint.

Just have to wrap my head around some stuff and check out some more things in this project and will come back to this question.
 
is this a new rewrite?
Have a look at MediatR and Vertical Slice Architecture. The MediatR Handler becomes your service and is injected into your endpoint as if by magic. You DI DbContext into the handler etc

This is the way.
Simple solutions to complex problems.
You can literally copy/paste the code I shared here and have a killer architecture - https://mybroadband.co.za/forum/thr...points-have-a-question.1207627/#post-30066005

Onion architecture/clean architecture is not needed.

You basically need 4 projects in a solution
Project.Api - Program.cs + controllers/minimal api
Project.Features - business logic. MediatR handlers. Named as a business process - AddProductToWishlist
Project.Data/Model (use whichever word you like) - DbContext + objects to use as DbSets
Project.Infrastructure (there is probably a better name for this) - code that really is shared. It is not related to business operations. Extension methods. Api client implementations. Utilities.

This architecture does not dictate what is the scope of a Project. But it definitely is a monolithic architecture - which is 100% fine, no matter what anyone says.


I think this is a rewrite. Having looked at it for a week now, refactoring is no longer practical.

It's funny you should Mediatr, I have been delving into that in the last month or so and strongly considering going the commands and queries route for this and have a basic practice project going with injecting the context into the handlers so we are on the same page there. I will take a look at Veritical slice. Thanks Spacerat

Rewrites of complicated applications are usually not really viable from a business point of view.

Refactoring is always possible, but often it will have to be a middle ground. e.g it will take a lot of effort to get the existing code base onto .net 6.

Then it might make more sense to have 2 applications. New features are built in the new system.
If old features are changed, you evaluate at that time - “is this worth migrating/rewriting in the new application, or are we just fixing a minor bug/updating a label/adding a field/etc”

This is easier to sell, because you have the additional value proposition of “we’ll be able to build new features faster on a new platform”
 
Thanks Kabal. Hitting the sack and will check this out later.
 
This is the way.
Simple solutions to complex problems.
You can literally copy/paste the code I shared here and have a killer architecture - https://mybroadband.co.za/forum/thr...points-have-a-question.1207627/#post-30066005

Onion architecture/clean architecture is not needed.

You basically need 4 projects in a solution
Project.Api - Program.cs + controllers/minimal api
Project.Features - business logic. MediatR handlers. Named as a business process - AddProductToWishlist
Project.Data/Model (use whichever word you like) - DbContext + objects to use as DbSets
Project.Infrastructure (there is probably a better name for this) - code that really is shared. It is not related to business operations. Extension methods. Api client implementations. Utilities.

This architecture does not dictate what is the scope of a Project. But it definitely is a monolithic architecture - which is 100% fine, no matter what anyone says.




Rewrites of complicated applications are usually not really viable from a business point of view.

Refactoring is always possible, but often it will have to be a middle ground. e.g it will take a lot of effort to get the existing code base onto .net 6.

Then it might make more sense to have 2 applications. New features are built in the new system.
If old features are changed, you evaluate at that time - “is this worth migrating/rewriting in the new application, or are we just fixing a minor bug/updating a label/adding a field/etc”

This is easier to sell, because you have the additional value proposition of “we’ll be able to build new features faster on a new platform”
Only comment is we call infrastructure common as it can really be anything.

If you have multiple apis or the means to break it down to a more microcseviced architecture, look into gateways as well like ocelot. It really easy to then use that as a bridge between old code and new with versioning etc as well and allows independent scaling.
 
  • Like
Reactions: B-1
Be aware that refactoring has a price. refactoring means that you gonna have to test rigorously after each cycle. If you dont have a good test suite refactoring might bite you
 
I'll be the devil's advocate, but these rewrites very rarely end well if the team (or worse, one guy) doing it doesn't have the experience to to split up a "monolith" into distributed services.

I've seen and deal with so many projects where guys over engineer the code base with layers of interfaces, abstractions, nuget packages, wrapping the standard lib into convenience packages and they end up creating a bigger mess than what they started with.

If you are doing this in C# beware the interface hell and multi projects in a single repo.
 
Thanks for the advice guys. I am coming back to this for further discussion, just in the middle of a relocating to another province.
 
My advice don't over-engineer. Only integrate and rewrite the parts you are working on.
 
Top
Sign up to the MyBroadband newsletter
X