2

We have a very complex and mature ASP.NET web application that is about 20 years old and has 5 million lines of code spread across roughly 30 project in a single monolithic solution.

It's running on .NET Framework which is no longer being supported by Microsoft using WebForms.

We are in the early stages of rewriting it using .NET Core API (backend) with Angular (separate front end) using Clean Architecture.

However, all the examples I came across online (GitHub, PluralSight, YouTube, Clean Architecture Book, etc.) are simple demos. They usually consist of 4 Projects:

  1. Presentation (API Controllers)
  2. Infrastructure (HttpServices, Persistence, Logging, etc.)
  3. Application (Use Cases, Services, Managers, Orchestrators, etc.)
  4. Domain (Entities, Domain-Level Validation, etc.)

I don't know if there is an upper-bound size limit on DLL sizes, but I have concerns about having the majority of the 5 million lines of code roughly separated between Application and Infrastructure.

With that said, does anyone have any diagrams showing more complex implementations of Clean Architecture?

I'm also aware we can have many flavors of Infrastructure projects. One for persistence, one for OS services, one for Network level services, etc., but the bulk of our logic is business-related. Is there way to separate our business concerns into multiple Projects/Components? Any diagrams of this would be much appreciated.

Below, is something we came up with, to create at least some separation between regular services and master-level services based on Jeff Bezos' Api Mandate. This at least separates several million lines of code by 2 projects instead of all being inside of one.

enter image description here

4
  • 1
    "It's running on .NET Framework which is no longer being supported.." wait thats still suppo... "..using WebForms" oooohhh
    – Ewan
    Commented Oct 22 at 18:59
  • 2
    If I were in your shoes, I would seek for an approach which allows to migrate to a different technology with rewriting as few lines of code as possible. Forget about the whole "Clean Architecture" hype - find something which is economically feasible, otherwise you will fail. See also joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i (and softwareengineering.stackexchange.com/q/6268).
    – Doc Brown
    Commented Oct 23 at 5:41
  • @DocBrown thank you for your feedback, I appreciate it. We are not rewriting from scratch, but are migrating to a new platform as .NET Framework is no longer supported, but that's not the biggest issue. We are using an older tech stack which uses WebForms which is tightly coupled to the backend. And we are now finding it difficult to find developers which know WebForms and the whole Page Life Cycle. So in short, we will be attempting to migrate to a modern tech stack with Angular on the front end, while keeping majority of business layer in tact.
    – Pavel
    Commented Oct 23 at 22:41
  • @Pavel: yes, you already wrote that. Your frontend technology is outdated, so you need to replace it. I would recommend to keep as much as you can from the existing backend, including its current structure, even if this might violate some CA ideas.
    – Doc Brown
    Commented Oct 24 at 6:05

2 Answers 2

3

I don't have actual project diagram I can share, but the ideas are fairly straight-forward and will scale.

One way to understand Clean is to re-drawn it using the more conventional layers (see below). Each of the black bounding boxes represents a layer. I've also called out dependencies separately. I have depicted the Entities and Use Cases as one layer - obviously you can separate them if you wish.

The "flow of control" diagram (in the Clean diagram) is basically saying that Layers can consume downwards e.g. technical components like the UI can consume application logic (not the other way around), and that application logic can consume externals like databases (not the other way around). The critical caveat being that you should use loose-coupling mechanisms like DI / Inversion of Control as appropriate (i.e. the "Interfaces Adaptors Layer" in Clean).

Interpretation of an example Clean architecture as conventional horizontal layers

Update: one important correction - the connectors show "consumption" (before I incorrectly had them labeled as "dependency").

  • E.g. your UI will typically 'consume' the domain layer / app logic, and might do so by calling it directly, which doesn't violate Clean's Dependency Rule; diagramically this is "down the layers".
  • Data access code is consumed by the app logic - in this diagram that's also "down the layers" but in the Clean context it's going in the reverse direction, so that consumption needs to be abstracted out so that the Dependency Rule isn't violated.

The other architectural style you can employ ideas from is Vertical Slice. Regardless, you just need to follow the classic high-cohesion / low-coupling principles.

You can then think about the potential packaging, deployment and tiering:

  • components in different layers are candidates for separate packaging.
  • components in different slices are candidates for separate packaging.

These options are not mutually exclusive, you can combine them in different ways - some of which may be dictated by the technology being used to implement a part of the architecture.

In this second diagram I have coloured the layers to show which of the Clean concepts they map to (Entities / Use cases, Interfaces & Adaptors, etc).

Same interpretation of Clean but coloured to show the different concepts of Clean

Update: response to comment about Components

Sorry if I was not clear - I was referring to components in a logical sense where "component" simply meant cohesive pieces of code, not a DLL specifically.

Thinking about how you want to logically structure the components of your system ties in with how they can then be packaged and deployed; how they will be reused; how you structure your .Net Projects and how the team(s) actually work on them.

I recall a massive project I worked on in 2010 where I think the project team had ~230 to 250 .Net projects across three solutions, where many projects were in at least 2 of those solutions... the amount of time it took to just open the IDE was poor, let alone compile. The team was not in a position to refactor the codebase at that stage.

Going back to your situation and Clean, taking Cleans "Enterprise Business Logic" as an example... Lets say you identify you have 20 areas/topics of functionality, which translates into 20 areas of logic - you can choose to have 20 namespaces (MyApp.MyLogic.Billing), put them in 1 project and have them compile into 1 DLL, or you could go the other way and have 20 projects and 20 DLLs.

