Software Architecture - 8Bit - 8Bit Mon, 19 Nov 2018 03:48:17 +0100 sr-yu Building customizable applications in .Net





At this level, the required solution actually depends on the application architecture. If the architecture contains just what I described at the beginning, a homogenous “vanilla” application and only one customizing plug-in per client, things get much simpler. For example, in this case it is possible to use SQL scripts to maintain the database schema, just develop a mechanism that remembers what scripts it already executed so that they don’t repeat. This is possible because the scripts will always be run in their chronological order. Contrast this with having several modules with different features: if an existing client wants to add a module to his existing application, you would need to upgrade the database by running the scripts from the module. But the database is already up-to-date for current configuration and the scripts from the new module may be written years ago. For this scenario you’d probably need a smarter solution, and I’m not sure that current migration frameworks can support it… Which sidetracks us to one of the most important things in modularity: integration. Most of the “usual” frameworks employed in applications don’t fully support modularity. You have either to customize and integrate them into your application or write your own equivalents. Which presents a kind of continuity of approach: if you want to develop a customizable application, you have to customize other people’s code.

What about the data layer? Once again, many things depend on the rules you establish. If you prohibit the higher level modules from deleting/renaming structures used by lower modules (which, I suppose, is common sense), you will be able to use SQL queries when needed – and given that SQL is unavoidable for complex queries, they most certainly will be. In this respect, SQL actually supports modularity because you can write a query using tables and columns from the base module and it won’t care if there are other structures added to them in the customization process. C# classes aren’t like that, but C# interfaces are.

For other things – like simple CRUD editing of data, an ORM is the logical choice. There are many ways in which you can add modularity to an ORM – and it seems to me none of those can be done without customizing the ORM. The route we took is to use dynamic ORM mapping to replace basic types (contained in the vanilla module) with customized ones (present in the client-specific customization module). This is possible only if the module hierarchy is simple – that is, there’s single inheritance between basic and customized module classes. If two or more different modules wanted to add something to the same data access class, a different method would need to be employed, and that would probably mean using either dynamically generated classes (reflection emit or code generation) or .Net 4’s dynamic objects.

One thing an ORM allows you to do is customize the queries themselves since they are not text-only but represented by a tree-like object structure. You could provide extension points to allow the derived modules to access this structure and modify your SELECTs or JOINs or WHEREs… With LINQ it would probably need to be done by building the query in stages and calling extension methods for each stage because a LINQ query can only be modified by making a different copy of itself. Other ORMS may prove to be more flexible – for example, modifying a NHibernate QueryOver/Criteria query is absolutely trivial since it allows direct modification of the expression structure.

One thing that using LINQ may offer is automatic integration with smarter UI controls: there are some third-party controls that understand LINQ queries and can accept them as a data source. They then modify them to perform server-side paging (with sorting and filtering) in order to retrieve just the data needed for display… In that case, all the customizations done on the data layer directly carry through to the interface.

For this and other reasons, my company chose to ignore the recommendation of not using data access classes in the business logic or interface layers. If you add a customer-specific field to an existing table, you need to piggy-back it to the appropriate data layer class and it will be transported through the bowels of business logic right to your special overridden method where you can use it. It also goes straight to the CRUD UI and you can get away with just adding a control for this field to the existing form and not changing anything else.

That part sounds deceptively easy - “can you just add another field for me to the existing form, please?” Visual Studio 2002 supported derived controls which could have been used for this, but Microsoft was incapable of getting this feature to work so they simply abandoned it. For this, WPF is somewhat more suitable because it separates visual from logical control structure so that theoretically you can add a control to the form and then have a UI designer person go over it and make sure everything is in place. But, WPF is also good because it’s layout logic is dictated from the inside out – that is, everything is laid out to suit the content while in WinForms the content gets the space allowed it by its parents. So, if you use WinForms you have to get a smart layout control – and customize it. I’m under the impression that the whole WinForms designer should be replaced by something less verbose, for example some kind of a fluent interface. There would have to be an intelligent layout engine underneath it so that it can get everything looking right. But, once you get that (yes I know, this also sounds simple but it should be possible to implement some basic logic) a whole world of opportunities opens, because then we can leave it to the engine to actually choose which control to display for which field, which validation logic to attach to it etc. A fluent UI code would also be much easier to merge in your versioning system than the dreaded *.Designer.cs files.

