03 Solution design


Our manifesto dictates we adhere to the following key criteria:

  1. Easy
  2. Open
  3. Modular
  4. Supportable
  5. Robust
  6. Performing


Easy

To be easy, our solution must be:

  1. concise - code must do a single thing, and it must be obvious what it does
  2. minimal - it should only have code that is necessary
  3. implement a full stack - after a (simple) install, it should contain everything necessary to run a website (content management bits, content delivery bits, fully featured website)
  4. utilize the underlaying frameworks - use Java / Spring or Microsoft libraries where possible


Open

To be open, our solution must:

  1. Be open source
  2. Utilize dependency injection - every single component in the framework must be coded to an interface, and must be injectable through the Inversion of Control pattern. We must be able to replace every single class in the framework with minimal overhead
    1. We may need to define which IoC frameworks we support on java (Spring, Java EE) & dotnet (Unity, Autofac, Ninject, etc)
    2. We have to get rid of static class references in the framework code layers - all these must be run through the IoC container


Modular

If a framework is open, it is modular by nature. Supporting the concept of modules requires us to define what a module does and how to install it. Tough nut to crack; a module could contain a variety of CME (templating, event system, resolver, UI extension) and CDE components (server side, client side, IoC parts). CDE is fairly simple to do using maven / nuget, but since Tridion does not actually support a "module" in CME the best lead there is alchemy (which only supports partials). Perhaps a combo of maven/nuget + custom powershell on CME?


Supportable


Robust

  • Automated functional testing where possible
  • Automated performance testing where possible (for both "grade your infrastructure" and "regression the code")


Performing

We run on a variety of patterns, including both direct API (up to 2013) as well as webservice based (web 8+) patterns. We need to have a caching layer that allows to utilize the following features:

  • Eternal caching, where cache expires based on publishing actions.
    • A page should only be removed from the cache when it is published or the cache decides it isn't optimal
    • An editor should, when publishing an item, be able to see the new version of the item immediately. Any time based caching should be taken care of by an external output cache
  • Caching items that depend on other items
    • Assume i have a system page that store custom information about structure about the blueprint; i want to store any derivate custom model of this page with a dependency to the page itself - when the page is published, the model is flushed so it can regenerate
  • Cache items based on several other items
    • Models exist that are based on multiple pages and components (such as: componentlink results). We should support this - if one dependency (out of several) is published, the item should be removed
  • Correct multi-threaded behaviour when calling the cache in our framework code. We have to use synchronization carefully and correctly - that both includes spawning threads where it makes sense (such as DCP resolving for a page) but also blocking threads where necessary (such as where we do a backend call to retrieve a cacheable object).


(For the record, the current DD4T java cache does this)

Especially in environments where there is significant overhead in doing lookups, having a correctly updating dependency cache is the only solution to having a performing high traffic website.


High level design

This is how both solutions are currently roughly architected. DXA lacks the JMS updates to its cache, but the general layering is correct. I would propose that, going forward, we would see that:

  • Source layer. Basic OOTB SDL web 8
  • Model layer. Should not require customers to change anything; intended extensibility is mostly in the deserializer area to enable custom strongly typed models and the processor pattern to inject code into the factories. All classes in this layer must utilize dependency injection in order to allow full customization where necessary and to support backwards compatibility (such as running multiple dd4t versions at the same time)
  • Controller layer. Mostly example code, expect customers to change it. Navigation, publication details, XPM extensions, smart target etc all need to get hooked up into this layer. Attempts to standardize will probably fail at complex implementations. Dependency injection is how controller access the factory and cache objects from the model layer.
  • View layer. Example code, every customer will run with custom views. View support could be standardized, allowing both pre- and post- rendering of componentviews vs pageviews, as well as supporting whatever view languages necessary. View support should utilize dependency injection in order for customers to use whatever view languages they want.