суббота, 23 июля 2016 г.

CQRS and F# SQLProvider

There are situations when a project has very complicated business logic and requires to display a lot of information to users. If it is not properly implemented and structured then some serious problems can appear. Usually people focus on domain and it is reflected on data storage organization which is usually not intended for presentation purposes. In practice the attempt to build presentation layer with domain focused storage organization can give some upsetting consequences:
1. dozens of joins in data queries when one such query occupies several tens lines of code – huge performance impact,
2. difficulties to modify such code – even people who wrote this code should spend time to recall how it works,
3. possibility to easy introduce bugs while modifying,
4. troubles with quick entry of new team members to existing projects due to excess code complication.
Also there can be attempts to reuse such queries for both domain logic and view representation – in many cases it will fall. I want to talk rather about how to avoid this kind of problems. The way is already known and it is called Command Query Responsibility Segregation (further — CQRS). I will not give attention to the theoretical side too much – there is a lot of information about this pattern in Internet. I want to tell about my practical experience and about how easy this pattern is implemented using the F# SQLProvider. Briefly, according to this pattern, all logic can be divided into two parts – commands and queries. In practice commands are related to domain actions and queries are related to presentation. It can be convenient to divide not only code by purposes, but data stores too: one store for domain and one store for presentation. However, it does not necessary. You can use your DBMS features such as views, indexed views to get the same result. In some cases you may even not think about data storage — the gain will be just from separation of domain logic from view logic – your code will become more clear — that all depends from your particular case. Of course, if you will maintain two storages, you should make efforts to synchronize data between domain and presentation storage. You will also have to keep synchronization aspect in mind when you should perform some support tasks or make some changes in database manually. However, from my practice such things are nothing comparing to harmful consequences described above. And now let’s consider the practical aspect. Actually, after domain logic separation from presentation logic, we consider our application as consisting from two parts which makes our initial task easier, because we can handle each of these parts almost independently and each of these parts has limited scope of responsibility. That means that every part will be simpler from the architecture point. I found very convenient to use F# SQLProvider especially for query side. In ORM’s like NHibernate you have to perform mappings between tables and classes and keep tracking to reflect changes in DB to mappings. F# SQL Provider works the different way. It always gives to you actual database schema representation which is checked on compile time. For example, if you change field name in some table and there are any queries using this field in project — the project will not compile. Also it should be mentioned that development speed significantly increases after using F# SQL Provider because you do not need to perform mappings and you always get actual DB representation through autocomplete!

You can contradict that powerful ORM’s allow to perform complex mappings to objects. But in our case the idea is to reduce the complexity: the presentation data storage should be prepared such way that interaction with it should be fast and easy. So in this case mappings functionality will be just redundant! Also better problem decomposition does matter too. We just develop the query side and think about the query side only. To emphasize this separation I even move query side in separate project. We do not touch the domain logic while work on presentation. Also this is convenient when you are still afraid use F# for entire project so you can just implement query side using it. Here is the code examples. It is pretty simple, but it should be simple – this is the main idea of my post. To organize the query side we need just describe the view models like this.
[<CLIMutable>]
type ReportModel =
    {
        ReportId : int
        TaskId : int
        Header : string
        Content : string
        AuthorName : string
        Date: DateTime
    }
and create queries like this
open FSharp.Data.Sql
open DataProvider
open System
 
type ReportPresentationService() =
     member this.GetNewestReports(from: int, reportsCount: int) =
        let db = DataProvider.getDataContext()
        let targetQuery = 
            query { for report in db.Public.VReports do 
                    skip from
                    take reportsCount
                    select { ReportId = report.ReportId; Header = report.Header; Content = report.Description; 
                             Date = report.CreationDate; AuthorName = report.Login; TaskId = report.TaskId }}
        let result = targetQuery |> Seq.head
        result
In my example there is a view – v_reports from which I query the data. For my particular case it is enough. Note that the ReportModel type has CLIMutable attribute. That is because I use it in ASP.NET MVC and default ASP.NET MVC model binder requires models to have mutable properties. That’s all – the presentation layer came out very thin and simple. It contains only logic that responsible for presentation. It is easy to read and to make changes.