I am putting together the architecture of a fairly large project and it is basically the following:
Main solution : it has 10 projects (8 class library, WebAPI and MVC)
Solution N (mvc and web api project) (The number of these solutions will depend on the number of clients who purchase the service)
All the logic, including that of the N solutions, is in the main solution, which is the idea that the N solutions refer to the DLLs of the main solution. Is this correct?
The problem I find with this is that if a client needs a specific requirement, what should I do? Add that requirement to the main solution or create a separate project (a dll) within solution N?
Cheers
This is one of the big questions of how to "organize" our "artifacts" ... which is the elixir of architects ;) There are many approaches and for each one, characteristics of the project as well as the "environment" must be evaluated ( project team, degree of volatility of requirements, how decoupled the components or modules are, etc) As @jasilva told you, as you progress in the project you can "explore these architectures" so that it is not an impediment at the beginning or worse that everything be delayed by having an "oversized" architecture for the first baby steps of a project... as they will tell you, you have to walk! (and so it is) but you can start taking some "practical improvements" from the beginning, which is what it is after all.
Well... we all start with projects "just for a client"! and they were growing to become some Software Packages to customize it by client or even as SaaS (Multi-Tenant). Where at each step you have to "refactor what is created and assembled" so that it can support the new customization requirements and request of several clients to the same module for example
Let's start... although a couple of years ago the only way to share was "referencing" today you have practical improvements with component packages (NuGet of the day you use it) and for example with DI (Dependency Injection) you can do the same without so much coupling , which after all is what we want to achieve in each "module"
recommendations
Then you can have with the "modules" part what I commented above, with respect to CORE
Well... the recommendations
RECOMMENDATION 1: Modify behavior (plugins) with MEF
If I had to recommend something to you, it would be... MEF -Managed Extensibility Framework the idea is simple "to be able to inject modules/plugins just by copying or uploading an assembly" (you could even have a module server to add to your "core project" Like this you can use MEF in MVC
RECOMMENDATION 2: Separate packages (modules) in internal NuGet
Some components you could make "modular" and completely decouple them from your Core. To make them Testable above all and reusable... to do this you can create it in separate projects and alone and then share them at an enterprise level in your own package repository ( an internal NuGet ).
Well they are ideas and recommendations,
Links that can help or guide you
This seems like a common dependency problem, what you want to do is "good", as you want to make core that has all the main logic, of a product, that looks like it will be sold to several clients as their own, but each one will have things unique.
This would leave you with an architecture similar to this
Where in main is all the common logic is in MAIN, and each client has a small piece of logic that is different from all the others.
Later in the project, each client will ask you for things that are only for him and you would have something like this
But you must keep in mind that MAIN will never be modified by the request of a client, when everyone needs something, it would be better to add it to main and send it to be called.
with the above
copy/paste
functionality that will be almost impossible to maintainAdd it in its own logic, with a condition, for example, a new query to extract the year's sales separated by fortnights , none of the other clients have requested it, but it could be that they will need it in the future, what's next? add functionality in MAIN and only reference it in client logic.
On the contrary, if a client asks to change the x80 request that says that it
consultaEjemplo
returnsA
it, that for all clients it is the same and it is in MAIN, but he wants it to return nowAB
, it must be overwritten in the client logic, without affecting MAIN .Now, on the subject of how to organize the solutions in visual studio, I think it is a bit more subjective, since the one that each person likes the most should be used, for example:
Advantage:
Disadvantages:
Advantage:
Disadvantages:
Advantage:
Disadvantages:
So as you can see, it depends a lot on how you organize yourself, on the security methods you want to have, or the ease of configuring environments, it is most likely that I have missed some other advantage or disadvantage, but I am sure a fellow OS in Spanish, it will help us.
You will always find a thousand different ways to approach this problem, I share with you the result of my personal experiences, some in agreement with other exposed alternatives and others in total disagreement.
In large corporate projects, especially in multi -company ones, you will always find this scenario.
Typically, customers demand customizations according to their needs and this is where physical, logical and process architecture decisions are of vital importance.
My recommended solution is listed below as
Multi-tenant application, and the world of software as a service**
For now here are my notes.
Multiple projects or solutions, 1 for each client.
It is the worst possible solution, the more projects the solution has, the slower the loading and compilation process will be. This alternative seems to be good but it is really creating a lot of collateral problems especially code redundancy . Over time it will be inevitable that this will happen and there will be no methodology or process that will prevent it.
You can try to keep some core projects that are 'untouchable' and only have a few customizable for each client, but as the solution grows you will see how, due to very specific needs of a specific client, you will begin to have core code leaks to migrate them to each client.
Solutions through design patterns and dependency injection
This approximation is a little better, a good architecture and implementation of design patterns can decouple your code a lot to get to have a highly customizable solution where by means of configuration you can establish the resolution of object instances that have the logic determined by each client. .
You will not need to open multiple projects but rather create custom classes according to the needs of each client, and then in the installation process for each of them modify the configuration of the application so that each client uses the objects that are relevant.
The catch with this methodology is that your app tends to get bigger and messier over time. Each new client may require endless configurations for dependency injection and in the end, despite the high technical value of your application, the level of entropy and maintenance effort will be high, this last part in particular is the typical scenario of an application with a high technical value but a great complexity in the code which will make it difficult to maintain the application during its life cycle.
Versioning per client
You can create a new branch of the application for each client, in this case you would have a single solution and set of projects, but every time you have to make a change outside of the standard, you create a new branch of the application.
This will give you the flexibility to apply changes or new features only to a certain client without creating a set of different solutions or projects (although they will be in the long run).
In this way you must maintain a main or core branch, with the application in its standard version and ensure that each change is replicated to all branches and then customized in each branch as necessary.
In any case, although you get rid of projects with great complexity due to the exaggerated use of patterns and dependency injection, and compiler problems by having solutions with multiple projects, in the end you will have a fairly complex issue to manage with the theme of versions opening the way to many errors and 'strange' differences between one branch and another.
Despite this, it is one of the most widely adopted solutions by software houses.
The plugins / MEF
It is an excellent alternative, which also gives a lot of flexibility in the middle of a widely tested framework.
However I wouldn't recommend it as much for LOBs, although it works. Because given the number of possible changes, the complexity of the application will overflow and the number of plugins could bring you some performance complications. Just take a look at how Visual Studio behaves when you have a lot of plug-ins or extensions installed.
Multitenant application, and the world of software as a service
For modern times this is my best option and by far! If your application is flatly multi-client, you should think about why you have to install your application on each client if you can probably offer it as a service in the cloud, reaching more clients and with considerably better implementation and maintenance costs.
The point is that even if you don't want/can/know how to sell your application as a cloud service, this same multi-tenant architecture will give you huge benefits when building and maintaining your code base.
What you have to do is build the application as if, in effect, multiple clients connected to the same instance.
This implies that your application must behave in different ways for each client, but since it knows that situation from the beginning, such customization is achieved by configuration parameters interpreted from the code, not asking why the client is connected but what configuration features are available. established for this specific customer.
So in your code you would have something like this