Grassland Component: Configuration System

Let’s dive into more technical discussion as well as coding to have more understanding on how Grassland works.

A good application or system often than not have configuration, whether to configure certain behavior, sms gateway, colors and many other things.

NOTE: The example that we usually give is Desktop-based Application, however, generally it is applicable to Web-based system as well.

Grassland is designed to take care of managing, setting, and distribution of configuration. Yes, distribution of configuration in Server-Client environment. In Grassland Architecture Design, we defined Configuration, as something stored in database or persists in other form e.g. temporary file and it is subjected to be distributed to client application. These configurations are Application Level Configuration.

Please do not confuse with System Settings or Config File. Those are system-level settings like Server IP, or configure which modules to be initialized.

So what is the big deal with Configuration? Like the following should do it right?

    public class Configuration
    {
        //constant
        public const int NumberOfRetry1 = 5;

        //static
        public static int NumberOfRetry2 { get; set; }
        public static int NumberOfRetry3 = 3;

        //using application settings
        public int NumberOfRetry4
        {
            get
            {
                return Settings.Default.NumberOfRetry4;
            }
        }

        //string
        public const string NumberOfRetry5 = "NumberOfRetry5";
        
        public void GetNumberOfRetry5()
        {
            //then get something from the database using the const
            var configHere = Database.GetConfiguration(NumberOfRetry5);
        }

        //string with hierarchy
        public const string RetrieveProductNumberOfRetry6 = "RetrieveProduct.NumberOfRetry6";
        public void GetNumberOfRetry6()
        {
            //then get something from the database using the const
            var configHere = Database.GetConfiguration(NumberOfRetry6);
        }
    }

NumberOfRetry1: Need recompile to change
NumberOfRetry2: Need every start of the program, likely need recompile
NumberOfRetry3: Need recompile to change
NumberOfRetry4: Using Application Settings, seems good but how to distribute it to client? Need to persist into database.
NumberOfRetry5: No hierarchy, hard to manage configurations when they getting more.
NumberOfRetry6: Seems good, can build class around to group configuration together. A lot of repetitive to have additional configuration. Inheritance? and configuration value type?

Grassland is designed to be scalable, versatile. Those examples above may only good for small application, but not appopriatae for big or huge enterprise application. Hence those does not fit our purpose. Simply, we need something more powerful yet flexible. Here are our proposal:
1. Easy to use and create additional settings
2. Able to trace the configuration easily (VS, just press Shift + F12, get all the usage)
3. Distribution of these configuration from server to client
4. Client can override selected configurations
5. Inheritance
6. Default value when nothing is set
7. Viewable in database
8. No constant field, no static field, can be testable
9. Type Safe for configuration value
and the list can grow further.

Most importantly, Grassland System is a domain ignorant system, a clay. System must able to handle configuration from module that might only be known at run time. This is a major challenge in grassland design in every single component.

Here is what we come out in the end:

public class ConfigurationSystemExample
    {
        //inject configuration manager
        [Dependency]
        public IConfigurationManager ConfigurationManager { get; set; }

        public void GetConfiguration()
        {
            //specify the configuration set
            var result = ConfigurationManager.Set<SampleConfiguration>()
                //retrieve the value
                .Get(x => x.Name);

            //for nested value
            var result2 = ConfigurationManager.Set<SampleConfiguration>()
                .Get(x => x.ProductCollection.PageSize);

            //to configure
            ConfigurationManager.Set<SampleConfiguration>()
                //with property type information from reference class
                .Configure(x => x.ProductCollection.NumberOfRetry, 4);
        }
    }

    public class SampleConfiguration
    {
        public string Name { get; set; }
        public int MaximumPages { get; set; }

        //inheritance, with hierarchy as well
        public TemplateConfig ProductCollection { get; set; }
        public TemplateConfig CustomerCollection { get; set; }
    }

    public class TemplateConfig
    {
        [LocalConfiguration]
        //each client application override server's distributed configuration by setting the value,
        //else it will return back server's value
        public int NumberOfRetry { get; set; }
        
        [DefaultConfiguration("20")]
        //default value when it is not configured
        public int PageSize { get; set; }
    }

This how grassland’s design works and its design philosophy. We want to have something simple yet powerful that can work most of the time.
Creating configuration can be simple as create plain class, on top of that you get benefit of inheritance and hierarchical information and every configurable value is type safe.
For beginner, only 2 interfaces and 2 attributes need be learnt: retrieve and configure; default value and local (if they are building distributed software)

If using Grassland desktop-based, to make things even better. Grassland System automatically generates to configuration user interface.

    //just put attribute below to opt-in for generation
    [GrasslandConfigurations]
    public class CRMConfiguration
    {
        [ConfigurationRequireRestart]
        public bool Enable { get; set; }
        public ProductCategoryConfiguration ProductCategory { get; set; }
        public BarcodeConfiguration Barcode { get; set; }
        public InventoryConfiguration Inventory { get; set; }
        public DeliveringConfiguration Delivering { get; set; }
        public CreditNoteConfiguration CreditNote { get; set; }
        public InvoicingConfiguration Invoicing { get; set; }
        public PricingConfiguration Pricing { get; set; }
        public SalesPersonConfiguration SalesPerson { get; set; }
        public CustomerConfiguration Customer { get; set; }
        public RetailConfiguration Retail { get; set; }
        public CashBillConfiguration CashBill { get; set; }
        public QuotationConfiguration Quotation { get; set; }
        public SalesOrderConfiguration SalesOrder { get; set; }
        public ReceiptConfiguration Receipt { get; set; }
        public ReportConfiguration Report { get; set; }
    }
facebooktwittergoogle_plusredditpinterestlinkedinmail

Leave a Reply