Introduction to Xperience MVC/Core Architectural Best Practices for Larger Scale Solutions
This article will introduce best practices for larger scale Xperience projects, both in MVC 5 and .NET Core. It will touch on different solution architectural setups from a high-level perspective and explain some advantages and disadvantages to each one. It will demonstrate proper separation of concerns for these architectures and give a glimpse into the benefit of using patterns. It will show high-level proofs of concepts to demonstrate how this can be achieved with Xperience, rather than going into detailed examples. When you would like to build upon these sample pieces, we have some fantastic training modules dedicated to this, which goes into full step-by-step implementation. There is also a fully built-out solution, the Medio Clinic site, which we would recommend as the next step The Kentico Xperience 13 training website.
Evaluating and choosing your best solution architecture in Xperience:
When deciding on a solution architecture for your project, you need to evaluate and determine what is most important in relation to your goals, so that your application can be built around them. Unfortunately, perfection is not always realistic, so prioritizing your goals can be really beneficial in the long run. Let us look at some examples of goals that are important in most projects:
Project completion time
- How long it takes to get the project to a finished state
- Increases with more layers, more projects
Code base maintainability
- How easy it is to modify or extend
- Degree of difficulty and risk when adding new features
- Easier with more layers/projects that are added, but this will increase the amount of time for project completion.
Adaptability to change
- How well your application can handle new tech and/or future business requirement changes
- Can also be closely related to quantity of layers
- How easily your project code can be tested
- Easier with more layers/projects
New employees ease of adaptation
- How well new recruits can get up to speed with the architecture
- Decreases with added layers/projects added
The separation of concerns principle is something we always strive to attain. In the most basic All-in-one application, all the logic for the entire app is contained in a single project. In this case, separation of concerns is achieved through the use of folders i.e. models, views, controllers, data, and services. With the increase in complexity of applications as they grow larger and larger, it becomes increasingly difficult to uphold this principle, as your folders start to bloat with more and more files. This is where layered architecture comes into play. In a layered architecture, separation of concerns is attained by organizing the code into separate projects related to specific functions, or “layers,” so that common low-level functionality can be reused throughout the application. As stated by the Microsoft docs on layers, “Layers (and encapsulation) make it much easier to replace functionality within the application. For example, an application might initially use its own SQL Server database for persistence, but later could choose to use a cloud-based persistence strategy, or one behind a web API. If the application has properly encapsulated its persistence implementation within a logical layer, that SQL Server-specific layer could be replaced by a new one implementing the same public interface”. More about layers.
That’s all well and good, but let’s actually involve Xperience— check out the example below!
In the above figure, we see that we have an all-in-one single layer structure on the left, and an example of multi-layer, or ‘N-layer’ architecture in the middle and on the right.
As briefly shown above, we are alleviating some of the responsibilities from the single layer project and moving them into separate projects to increase our maintainability, and application adaptability to change, among other benefits. In the short term, this might elongate the speed of development of the application as a whole, but the many benefits outweigh the increased completion time. Let’s attempt to visualize this and take a look at this comparison:
The above figure roughly illustrates the original goals discussed at the start of this article. By using a simple, one-layer, all-in-one application, you can get everything up and running pretty quickly. As your project grows, however, we sacrifice a number of other goals. Adding more layers of abstraction and achieving separation of concerns through these means will increase application adaptability to changes and code maintainability, among other things, while sacrificing some project completion time. It should be noted that while adding more layers of abstraction will help to alleviate bloat in increasingly complex projects, it doesn’t always make sense to add an ever increasing amount of layers. If you go “layer happy” so to speak without there being much complexity, you may hit the opposite extreme where indirection becomes the result. Layers are very useful and should be added when the complexity of the project grows and your folders start to bloat.
In Fig 1 we saw the expansion from single layer to N-layer architecture, but what are these projects doing in this Xperience solution and how is it helping?
Pulling out data access and business logic and placing them in their own projects (Business and Xperience Adapter in our case) while leaving the MedioClinic project to handle the user interface side of things really cleans up the code functionality. The MedioClinic and Business projects are at the top of the dependency chain and utilize the codebase of the XperienceAdapter, a lower-level project which provides access to the Xperience APIs.
As seen in the above figure, we have the Xperience projects set up in a way applicable to the N-layer structure that nails down solid, the separation of concerns principle in larger projects.
Something worth taking a closer look at is how patterns are helping us in these projects, by adding an additional layer of abstraction. On our Xperience MedioClinic training site, we are using something called the Repository Pattern. For example, you can see the DoctorRepository, which prevents the higher-level projects from needing to use the Xperience APIs to retrieve pages and filter them by the doctor type” (You can read more about repository patterns) This repository layer will act as a gateway between our Business project and our XperienceAdapter project. The purpose of adding something like a Repository Layer is to help with the following:
DRY principle, i.e. cut down on using the same pieces of code redundantly
Greater Testability through a decoupled code base
Custom Data Formats, the platform-level data layer rarely allows for strongly-typed joins of data. Xperience is no exception.
Additionally, it should also be noted that utilizing tests on the business and or data layer of your solutions will be quite useful and will provide further value by helping with maintenance.
Putting it all together
Hopefully going through this article has given you some ideas on how you might make use of solution architecture best practices and apply them to your enterprise Xperience solutions.
In summary, we have gone through:
- Identifying your project goals
- single and multi-layer architectures, the benefits and drawbacks to both, and how they relate to your goals and separation of concerns
- Demonstrating a glimpse of the MedioClinic training site and visualizing how the solution architecture can be applied to Xperience applications in a best practice manner
- Using a Repository layer to achieve things like greater testability and extensibility
If and when you would like to expand upon these ideas, the training modules await, with detailed setup and best practice examples/implementations.Xperience training