This is probably enough to illustrate the scope and type of the subject. Since it’s an ongoing research I allowed myself to mention some solutions we employed and some we hope to employ. There’s a lot of other subjects like validation, business rules, data models that support customization etc. I will be working on those and posting my findings here, and these future posts will be more focused because each will be more practical and cover a single topic.

]]> (Boris Drajer) Software Architecture Sun, 22 Sep 2013 11:11:34 +0200
Model-Controller pattern for business rules

The model-view-controller (MVC) pattern has an interesting, let’s call it sub-pattern, that could be more broadly used. The basic purpose of MVC is to “clean up” the data (model) and interface (view) by delegating all the in-between “dirty” logic to the controller. The controller is aware of both the data and the interface and knows how to handle both: it controls what is happening in them, but from the outside. The controller, if written correctly, can be reused for multiple types of model or view. If we go a step further, we could program multiple controllers that know how to handle different aspects of the functionality: in this way we very much get add-ons that we can attach onto non-intelligent components and make them smarter. By choosing which controllers we attach, we can customize the behaviour of our application. And because the controller is made to work “from the outside” it is isolated from the internal implementation of the components: this could make it instantly reusable.

But it could be interesting to generalize the “add-on” controller pattern and make it work in other situations as well. One interesting area of application could be controlling data: if you use an Object-relational manager (ORM) to read your data (and if you don’t, you should), you already have your data in the perfect form for this - that is, as objects. Likewise if you use a traditional data-access layer and then create business entities as object-oriented structures. Usually, these classes contain much of the business logic inside and this is quite natural to do because business logic represents the behaviour of the data. But it’s not good for reusability: whether you combine the data access and business entities or implement them separately, the business logic is tightly coupled with data/hardcoded inside data so it’s not easy to customize. It would be nice if we could externalize at least some parts of it, but keep it as close to data as possible. Even better would be if we could split the logic and implement different aspects as different components.

If we attached controller objects to our data, they could take the responsibility of providing its behaviour. We could have different controller types for different types of behaviour (status changes, automatic calculations etc.), and if we instantiate them using some kind of configuration engine (or dependency injection framework), they will be easy to replace and thus make your application highly customizable.

Of course, these “data controllers” sound similar to what rules engines do, only more lightweight. But how much of an overhead would they add? As always, it depends on what we do, but I would say not too much. They would contain the code we already have, with probably one layer of isolation because it would be split into distinct classes. Would the instantiated rules waste memory? Probably some: but when you consider that the ORM instantiates each record as an object and has a complex infrastructure for tracking its changes; that for each data binding there is a couple of objects created in the interface; that there can possibly be a control (which is quite a large object) bound to each field… It seems that it shouldn’t make a big difference.

The most sensitive bit is collections: there we can have hundreds of records with one control (a data grid) bound to them. In this case, the overhead of the rules engine could be significant compared to the overhead of the interface – but not in comparison to ORM overhead. Again, this depends on how we implement the rules: the rule could be optimized to utilize a single instance for the whole collection – this can be done using an IBindingList implementation where the collection transmits events for everything happening inside it… Of course, here it is the collection which incurs the overhead, but let’s say we would use it anyway for data binding purposes.

Obviously, there’s a lot of technical issues here. This is partly because the base framework doesn’t have built-in support for what we need. But, it is to be expected that having an ORM (which can be interrogated for data structures and from which we can receive notifications when data is loaded/saved) generally helps.

Of course, I’m still talking hypothetically here: but I’ve already made a couple of small steps in the direction of having a living prototype (in fact, I’m testing an minimal working something as we – uhm, speak). More on that in another post.

]]> (Boris Drajer) Software Architecture Tue, 31 Mar 2009 19:26:20 +0200