Business rules

Build a Business Rules system in c-charp. Pass or not to pass. Below is an image that descibes rules. If a rule has a match, continue to next rule until we meet the expected result.

Introduction, background

When I was started at a bank in Norway, I was left a lone in a huge project where I needed to take care of the client register. At a first look, it looked complete, but the problem started when I was diving deeper into the code. Such as functions in functions that didn't end anywhere. At least not to be readble. I needed to develop most of the code in a new more Solid, and Clean code way.

Business rules

I started of by search the internet for such a system, but not a single one meet the requirements for my need. I needed something new. The main thought, was to create each rule as a function, with the ability to combine these when I run it.

It's running each item in a list thru these rules, it returns back one list of valid items and one list of not passed item. By combining the rules for a specific need(Rules) we get a list of Valid(passed) items. A rule just deside if it has a match. See code below.

And Yeah, now we actually have a named rule-system containing our Business Rules. It's easy to manage new rules and change the order and the expected result as we like, rather than before where we needed to go to a bunch of functions to achieve the result. It was also hard to change.

Future

In the future I think that I will change the rules to only apply to one item, rather then 'create a list of results'. Then it should become even more easy to adjust.

public static partial class RuleProcessor
{
        //Print status colored
        static Action<string> P = (s) => { 
          Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(s); };
        static Action<string> F = (s) => { 
          Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(s); };
        
        static Dictionary<RequestType, List<RegisterEvent>> Events = 
            new Dictionary<RequestType, List<RegisterEvent>>();

        public static void Process(List<RegisterEvent> items)
        {
            items.ForEach(c=> ProcessItem(c));
            PrintDict();
        }


        private static void ProcessItem(RegisterEvent item)
        {
            // PreRun all Rules for the Event
            var validateIsBank = ValidateSource(item);
            var validateIsActive = ValidateStatus(item);
            var validateInsuranceType = IsInsuranceType(item);


            /* 
             * Now we can group these rules to meet a specific requirement.
             * Group several rules to match a specific item.
             * What we want to achieve, get's more clear now.
             */
             var ShouldPassActiveAndIsBank =
                validateIsBank
                .And(validateIsActive);

             /*
             * The name "ShouldPassActiveAndIsBank" can later on, 
             * be used to run the event in a specific function 
             * or store the event in a table in a database. 
             * We now know what todo with this item.
             * 
             * The image(schema) describes what todo with an item that reaches this level.  
             */

            if (ShouldPassActiveAndIsBank.PassedItem){
                AddToDict(RequestType.IsActiveAndIsBank, item);
            }
            else {
                var ShouldBeInsuranceType = validateInsuranceType;

                if (ShouldBeInsuranceType.PassedItem)
                    AddToDict(RequestType.IsInsurance, item);
                else
                    AddToDict(RequestType.UnKnownType, item);
            }
        }

        #region Helpers

        private static void PrintDict()
        {
            foreach(var key in Events.Keys)
            {
                var list = Events[key];
                foreach (var evt in list)
                    if(key==RequestType.UnKnownType)
                        F($"Unknown type: {evt.Name}");
                    else
                        P($"Item found: {key} : {evt.Name}");
            }
        }

        private static void AddToDict(RequestType key, RegisterEvent item)
        {
            var items = new List<RegisterEvent>();

            if (!Events.ContainsKey(key)) {
                items.Add(item);
                Events.Add(key, items);
            }
            else
            {
                Events.TryGetValue(key, out items);
                items.Add(item);
            }
        }
        #endregion
    }

Created by Bootproject editor on 2019-10-27


  • multi

    About

    The Swede(me), Rickard Magnusson a Senior Software Engineer, currently employeed as a freelance consultant in Norway.

  • Legal

    Bootproject.se and Footer.se is property of Bootproject and may be used under (MIT)licence . See project on Bitbucket

  • Logo Contact

    Email: bootproject@icloud.com

(©) Copyright www.bootproject.no 2020