Or (if it made sense) groupings of several logic areas into the same DLL. Lets say the areas of logic were of different complexity and size (and were correspondingly more likely to change) then you could have the big/complex logic in a single project per area, and smaller trivial ones grouped together AS LONG AS they were reasonably cohesive. E.g. simple finance logic separate from simple product management logic.

When designing the logic structure, project structure and eventual packaging for deployment and use, you'll need to consider a number of aspects (which you probably already are thinking of, but for the sake of a more complete answer), including:

  • How to ensure appropriate coupling and cohesion between different parts of the logic, and with the other parts of your system.
  • Size and complexity.
  • How likely they are to change.
  • The degree to which they are, or are likely, to be reused by other parts of the solution.
  • How many instances there will be at runtime, in how many different environments (is it one instance in a backend service, or more complicated than that?).
  • How easy it will be to modify the code.
  • How easy it will be to consume the code e.g. for UI and API developers to build their part of the solution on top of the logic.
  • How is the project team(s) likely to be structured; how many developers do you have, etc.

If all else is equal: the more likely it is that something will change (maybe because it is big, complex, is heavily reused, meets real world needs that are volatile, etc) then:

  • the more easy it needs to be to facilitate that change (e.g. easy to work on without impacting others, other parts of the code, test, etc)
  • and minimize the impacts of the change (e.g. ease of deployment, manage breaking changes, etc).

But that's getting into broader solution considerations such as which system qualities you need to prioritize, which is beyond the scope of this.

Code to Deployment

Based on your question, I spent some time yesterday thinking about how to portrait a Clean based architecture as logical components and then how that could translate into deployment - not what the actual packages were but just where the code needs to end up; from this sort of view you could start identifying actual deployment packages.

This first diagram (below) is basically the same as the first one at the top of my answer: an interpretation of Clean architecture as conventional horizontal layers, showing logical code and components:

Logical code / component architecture

This diagram (below) identifies which code is specific to an application and which is common / reused.

Mapping the logical components to eventual packaging

This diagram (below) shows where the code is eventually deployed into an application. This is NOT showing specific DLL's and deployment packages, merely where the logical code ends up in terms of which application it is deployed to.

Deployment view showing code reuse

7
  • Thank you Adrian. I have a question when you say, "components in different layers are...". After reading the Clean Architecture book and applying it to .NET environment, it seems that a Component is equivalent to a DLL which in turn is equivalent to a Project. A .NET solution can have multiple Projects (DLLs). With that said, I'm finding that each "Layer" is a "Component/Project". We have 5 million lines of mostly Use Cases (business logic). Is it possible to break this out into multiple projects/components/DLLs?
    – Pavel
    Commented Oct 24 at 16:34
  • 1
    hmmmm i think you might have gone wrong here with "application logic can consume externals like databases" and your diagram with domain "consuming" persistence
    – Ewan
    Commented Oct 24 at 17:37
  • Consumption isn't meant to imply a dependency; think Ports & Adaptors.
    – Adrian K
    Commented Oct 24 at 17:52
  • 1
    yeah its not impossible to be CA and also follow your diagrams, but I think you have to question when all your dependencies are inverted with interfaces are you really following the spirit of the idea?
    – Ewan
    Commented Oct 24 at 18:24
  • 1
    it seems like you are combining the domain and application layer, which makes it look odd, whereas I would have the domain layer as fundamental data structs, which are passed through all layers and the application layer pulling in various services (via interfaces) in order to implement the functionality. but with the diagrams only having the downward flow of dependency it makes it look different to the in-then-out flow noramlly associated with CA
    – Ewan
    Commented Oct 24 at 18:30
1

However, all the examples I came across online (GitHub, PluralSight, YouTube, Clean Architecture Book, etc.) are simple demos. They usually consist of 4 Projects:

Yes this is super annoying, everyone seems to think that CA == one project per layer, but it obviously can't be true.

Famous diagram

Here we have "Uncle Bob"s famous diagram, clearly you can't put your UI and DB in the same dll and have it make sense.

However, I haven't found a clear example. You have to dig into other Rob C Martin books to find that he thinks .net components are ddls and that small, many components are good and infer that the Devices, Web, Controllers etc are components to make the argument to people who think one project is all you need and don't understand interfaces.

My advice would be to go look at some of Microsoft own open source .net solutions. You will find millions of small projects per solution.

22
  • 1
    Exactly, I read his book several times to fully grasp this concept. He is indeed referring to DLLs or Projects when referring to components, when it comes to .NET environments. So with this in mind, all examples of Clean Architecture for .NET include just 4 project solutions.
    – Pavel
    Commented Oct 23 at 18:58
  • the eShopOnContainers app is a great stop: github.com/dotnet/eShop
    – VinArrow
    Commented Oct 24 at 13:11
  • mmmmm its got Ordering.Infrastructure and Ordering.API with an infrastructure folder. You are just best not to use layer names for projects
    – Ewan
    Commented Oct 24 at 17:32
  • @Pavel yeah I think he calls it out explicitly in "Clean Coding" I would have to check for the exact ref though.
    – Ewan
    Commented Oct 24 at 17:33
  • 1
    The annoying thing though isnt people with well structured static single exes carefully obeying all the dependency rules without using language features to do so. Its people who make a project per layer and say "Right now im doing CA!" regardless of how the code is structured otherwise
    – Ewan
    Commented Nov 4 at 14:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.