[{"data":1,"prerenderedAt":3149},["ShallowReactive",2],{"blog-guide-to-rule-engines":3,"blog-all-for-related":2693},{"id":4,"title":5,"author":6,"body":7,"cardAlt":5,"categories":2679,"description":2681,"draft":2682,"extension":2683,"headerImage":2684,"keywords":2685,"meta":2686,"name":2687,"navigation":302,"path":2688,"seo":2689,"series":6,"stem":2690,"updated":6,"year":2691,"__hash__":2692},"blog\u002Fblog\u002Fguide-to-rule-engines.md","Guide to Rule Engines",null,{"type":8,"value":9,"toc":2666},"minimark",[10,22,25,28,33,41,44,112,115,121,134,140,143,150,153,156,158,162,169,174,179,188,193,200,205,208,215,217,221,232,235,277,284,369,372,411,417,1171,1174,1185,1188,1627,1634,1651,1656,1766,1769,1775,2479,2482,2536,2546,2548,2552,2578,2582,2585,2587,2591,2607,2611,2627,2645,2648,2657,2662],[11,12,13,14,21],"p",{},"If you've been working on a product or business, a recurring scenario that happens is the changing business requirements. Developers build a solution based on set of conditions. Over time these logical conditions might change due to changing business needs or other external market factors. ",[15,16,20],"a",{"href":17,"rel":18},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FBusiness_rules_engine",[19],"nofollow","Rule engines"," are a powerful way to solve such problems.",[11,23,24],{},"In this article, you'll learn about the rule engines and how can this system be leveraged to solve complicated business problems in a scalable and maintainable way.",[26,27],"hr",{},[29,30,32],"h2",{"id":31},"what-is-a-rule-engine","What is a Rule Engine?",[11,34,35,36,40],{},"You can think of rule engines as a way of business logic and conditions that helps in growing your business over time. In very layman terms, these could be a bunch of ",[37,38,39],"strong",{},"if-else conditions closely associated with business attributes"," that can vary and grow over time. So these are set of rules that check a condition and execute a action based on the result.",[11,42,43],{},"Each rule follows a basic structure",[45,46,51],"pre",{"className":47,"code":48,"language":49,"meta":50,"style":50},"language-bash shiki shiki-themes github-light github-dark","When\n   \u003CCondition is true>\nThen\n   \u003CTake desired Action>\n","bash","",[52,53,54,63,87,93],"code",{"__ignoreMap":50},[55,56,59],"span",{"class":57,"line":58},"line",1,[55,60,62],{"class":61},"sScJk","When\n",[55,64,66,70,73,77,80,84],{"class":57,"line":65},2,[55,67,69],{"class":68},"szBVR","   \u003C",[55,71,72],{"class":61},"Condition",[55,74,76],{"class":75},"sZZnC"," is",[55,78,79],{"class":75}," tru",[55,81,83],{"class":82},"sVt8B","e",[55,85,86],{"class":68},">\n",[55,88,90],{"class":57,"line":89},3,[55,91,92],{"class":61},"Then\n",[55,94,96,98,101,104,107,110],{"class":57,"line":95},4,[55,97,69],{"class":68},[55,99,100],{"class":61},"Take",[55,102,103],{"class":75}," desired",[55,105,106],{"class":75}," Actio",[55,108,109],{"class":82},"n",[55,111,86],{"class":68},[11,113,114],{},"Let's take an example to understand this better. Assume you're working on a problem where you want to give relevant offers to users for the food ordering service that your business provides. (Eg. Zomato, Swiggy, Uber Eats)",[11,116,117,120],{},[37,118,119],{},"Condition:"," When a user meets all of the following conditions:",[122,123,124,128,131],"ul",{},[125,126,127],"li",{},"User has made atleast 10 orders",[125,129,130],{},"Average order values is greater than Rs. 150",[125,132,133],{},"User age is between 20-30",[11,135,136,139],{},[37,137,138],{},"Action:"," Offer user a discount of 20%",[11,141,142],{},"This logic can be modified easily as well as enhanced further to other attributes that belong to user.",[11,144,145,146,149],{},"Rule engines are useful in solving business oriented logic that result in some sort of decision using number of business attributes. You could argue that can't we embed this logic in our code itself. Yes, we could do that but rule engines give ",[37,147,148],{},"flexibility"," to modify conditions and add more logics. Since these conditions come from product\u002Fbusiness, they have much more accessibily and don't have to reach out to developers each time.",[11,151,152],{},"Also you have the flexibility where you want to define the rules. It could be in a JSON, text file or a web interface where anyone can easily perform CRUD operations. Another addition would be support of multiple version of rules for different set of users.",[11,154,155],{},"In the next section, let's learn how the rule engine actually works.",[26,157],{},[29,159,161],{"id":160},"working-of-a-rule-engine","Working of a Rule Engine",[11,163,164,165,168],{},"As you must have understood the rule engine typically works as like multiple ",[52,166,167],{},"if-else "," conditons. So the system runs input (aka fact) through defined set of rules, based on the result of the condition it decides whether to run corresponding action or not. To define it a bit formally, there are 3 phases in one execution.",[170,171,173],"h3",{"id":172},"_3-phases-in-rule-engine","3 phases in rule engine",[11,175,176],{},[37,177,178],{},"Match",[11,180,181,182,187],{},"This is the phase of pattern matching where the system matches the facts and data against the set of defined conditions (rules). Some of the commonly used algorithm for pattern matching like ",[15,183,186],{"href":184,"rel":185},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FRete_algorithm",[19],"Rete"," (used in Drools), Treat, Leaps, etc. Various versions of Rete are used in modern business rule management solutions (BRMS) today. Going in-depth of Rete is out of scope for this blog (maybe another time).",[11,189,190],{},[37,191,192],{},"Resolve",[11,194,195,196,199],{},"There can be scenarios of conflicts from match phase, the engine handles the order of conflicting rules. Think of this like a ",[37,197,198],{},"priority"," that allows engine to give more weightage to some conditons over others. Few of the algorithms used for resolving conflicts are Recency based, priority wise, refactor, etc.",[11,201,202],{},[37,203,204],{},"Execute",[11,206,207],{},"In this phase, the engine executes the action corresponding to the selected rule and returns the final result.",[11,209,210,211,214],{},"An important property of rule engines is ",[37,212,213],{},"chaining"," - where the action part of one rule changes the state of the system in such a way that it alters the value of the condition part of other rules.",[26,216],{},[29,218,220],{"id":219},"implementing-a-rule-engine","Implementing a Rule Engine",[11,222,223,224,231],{},"Let's try to implement a rule engine for hands-on experience. We'll be using the ",[37,225,226],{},[15,227,230],{"href":228,"rel":229},"https:\u002F\u002Fgithub.com\u002Fhyperjumptech\u002Fgrule-rule-engine",[19],"Grule"," library and implementing a fairly simple rule engine in Golang. Grule has its own Domain Specific Language and is inspired from the popular Drools library.",[11,233,234],{},"We'll be implementing the offer example defined in previous section. Let's get started by setting up a go project.",[45,236,238],{"className":47,"code":237,"language":49,"meta":50,"style":50},"mkdir test_rule_engine\ncd test_rule_engine\ngo mod init test_rule_engine\ntouch main.go\n",[52,239,240,248,256,269],{"__ignoreMap":50},[55,241,242,245],{"class":57,"line":58},[55,243,244],{"class":61},"mkdir",[55,246,247],{"class":75}," test_rule_engine\n",[55,249,250,254],{"class":57,"line":65},[55,251,253],{"class":252},"sj4cs","cd",[55,255,247],{"class":75},[55,257,258,261,264,267],{"class":57,"line":89},[55,259,260],{"class":61},"go",[55,262,263],{"class":75}," mod",[55,265,266],{"class":75}," init",[55,268,247],{"class":75},[55,270,271,274],{"class":57,"line":95},[55,272,273],{"class":61},"touch",[55,275,276],{"class":75}," main.go\n",[11,278,279,280,283],{},"Open ",[52,281,282],{},"main.go"," in your editor and add following code.",[45,285,288],{"className":286,"code":287,"language":260,"meta":50,"style":50},"language-go shiki shiki-themes github-light github-dark","package main\n\nimport (\n    \"fmt\"\n)\n\nfunc main() {\n  fmt.Println(\"TODO: implementing rule engine\")\n}\n",[52,289,290,298,304,312,323,329,334,346,363],{"__ignoreMap":50},[55,291,292,295],{"class":57,"line":58},[55,293,294],{"class":68},"package",[55,296,297],{"class":61}," main\n",[55,299,300],{"class":57,"line":65},[55,301,303],{"emptyLinePlaceholder":302},true,"\n",[55,305,306,309],{"class":57,"line":89},[55,307,308],{"class":68},"import",[55,310,311],{"class":82}," (\n",[55,313,314,317,320],{"class":57,"line":95},[55,315,316],{"class":75},"    \"",[55,318,319],{"class":61},"fmt",[55,321,322],{"class":75},"\"\n",[55,324,326],{"class":57,"line":325},5,[55,327,328],{"class":82},")\n",[55,330,332],{"class":57,"line":331},6,[55,333,303],{"emptyLinePlaceholder":302},[55,335,337,340,343],{"class":57,"line":336},7,[55,338,339],{"class":68},"func",[55,341,342],{"class":61}," main",[55,344,345],{"class":82},"() {\n",[55,347,349,352,355,358,361],{"class":57,"line":348},8,[55,350,351],{"class":82},"  fmt.",[55,353,354],{"class":61},"Println",[55,356,357],{"class":82},"(",[55,359,360],{"class":75},"\"TODO: implementing rule engine\"",[55,362,328],{"class":82},[55,364,366],{"class":57,"line":365},9,[55,367,368],{"class":82},"}\n",[11,370,371],{},"Now that are project is ready, let's create a rule engine service.",[45,373,375],{"className":47,"code":374,"language":49,"meta":50,"style":50},"mkdir rule_engine\ntouch rule_engine\u002Fservice.go\ntouch rule_engine\u002Foffer.go\ngo get -u github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\n",[52,376,377,384,391,398],{"__ignoreMap":50},[55,378,379,381],{"class":57,"line":58},[55,380,244],{"class":61},[55,382,383],{"class":75}," rule_engine\n",[55,385,386,388],{"class":57,"line":65},[55,387,273],{"class":61},[55,389,390],{"class":75}," rule_engine\u002Fservice.go\n",[55,392,393,395],{"class":57,"line":89},[55,394,273],{"class":61},[55,396,397],{"class":75}," rule_engine\u002Foffer.go\n",[55,399,400,402,405,408],{"class":57,"line":95},[55,401,260],{"class":61},[55,403,404],{"class":75}," get",[55,406,407],{"class":252}," -u",[55,409,410],{"class":75}," github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\n",[11,412,413,414],{},"Let's define our core rule engine service. Paste the following code in ",[52,415,416],{},"service.go",[45,418,420],{"className":286,"code":419,"language":260,"meta":50,"style":50},"\u002F\u002F rule_engine\u002Fservice.go\npackage rule_engine\n\nimport (\n    \"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Fast\"\n    \"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Fbuilder\"\n    \"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Fengine\"\n    \"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Fpkg\"\n)\n\nvar knowledgeLibrary = *ast.NewKnowledgeLibrary()\n\n\u002F\u002F Rule input object\ntype RuleInput interface {\n    DataKey() string\n}\n\n\u002F\u002F Rule output object\ntype RuleOutput interface {\n    DataKey() string\n}\n\n\u002F\u002F configs associated with each rule\ntype RuleConfig interface {\n    RuleName() string\n    RuleInput() RuleInput\n    RuleOutput() RuleOutput\n}\n\ntype RuleEngineSvc struct {\n}\n\nfunc NewRuleEngineSvc() *RuleEngineSvc {\n    \u002F\u002F you could add your cloud provider here instead of keeping rule file in your code.\n    buildRuleEngine()\n    return &RuleEngineSvc{}\n}\n\nfunc buildRuleEngine() {\n    ruleBuilder := builder.NewRuleBuilder(&knowledgeLibrary)\n\n    \u002F\u002F Read rule from file and build rules\n    ruleFile := pkg.NewFileResource(\"rules.grl\")\n    err := ruleBuilder.BuildRuleFromResource(\"Rules\", \"0.0.1\", ruleFile)\n    if err != nil {\n        panic(err)\n    }\n\n}\n\nfunc (svc *RuleEngineSvc) Execute(ruleConf RuleConfig) error {\n    \u002F\u002F get KnowledgeBase instance to execute particular rule\n    knowledgeBase := knowledgeLibrary.NewKnowledgeBaseInstance(\"Rules\", \"0.0.1\")\n\n    dataCtx := ast.NewDataContext()\n    \u002F\u002F add input data context\n    err := dataCtx.Add(ruleConf.RuleInput().DataKey(), ruleConf.RuleInput())\n    if err != nil {\n        return err\n    }\n\n    \u002F\u002F add output data context\n    err = dataCtx.Add(ruleConf.RuleOutput().DataKey(), ruleConf.RuleOutput())\n    if err != nil {\n        return err\n    }\n\n    \u002F\u002F create rule engine and execute on provided data and knowledge base\n    ruleEngine := engine.NewGruleEngine()\n    err = ruleEngine.Execute(dataCtx, knowledgeBase)\n    if err != nil {\n        return err\n    }\n    return nil\n}\n",[52,421,422,428,434,438,444,453,462,471,480,484,489,513,518,524,539,551,556,561,567,579,588,593,598,604,616,626,637,648,653,658,671,676,681,699,705,713,727,732,737,747,770,775,781,802,830,847,856,862,867,872,877,912,918,942,947,963,969,1002,1015,1024,1029,1034,1040,1066,1079,1086,1091,1096,1102,1118,1133,1146,1153,1158,1166],{"__ignoreMap":50},[55,423,424],{"class":57,"line":58},[55,425,427],{"class":426},"sJ8bj","\u002F\u002F rule_engine\u002Fservice.go\n",[55,429,430,432],{"class":57,"line":65},[55,431,294],{"class":68},[55,433,383],{"class":61},[55,435,436],{"class":57,"line":89},[55,437,303],{"emptyLinePlaceholder":302},[55,439,440,442],{"class":57,"line":95},[55,441,308],{"class":68},[55,443,311],{"class":82},[55,445,446,448,451],{"class":57,"line":325},[55,447,316],{"class":75},[55,449,450],{"class":61},"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Fast",[55,452,322],{"class":75},[55,454,455,457,460],{"class":57,"line":331},[55,456,316],{"class":75},[55,458,459],{"class":61},"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Fbuilder",[55,461,322],{"class":75},[55,463,464,466,469],{"class":57,"line":336},[55,465,316],{"class":75},[55,467,468],{"class":61},"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Fengine",[55,470,322],{"class":75},[55,472,473,475,478],{"class":57,"line":348},[55,474,316],{"class":75},[55,476,477],{"class":61},"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Fpkg",[55,479,322],{"class":75},[55,481,482],{"class":57,"line":365},[55,483,328],{"class":82},[55,485,487],{"class":57,"line":486},10,[55,488,303],{"emptyLinePlaceholder":302},[55,490,492,495,498,501,504,507,510],{"class":57,"line":491},11,[55,493,494],{"class":68},"var",[55,496,497],{"class":82}," knowledgeLibrary ",[55,499,500],{"class":68},"=",[55,502,503],{"class":68}," *",[55,505,506],{"class":82},"ast.",[55,508,509],{"class":61},"NewKnowledgeLibrary",[55,511,512],{"class":82},"()\n",[55,514,516],{"class":57,"line":515},12,[55,517,303],{"emptyLinePlaceholder":302},[55,519,521],{"class":57,"line":520},13,[55,522,523],{"class":426},"\u002F\u002F Rule input object\n",[55,525,527,530,533,536],{"class":57,"line":526},14,[55,528,529],{"class":68},"type",[55,531,532],{"class":61}," RuleInput",[55,534,535],{"class":68}," interface",[55,537,538],{"class":82}," {\n",[55,540,542,545,548],{"class":57,"line":541},15,[55,543,544],{"class":61},"    DataKey",[55,546,547],{"class":82},"() ",[55,549,550],{"class":68},"string\n",[55,552,554],{"class":57,"line":553},16,[55,555,368],{"class":82},[55,557,559],{"class":57,"line":558},17,[55,560,303],{"emptyLinePlaceholder":302},[55,562,564],{"class":57,"line":563},18,[55,565,566],{"class":426},"\u002F\u002F Rule output object\n",[55,568,570,572,575,577],{"class":57,"line":569},19,[55,571,529],{"class":68},[55,573,574],{"class":61}," RuleOutput",[55,576,535],{"class":68},[55,578,538],{"class":82},[55,580,582,584,586],{"class":57,"line":581},20,[55,583,544],{"class":61},[55,585,547],{"class":82},[55,587,550],{"class":68},[55,589,591],{"class":57,"line":590},21,[55,592,368],{"class":82},[55,594,596],{"class":57,"line":595},22,[55,597,303],{"emptyLinePlaceholder":302},[55,599,601],{"class":57,"line":600},23,[55,602,603],{"class":426},"\u002F\u002F configs associated with each rule\n",[55,605,607,609,612,614],{"class":57,"line":606},24,[55,608,529],{"class":68},[55,610,611],{"class":61}," RuleConfig",[55,613,535],{"class":68},[55,615,538],{"class":82},[55,617,619,622,624],{"class":57,"line":618},25,[55,620,621],{"class":61},"    RuleName",[55,623,547],{"class":82},[55,625,550],{"class":68},[55,627,629,632,634],{"class":57,"line":628},26,[55,630,631],{"class":61},"    RuleInput",[55,633,547],{"class":82},[55,635,636],{"class":61},"RuleInput\n",[55,638,640,643,645],{"class":57,"line":639},27,[55,641,642],{"class":61},"    RuleOutput",[55,644,547],{"class":82},[55,646,647],{"class":61},"RuleOutput\n",[55,649,651],{"class":57,"line":650},28,[55,652,368],{"class":82},[55,654,656],{"class":57,"line":655},29,[55,657,303],{"emptyLinePlaceholder":302},[55,659,661,663,666,669],{"class":57,"line":660},30,[55,662,529],{"class":68},[55,664,665],{"class":61}," RuleEngineSvc",[55,667,668],{"class":68}," struct",[55,670,538],{"class":82},[55,672,674],{"class":57,"line":673},31,[55,675,368],{"class":82},[55,677,679],{"class":57,"line":678},32,[55,680,303],{"emptyLinePlaceholder":302},[55,682,684,686,689,691,694,697],{"class":57,"line":683},33,[55,685,339],{"class":68},[55,687,688],{"class":61}," NewRuleEngineSvc",[55,690,547],{"class":82},[55,692,693],{"class":68},"*",[55,695,696],{"class":61},"RuleEngineSvc",[55,698,538],{"class":82},[55,700,702],{"class":57,"line":701},34,[55,703,704],{"class":426},"    \u002F\u002F you could add your cloud provider here instead of keeping rule file in your code.\n",[55,706,708,711],{"class":57,"line":707},35,[55,709,710],{"class":61},"    buildRuleEngine",[55,712,512],{"class":82},[55,714,716,719,722,724],{"class":57,"line":715},36,[55,717,718],{"class":68},"    return",[55,720,721],{"class":68}," &",[55,723,696],{"class":61},[55,725,726],{"class":82},"{}\n",[55,728,730],{"class":57,"line":729},37,[55,731,368],{"class":82},[55,733,735],{"class":57,"line":734},38,[55,736,303],{"emptyLinePlaceholder":302},[55,738,740,742,745],{"class":57,"line":739},39,[55,741,339],{"class":68},[55,743,744],{"class":61}," buildRuleEngine",[55,746,345],{"class":82},[55,748,750,753,756,759,762,764,767],{"class":57,"line":749},40,[55,751,752],{"class":82},"    ruleBuilder ",[55,754,755],{"class":68},":=",[55,757,758],{"class":82}," builder.",[55,760,761],{"class":61},"NewRuleBuilder",[55,763,357],{"class":82},[55,765,766],{"class":68},"&",[55,768,769],{"class":82},"knowledgeLibrary)\n",[55,771,773],{"class":57,"line":772},41,[55,774,303],{"emptyLinePlaceholder":302},[55,776,778],{"class":57,"line":777},42,[55,779,780],{"class":426},"    \u002F\u002F Read rule from file and build rules\n",[55,782,784,787,789,792,795,797,800],{"class":57,"line":783},43,[55,785,786],{"class":82},"    ruleFile ",[55,788,755],{"class":68},[55,790,791],{"class":82}," pkg.",[55,793,794],{"class":61},"NewFileResource",[55,796,357],{"class":82},[55,798,799],{"class":75},"\"rules.grl\"",[55,801,328],{"class":82},[55,803,805,808,810,813,816,818,821,824,827],{"class":57,"line":804},44,[55,806,807],{"class":82},"    err ",[55,809,755],{"class":68},[55,811,812],{"class":82}," ruleBuilder.",[55,814,815],{"class":61},"BuildRuleFromResource",[55,817,357],{"class":82},[55,819,820],{"class":75},"\"Rules\"",[55,822,823],{"class":82},", ",[55,825,826],{"class":75},"\"0.0.1\"",[55,828,829],{"class":82},", ruleFile)\n",[55,831,833,836,839,842,845],{"class":57,"line":832},45,[55,834,835],{"class":68},"    if",[55,837,838],{"class":82}," err ",[55,840,841],{"class":68},"!=",[55,843,844],{"class":252}," nil",[55,846,538],{"class":82},[55,848,850,853],{"class":57,"line":849},46,[55,851,852],{"class":61},"        panic",[55,854,855],{"class":82},"(err)\n",[55,857,859],{"class":57,"line":858},47,[55,860,861],{"class":82},"    }\n",[55,863,865],{"class":57,"line":864},48,[55,866,303],{"emptyLinePlaceholder":302},[55,868,870],{"class":57,"line":869},49,[55,871,368],{"class":82},[55,873,875],{"class":57,"line":874},50,[55,876,303],{"emptyLinePlaceholder":302},[55,878,880,882,885,889,891,893,896,898,900,903,905,907,910],{"class":57,"line":879},51,[55,881,339],{"class":68},[55,883,884],{"class":82}," (",[55,886,888],{"class":887},"s4XuR","svc ",[55,890,693],{"class":68},[55,892,696],{"class":61},[55,894,895],{"class":82},") ",[55,897,204],{"class":61},[55,899,357],{"class":82},[55,901,902],{"class":887},"ruleConf",[55,904,611],{"class":61},[55,906,895],{"class":82},[55,908,909],{"class":68},"error",[55,911,538],{"class":82},[55,913,915],{"class":57,"line":914},52,[55,916,917],{"class":426},"    \u002F\u002F get KnowledgeBase instance to execute particular rule\n",[55,919,921,924,926,929,932,934,936,938,940],{"class":57,"line":920},53,[55,922,923],{"class":82},"    knowledgeBase ",[55,925,755],{"class":68},[55,927,928],{"class":82}," knowledgeLibrary.",[55,930,931],{"class":61},"NewKnowledgeBaseInstance",[55,933,357],{"class":82},[55,935,820],{"class":75},[55,937,823],{"class":82},[55,939,826],{"class":75},[55,941,328],{"class":82},[55,943,945],{"class":57,"line":944},54,[55,946,303],{"emptyLinePlaceholder":302},[55,948,950,953,955,958,961],{"class":57,"line":949},55,[55,951,952],{"class":82},"    dataCtx ",[55,954,755],{"class":68},[55,956,957],{"class":82}," ast.",[55,959,960],{"class":61},"NewDataContext",[55,962,512],{"class":82},[55,964,966],{"class":57,"line":965},56,[55,967,968],{"class":426},"    \u002F\u002F add input data context\n",[55,970,972,974,976,979,982,985,988,991,994,997,999],{"class":57,"line":971},57,[55,973,807],{"class":82},[55,975,755],{"class":68},[55,977,978],{"class":82}," dataCtx.",[55,980,981],{"class":61},"Add",[55,983,984],{"class":82},"(ruleConf.",[55,986,987],{"class":61},"RuleInput",[55,989,990],{"class":82},"().",[55,992,993],{"class":61},"DataKey",[55,995,996],{"class":82},"(), ruleConf.",[55,998,987],{"class":61},[55,1000,1001],{"class":82},"())\n",[55,1003,1005,1007,1009,1011,1013],{"class":57,"line":1004},58,[55,1006,835],{"class":68},[55,1008,838],{"class":82},[55,1010,841],{"class":68},[55,1012,844],{"class":252},[55,1014,538],{"class":82},[55,1016,1018,1021],{"class":57,"line":1017},59,[55,1019,1020],{"class":68},"        return",[55,1022,1023],{"class":82}," err\n",[55,1025,1027],{"class":57,"line":1026},60,[55,1028,861],{"class":82},[55,1030,1032],{"class":57,"line":1031},61,[55,1033,303],{"emptyLinePlaceholder":302},[55,1035,1037],{"class":57,"line":1036},62,[55,1038,1039],{"class":426},"    \u002F\u002F add output data context\n",[55,1041,1043,1045,1047,1049,1051,1053,1056,1058,1060,1062,1064],{"class":57,"line":1042},63,[55,1044,807],{"class":82},[55,1046,500],{"class":68},[55,1048,978],{"class":82},[55,1050,981],{"class":61},[55,1052,984],{"class":82},[55,1054,1055],{"class":61},"RuleOutput",[55,1057,990],{"class":82},[55,1059,993],{"class":61},[55,1061,996],{"class":82},[55,1063,1055],{"class":61},[55,1065,1001],{"class":82},[55,1067,1069,1071,1073,1075,1077],{"class":57,"line":1068},64,[55,1070,835],{"class":68},[55,1072,838],{"class":82},[55,1074,841],{"class":68},[55,1076,844],{"class":252},[55,1078,538],{"class":82},[55,1080,1082,1084],{"class":57,"line":1081},65,[55,1083,1020],{"class":68},[55,1085,1023],{"class":82},[55,1087,1089],{"class":57,"line":1088},66,[55,1090,861],{"class":82},[55,1092,1094],{"class":57,"line":1093},67,[55,1095,303],{"emptyLinePlaceholder":302},[55,1097,1099],{"class":57,"line":1098},68,[55,1100,1101],{"class":426},"    \u002F\u002F create rule engine and execute on provided data and knowledge base\n",[55,1103,1105,1108,1110,1113,1116],{"class":57,"line":1104},69,[55,1106,1107],{"class":82},"    ruleEngine ",[55,1109,755],{"class":68},[55,1111,1112],{"class":82}," engine.",[55,1114,1115],{"class":61},"NewGruleEngine",[55,1117,512],{"class":82},[55,1119,1121,1123,1125,1128,1130],{"class":57,"line":1120},70,[55,1122,807],{"class":82},[55,1124,500],{"class":68},[55,1126,1127],{"class":82}," ruleEngine.",[55,1129,204],{"class":61},[55,1131,1132],{"class":82},"(dataCtx, knowledgeBase)\n",[55,1134,1136,1138,1140,1142,1144],{"class":57,"line":1135},71,[55,1137,835],{"class":68},[55,1139,838],{"class":82},[55,1141,841],{"class":68},[55,1143,844],{"class":252},[55,1145,538],{"class":82},[55,1147,1149,1151],{"class":57,"line":1148},72,[55,1150,1020],{"class":68},[55,1152,1023],{"class":82},[55,1154,1156],{"class":57,"line":1155},73,[55,1157,861],{"class":82},[55,1159,1161,1163],{"class":57,"line":1160},74,[55,1162,718],{"class":68},[55,1164,1165],{"class":252}," nil\n",[55,1167,1169],{"class":57,"line":1168},75,[55,1170,368],{"class":82},[11,1172,1173],{},"I've tried to document the code in a way that helps you understand the flow. Here we define a rule engine service. The rule engine execute as explained above in theory works in three parts.",[122,1175,1176,1179,1182],{},[125,1177,1178],{},"Defining knowledge library (loading rules)",[125,1180,1181],{},"Defining the data attributes on which the rules will evaluate",[125,1183,1184],{},"Executing the rule engine and getting the result.",[11,1186,1187],{},"Let's create our offer rule now that uses the interface we've defined in our core rule engine service.",[45,1189,1191],{"className":286,"code":1190,"language":260,"meta":50,"style":50},"\u002F\u002F rule_engine\u002Foffer.go\npackage rule_engine\n\ntype UserOfferContext struct {\n    UserOfferInput  *UserOfferInput\n    UserOfferOutput *UserOfferOutput\n}\n\nfunc (uoc *UserOfferContext) RuleName() string {\n    return \"user_offers\"\n}\n\nfunc (uoc *UserOfferContext) RuleInput() RuleInput {\n    return uoc.UserOfferInput\n}\n\nfunc (uoc *UserOfferContext) RuleOutput() RuleOutput {\n    return uoc.UserOfferOutput\n}\n\n\u002F\u002F User data attributes\ntype UserOfferInput struct {\n    Name              string  `json:\"name\"`\n    Username          string  `json:\"username\"`\n    Email             string  `json:\"email\"`\n    Age               int     `json:\"age\"`\n    Gender            string  `json:\"gender\"`\n    TotalOrders       int     `json:\"total_orders\"`\n    AverageOrderValue float64 `json:\"average_order_value\"`\n}\n\nfunc (u *UserOfferInput) DataKey() string {\n    return \"InputData\"\n}\n\n\u002F\u002F Offer output object\ntype UserOfferOutput struct {\n    IsOfferApplicable bool `json:\"is_offer_applicable\"`\n}\n\nfunc (u *UserOfferOutput) DataKey() string {\n    return \"OutputData\"\n}\n\nfunc NewUserOfferContext() *UserOfferContext {\n    return &UserOfferContext{\n        UserOfferInput:  &UserOfferInput{},\n        UserOfferOutput: &UserOfferOutput{},\n    }\n}\n",[52,1192,1193,1198,1204,1208,1219,1229,1239,1243,1247,1273,1280,1284,1288,1310,1317,1321,1325,1347,1354,1358,1362,1367,1378,1388,1398,1408,1419,1429,1439,1450,1454,1458,1482,1489,1493,1497,1502,1513,1524,1528,1532,1555,1562,1566,1570,1585,1596,1608,1619,1623],{"__ignoreMap":50},[55,1194,1195],{"class":57,"line":58},[55,1196,1197],{"class":426},"\u002F\u002F rule_engine\u002Foffer.go\n",[55,1199,1200,1202],{"class":57,"line":65},[55,1201,294],{"class":68},[55,1203,383],{"class":61},[55,1205,1206],{"class":57,"line":89},[55,1207,303],{"emptyLinePlaceholder":302},[55,1209,1210,1212,1215,1217],{"class":57,"line":95},[55,1211,529],{"class":68},[55,1213,1214],{"class":61}," UserOfferContext",[55,1216,668],{"class":68},[55,1218,538],{"class":82},[55,1220,1221,1224,1226],{"class":57,"line":325},[55,1222,1223],{"class":82},"    UserOfferInput  ",[55,1225,693],{"class":68},[55,1227,1228],{"class":61},"UserOfferInput\n",[55,1230,1231,1234,1236],{"class":57,"line":331},[55,1232,1233],{"class":82},"    UserOfferOutput ",[55,1235,693],{"class":68},[55,1237,1238],{"class":61},"UserOfferOutput\n",[55,1240,1241],{"class":57,"line":336},[55,1242,368],{"class":82},[55,1244,1245],{"class":57,"line":348},[55,1246,303],{"emptyLinePlaceholder":302},[55,1248,1249,1251,1253,1256,1258,1261,1263,1266,1268,1271],{"class":57,"line":365},[55,1250,339],{"class":68},[55,1252,884],{"class":82},[55,1254,1255],{"class":887},"uoc ",[55,1257,693],{"class":68},[55,1259,1260],{"class":61},"UserOfferContext",[55,1262,895],{"class":82},[55,1264,1265],{"class":61},"RuleName",[55,1267,547],{"class":82},[55,1269,1270],{"class":68},"string",[55,1272,538],{"class":82},[55,1274,1275,1277],{"class":57,"line":486},[55,1276,718],{"class":68},[55,1278,1279],{"class":75}," \"user_offers\"\n",[55,1281,1282],{"class":57,"line":491},[55,1283,368],{"class":82},[55,1285,1286],{"class":57,"line":515},[55,1287,303],{"emptyLinePlaceholder":302},[55,1289,1290,1292,1294,1296,1298,1300,1302,1304,1306,1308],{"class":57,"line":520},[55,1291,339],{"class":68},[55,1293,884],{"class":82},[55,1295,1255],{"class":887},[55,1297,693],{"class":68},[55,1299,1260],{"class":61},[55,1301,895],{"class":82},[55,1303,987],{"class":61},[55,1305,547],{"class":82},[55,1307,987],{"class":61},[55,1309,538],{"class":82},[55,1311,1312,1314],{"class":57,"line":526},[55,1313,718],{"class":68},[55,1315,1316],{"class":82}," uoc.UserOfferInput\n",[55,1318,1319],{"class":57,"line":541},[55,1320,368],{"class":82},[55,1322,1323],{"class":57,"line":553},[55,1324,303],{"emptyLinePlaceholder":302},[55,1326,1327,1329,1331,1333,1335,1337,1339,1341,1343,1345],{"class":57,"line":558},[55,1328,339],{"class":68},[55,1330,884],{"class":82},[55,1332,1255],{"class":887},[55,1334,693],{"class":68},[55,1336,1260],{"class":61},[55,1338,895],{"class":82},[55,1340,1055],{"class":61},[55,1342,547],{"class":82},[55,1344,1055],{"class":61},[55,1346,538],{"class":82},[55,1348,1349,1351],{"class":57,"line":563},[55,1350,718],{"class":68},[55,1352,1353],{"class":82}," uoc.UserOfferOutput\n",[55,1355,1356],{"class":57,"line":569},[55,1357,368],{"class":82},[55,1359,1360],{"class":57,"line":581},[55,1361,303],{"emptyLinePlaceholder":302},[55,1363,1364],{"class":57,"line":590},[55,1365,1366],{"class":426},"\u002F\u002F User data attributes\n",[55,1368,1369,1371,1374,1376],{"class":57,"line":595},[55,1370,529],{"class":68},[55,1372,1373],{"class":61}," UserOfferInput",[55,1375,668],{"class":68},[55,1377,538],{"class":82},[55,1379,1380,1383,1385],{"class":57,"line":600},[55,1381,1382],{"class":82},"    Name              ",[55,1384,1270],{"class":68},[55,1386,1387],{"class":75},"  `json:\"name\"`\n",[55,1389,1390,1393,1395],{"class":57,"line":606},[55,1391,1392],{"class":82},"    Username          ",[55,1394,1270],{"class":68},[55,1396,1397],{"class":75},"  `json:\"username\"`\n",[55,1399,1400,1403,1405],{"class":57,"line":618},[55,1401,1402],{"class":82},"    Email             ",[55,1404,1270],{"class":68},[55,1406,1407],{"class":75},"  `json:\"email\"`\n",[55,1409,1410,1413,1416],{"class":57,"line":628},[55,1411,1412],{"class":82},"    Age               ",[55,1414,1415],{"class":68},"int",[55,1417,1418],{"class":75},"     `json:\"age\"`\n",[55,1420,1421,1424,1426],{"class":57,"line":639},[55,1422,1423],{"class":82},"    Gender            ",[55,1425,1270],{"class":68},[55,1427,1428],{"class":75},"  `json:\"gender\"`\n",[55,1430,1431,1434,1436],{"class":57,"line":650},[55,1432,1433],{"class":82},"    TotalOrders       ",[55,1435,1415],{"class":68},[55,1437,1438],{"class":75},"     `json:\"total_orders\"`\n",[55,1440,1441,1444,1447],{"class":57,"line":655},[55,1442,1443],{"class":82},"    AverageOrderValue ",[55,1445,1446],{"class":68},"float64",[55,1448,1449],{"class":75}," `json:\"average_order_value\"`\n",[55,1451,1452],{"class":57,"line":660},[55,1453,368],{"class":82},[55,1455,1456],{"class":57,"line":673},[55,1457,303],{"emptyLinePlaceholder":302},[55,1459,1460,1462,1464,1467,1469,1472,1474,1476,1478,1480],{"class":57,"line":678},[55,1461,339],{"class":68},[55,1463,884],{"class":82},[55,1465,1466],{"class":887},"u ",[55,1468,693],{"class":68},[55,1470,1471],{"class":61},"UserOfferInput",[55,1473,895],{"class":82},[55,1475,993],{"class":61},[55,1477,547],{"class":82},[55,1479,1270],{"class":68},[55,1481,538],{"class":82},[55,1483,1484,1486],{"class":57,"line":683},[55,1485,718],{"class":68},[55,1487,1488],{"class":75}," \"InputData\"\n",[55,1490,1491],{"class":57,"line":701},[55,1492,368],{"class":82},[55,1494,1495],{"class":57,"line":707},[55,1496,303],{"emptyLinePlaceholder":302},[55,1498,1499],{"class":57,"line":715},[55,1500,1501],{"class":426},"\u002F\u002F Offer output object\n",[55,1503,1504,1506,1509,1511],{"class":57,"line":729},[55,1505,529],{"class":68},[55,1507,1508],{"class":61}," UserOfferOutput",[55,1510,668],{"class":68},[55,1512,538],{"class":82},[55,1514,1515,1518,1521],{"class":57,"line":734},[55,1516,1517],{"class":82},"    IsOfferApplicable ",[55,1519,1520],{"class":68},"bool",[55,1522,1523],{"class":75}," `json:\"is_offer_applicable\"`\n",[55,1525,1526],{"class":57,"line":739},[55,1527,368],{"class":82},[55,1529,1530],{"class":57,"line":749},[55,1531,303],{"emptyLinePlaceholder":302},[55,1533,1534,1536,1538,1540,1542,1545,1547,1549,1551,1553],{"class":57,"line":772},[55,1535,339],{"class":68},[55,1537,884],{"class":82},[55,1539,1466],{"class":887},[55,1541,693],{"class":68},[55,1543,1544],{"class":61},"UserOfferOutput",[55,1546,895],{"class":82},[55,1548,993],{"class":61},[55,1550,547],{"class":82},[55,1552,1270],{"class":68},[55,1554,538],{"class":82},[55,1556,1557,1559],{"class":57,"line":777},[55,1558,718],{"class":68},[55,1560,1561],{"class":75}," \"OutputData\"\n",[55,1563,1564],{"class":57,"line":783},[55,1565,368],{"class":82},[55,1567,1568],{"class":57,"line":804},[55,1569,303],{"emptyLinePlaceholder":302},[55,1571,1572,1574,1577,1579,1581,1583],{"class":57,"line":832},[55,1573,339],{"class":68},[55,1575,1576],{"class":61}," NewUserOfferContext",[55,1578,547],{"class":82},[55,1580,693],{"class":68},[55,1582,1260],{"class":61},[55,1584,538],{"class":82},[55,1586,1587,1589,1591,1593],{"class":57,"line":849},[55,1588,718],{"class":68},[55,1590,721],{"class":68},[55,1592,1260],{"class":61},[55,1594,1595],{"class":82},"{\n",[55,1597,1598,1601,1603,1605],{"class":57,"line":858},[55,1599,1600],{"class":82},"        UserOfferInput:  ",[55,1602,766],{"class":68},[55,1604,1471],{"class":61},[55,1606,1607],{"class":82},"{},\n",[55,1609,1610,1613,1615,1617],{"class":57,"line":864},[55,1611,1612],{"class":82},"        UserOfferOutput: ",[55,1614,766],{"class":68},[55,1616,1544],{"class":61},[55,1618,1607],{"class":82},[55,1620,1621],{"class":57,"line":869},[55,1622,861],{"class":82},[55,1624,1625],{"class":57,"line":874},[55,1626,368],{"class":82},[11,1628,1629,1630,1633],{},"Cool, so we've defined our offer rule construct. But we're missing one step, we haven't added any rule yet. Remember ",[52,1631,1632],{},"rules.grl"," file that we read rules from. Let's add that.",[45,1635,1637],{"className":47,"code":1636,"language":49,"meta":50,"style":50},"# go to root level in project\ntouch rules.grl\n",[52,1638,1639,1644],{"__ignoreMap":50},[55,1640,1641],{"class":57,"line":58},[55,1642,1643],{"class":426},"# go to root level in project\n",[55,1645,1646,1648],{"class":57,"line":65},[55,1647,273],{"class":61},[55,1649,1650],{"class":75}," rules.grl\n",[11,1652,1653,1654],{},"Paste the following code in ",[52,1655,1632],{},[45,1657,1659],{"className":47,"code":1658,"language":49,"meta":50,"style":50},"rule CheckOffer \"Check if offer can be applied for user\" salience 10 {\n    when\n        InputData.TotalOrders >= 10 && InputData.AverageOrderValue > 150 && InputData.Age >= 20 && InputData.Age \u003C= 30\n    then\n        OutputData.IsOfferApplicable = true;\n        Retract(\"CheckOffer\");\n}\n",[52,1660,1661,1680,1685,1732,1737,1751,1762],{"__ignoreMap":50},[55,1662,1663,1666,1669,1672,1675,1678],{"class":57,"line":58},[55,1664,1665],{"class":61},"rule",[55,1667,1668],{"class":75}," CheckOffer",[55,1670,1671],{"class":75}," \"Check if offer can be applied for user\"",[55,1673,1674],{"class":75}," salience",[55,1676,1677],{"class":252}," 10",[55,1679,538],{"class":75},[55,1681,1682],{"class":57,"line":65},[55,1683,1684],{"class":61},"    when\n",[55,1686,1687,1690,1693,1695,1697,1700,1703,1705,1708,1710,1713,1715,1717,1720,1722,1724,1727,1729],{"class":57,"line":89},[55,1688,1689],{"class":61},"        InputData.TotalOrders",[55,1691,1692],{"class":68}," >",[55,1694,500],{"class":75},[55,1696,1677],{"class":252},[55,1698,1699],{"class":82}," && ",[55,1701,1702],{"class":61},"InputData.AverageOrderValue",[55,1704,1692],{"class":68},[55,1706,1707],{"class":252}," 150",[55,1709,1699],{"class":82},[55,1711,1712],{"class":61},"InputData.Age",[55,1714,1692],{"class":68},[55,1716,500],{"class":75},[55,1718,1719],{"class":252}," 20",[55,1721,1699],{"class":82},[55,1723,1712],{"class":61},[55,1725,1726],{"class":68}," \u003C",[55,1728,500],{"class":75},[55,1730,1731],{"class":252}," 30\n",[55,1733,1734],{"class":57,"line":95},[55,1735,1736],{"class":68},"    then\n",[55,1738,1739,1742,1745,1748],{"class":57,"line":325},[55,1740,1741],{"class":61},"        OutputData.IsOfferApplicable",[55,1743,1744],{"class":75}," =",[55,1746,1747],{"class":252}," true",[55,1749,1750],{"class":82},";\n",[55,1752,1753,1756,1759],{"class":57,"line":331},[55,1754,1755],{"class":61},"        Retract(",[55,1757,1758],{"class":61},"\"CheckOffer\"",[55,1760,1761],{"class":82},");\n",[55,1763,1764],{"class":57,"line":336},[55,1765,368],{"class":82},[11,1767,1768],{},"There are couple of things that could be refactored here further. But i'll leave that as an exercise. Now that we have our offer rule engine ready to be used, let's see it in action.",[11,1770,1771,1772,1774],{},"Go to ",[52,1773,282],{}," and update it with following code.",[45,1776,1778],{"className":286,"code":1777,"language":260,"meta":50,"style":50},"\u002F\u002F main.go\npackage main\n\nimport (\n    \"fmt\"\n    \"testgo\u002Frule_engine\"\n\n    \"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Flogger\"\n)\n\n\u002F\u002F can be part of user serice and a separate directory\ntype User struct {\n    Name              string  `json:\"name\"`\n    Username          string  `json:\"username\"`\n    Email             string  `json:\"email\"`\n    Age               int     `json:\"age\"`\n    Gender            string  `json:\"gender\"`\n    TotalOrders       int     `json:\"total_orders\"`\n    AverageOrderValue float64 `json:\"average_order_value\"`\n}\n\n\u002F\u002F can be moved to offer directory\ntype OfferService interface {\n    CheckOfferForUser(user User) bool\n}\n\ntype OfferServiceClient struct {\n    ruleEngineSvc *rule_engine.RuleEngineSvc\n}\n\nfunc NewOfferService(ruleEngineSvc *rule_engine.RuleEngineSvc) OfferService {\n    return &OfferServiceClient{\n        ruleEngineSvc: ruleEngineSvc,\n    }\n}\n\nfunc (svc OfferServiceClient) CheckOfferForUser(user User) bool {\n    offerCard := rule_engine.NewUserOfferContext()\n    offerCard.UserOfferInput = &rule_engine.UserOfferInput{\n        Name:              user.Name,\n        Username:          user.Username,\n        Email:             user.Email,\n        Gender:            user.Gender,\n        Age:               user.Age,\n        TotalOrders:       user.TotalOrders,\n        AverageOrderValue: user.AverageOrderValue,\n    }\n\n    err := svc.ruleEngineSvc.Execute(offerCard)\n    if err != nil {\n        logger.Log.Error(\"get user offer rule engine failed\", err)\n    }\n\n    return offerCard.UserOfferOutput.IsOfferApplicable\n}\n\nfunc main() {\n    ruleEngineSvc := rule_engine.NewRuleEngineSvc()\n    offerSvc := NewOfferService(ruleEngineSvc)\n\n    userA := User{\n        Name:              \"Mohit Khare\",\n        Username:          \"mkfeuhrer\",\n        Email:             \"me@mohitkhare.com\",\n        Gender:            \"Male\",\n        Age:               25,\n        TotalOrders:       50,\n        AverageOrderValue: 225,\n    }\n\n    fmt.Println(\"offer validity for user A: \", offerSvc.CheckOfferForUser(userA))\n\n    userB := User{\n        Name:              \"Pranjal Sharma\",\n        Username:          \"pj\",\n        Email:             \"pj@abc.com\",\n        Gender:            \"Male\",\n        Age:               25,\n        TotalOrders:       10,\n        AverageOrderValue: 80,\n    }\n\n    fmt.Println(\"offer validity for user B: \", offerSvc.CheckOfferForUser(userB))\n}\n",[52,1779,1780,1785,1791,1795,1801,1809,1818,1822,1831,1835,1839,1844,1855,1863,1871,1879,1887,1895,1903,1911,1915,1919,1924,1935,1952,1956,1960,1971,1987,1991,1995,2022,2033,2038,2042,2046,2050,2077,2092,2109,2114,2119,2124,2129,2134,2139,2144,2148,2152,2166,2178,2194,2198,2202,2209,2213,2217,2225,2238,2250,2254,2265,2276,2286,2296,2306,2316,2326,2336,2340,2344,2364,2368,2379,2388,2397,2407,2416,2425,2435,2445,2450,2455,2474],{"__ignoreMap":50},[55,1781,1782],{"class":57,"line":58},[55,1783,1784],{"class":426},"\u002F\u002F main.go\n",[55,1786,1787,1789],{"class":57,"line":65},[55,1788,294],{"class":68},[55,1790,297],{"class":61},[55,1792,1793],{"class":57,"line":89},[55,1794,303],{"emptyLinePlaceholder":302},[55,1796,1797,1799],{"class":57,"line":95},[55,1798,308],{"class":68},[55,1800,311],{"class":82},[55,1802,1803,1805,1807],{"class":57,"line":325},[55,1804,316],{"class":75},[55,1806,319],{"class":61},[55,1808,322],{"class":75},[55,1810,1811,1813,1816],{"class":57,"line":331},[55,1812,316],{"class":75},[55,1814,1815],{"class":61},"testgo\u002Frule_engine",[55,1817,322],{"class":75},[55,1819,1820],{"class":57,"line":336},[55,1821,303],{"emptyLinePlaceholder":302},[55,1823,1824,1826,1829],{"class":57,"line":348},[55,1825,316],{"class":75},[55,1827,1828],{"class":61},"github.com\u002Fhyperjumptech\u002Fgrule-rule-engine\u002Flogger",[55,1830,322],{"class":75},[55,1832,1833],{"class":57,"line":365},[55,1834,328],{"class":82},[55,1836,1837],{"class":57,"line":486},[55,1838,303],{"emptyLinePlaceholder":302},[55,1840,1841],{"class":57,"line":491},[55,1842,1843],{"class":426},"\u002F\u002F can be part of user serice and a separate directory\n",[55,1845,1846,1848,1851,1853],{"class":57,"line":515},[55,1847,529],{"class":68},[55,1849,1850],{"class":61}," User",[55,1852,668],{"class":68},[55,1854,538],{"class":82},[55,1856,1857,1859,1861],{"class":57,"line":520},[55,1858,1382],{"class":82},[55,1860,1270],{"class":68},[55,1862,1387],{"class":75},[55,1864,1865,1867,1869],{"class":57,"line":526},[55,1866,1392],{"class":82},[55,1868,1270],{"class":68},[55,1870,1397],{"class":75},[55,1872,1873,1875,1877],{"class":57,"line":541},[55,1874,1402],{"class":82},[55,1876,1270],{"class":68},[55,1878,1407],{"class":75},[55,1880,1881,1883,1885],{"class":57,"line":553},[55,1882,1412],{"class":82},[55,1884,1415],{"class":68},[55,1886,1418],{"class":75},[55,1888,1889,1891,1893],{"class":57,"line":558},[55,1890,1423],{"class":82},[55,1892,1270],{"class":68},[55,1894,1428],{"class":75},[55,1896,1897,1899,1901],{"class":57,"line":563},[55,1898,1433],{"class":82},[55,1900,1415],{"class":68},[55,1902,1438],{"class":75},[55,1904,1905,1907,1909],{"class":57,"line":569},[55,1906,1443],{"class":82},[55,1908,1446],{"class":68},[55,1910,1449],{"class":75},[55,1912,1913],{"class":57,"line":581},[55,1914,368],{"class":82},[55,1916,1917],{"class":57,"line":590},[55,1918,303],{"emptyLinePlaceholder":302},[55,1920,1921],{"class":57,"line":595},[55,1922,1923],{"class":426},"\u002F\u002F can be moved to offer directory\n",[55,1925,1926,1928,1931,1933],{"class":57,"line":600},[55,1927,529],{"class":68},[55,1929,1930],{"class":61}," OfferService",[55,1932,535],{"class":68},[55,1934,538],{"class":82},[55,1936,1937,1940,1942,1945,1947,1949],{"class":57,"line":606},[55,1938,1939],{"class":61},"    CheckOfferForUser",[55,1941,357],{"class":82},[55,1943,1944],{"class":887},"user",[55,1946,1850],{"class":61},[55,1948,895],{"class":82},[55,1950,1951],{"class":68},"bool\n",[55,1953,1954],{"class":57,"line":618},[55,1955,368],{"class":82},[55,1957,1958],{"class":57,"line":628},[55,1959,303],{"emptyLinePlaceholder":302},[55,1961,1962,1964,1967,1969],{"class":57,"line":639},[55,1963,529],{"class":68},[55,1965,1966],{"class":61}," OfferServiceClient",[55,1968,668],{"class":68},[55,1970,538],{"class":82},[55,1972,1973,1976,1978,1981,1984],{"class":57,"line":650},[55,1974,1975],{"class":82},"    ruleEngineSvc ",[55,1977,693],{"class":68},[55,1979,1980],{"class":61},"rule_engine",[55,1982,1983],{"class":82},".",[55,1985,1986],{"class":61},"RuleEngineSvc\n",[55,1988,1989],{"class":57,"line":655},[55,1990,368],{"class":82},[55,1992,1993],{"class":57,"line":660},[55,1994,303],{"emptyLinePlaceholder":302},[55,1996,1997,1999,2002,2004,2007,2009,2011,2013,2015,2017,2020],{"class":57,"line":673},[55,1998,339],{"class":68},[55,2000,2001],{"class":61}," NewOfferService",[55,2003,357],{"class":82},[55,2005,2006],{"class":887},"ruleEngineSvc",[55,2008,503],{"class":68},[55,2010,1980],{"class":61},[55,2012,1983],{"class":82},[55,2014,696],{"class":61},[55,2016,895],{"class":82},[55,2018,2019],{"class":61},"OfferService",[55,2021,538],{"class":82},[55,2023,2024,2026,2028,2031],{"class":57,"line":678},[55,2025,718],{"class":68},[55,2027,721],{"class":68},[55,2029,2030],{"class":61},"OfferServiceClient",[55,2032,1595],{"class":82},[55,2034,2035],{"class":57,"line":683},[55,2036,2037],{"class":82},"        ruleEngineSvc: ruleEngineSvc,\n",[55,2039,2040],{"class":57,"line":701},[55,2041,861],{"class":82},[55,2043,2044],{"class":57,"line":707},[55,2045,368],{"class":82},[55,2047,2048],{"class":57,"line":715},[55,2049,303],{"emptyLinePlaceholder":302},[55,2051,2052,2054,2056,2058,2060,2062,2065,2067,2069,2071,2073,2075],{"class":57,"line":729},[55,2053,339],{"class":68},[55,2055,884],{"class":82},[55,2057,888],{"class":887},[55,2059,2030],{"class":61},[55,2061,895],{"class":82},[55,2063,2064],{"class":61},"CheckOfferForUser",[55,2066,357],{"class":82},[55,2068,1944],{"class":887},[55,2070,1850],{"class":61},[55,2072,895],{"class":82},[55,2074,1520],{"class":68},[55,2076,538],{"class":82},[55,2078,2079,2082,2084,2087,2090],{"class":57,"line":734},[55,2080,2081],{"class":82},"    offerCard ",[55,2083,755],{"class":68},[55,2085,2086],{"class":82}," rule_engine.",[55,2088,2089],{"class":61},"NewUserOfferContext",[55,2091,512],{"class":82},[55,2093,2094,2097,2099,2101,2103,2105,2107],{"class":57,"line":739},[55,2095,2096],{"class":82},"    offerCard.UserOfferInput ",[55,2098,500],{"class":68},[55,2100,721],{"class":68},[55,2102,1980],{"class":61},[55,2104,1983],{"class":82},[55,2106,1471],{"class":61},[55,2108,1595],{"class":82},[55,2110,2111],{"class":57,"line":749},[55,2112,2113],{"class":82},"        Name:              user.Name,\n",[55,2115,2116],{"class":57,"line":772},[55,2117,2118],{"class":82},"        Username:          user.Username,\n",[55,2120,2121],{"class":57,"line":777},[55,2122,2123],{"class":82},"        Email:             user.Email,\n",[55,2125,2126],{"class":57,"line":783},[55,2127,2128],{"class":82},"        Gender:            user.Gender,\n",[55,2130,2131],{"class":57,"line":804},[55,2132,2133],{"class":82},"        Age:               user.Age,\n",[55,2135,2136],{"class":57,"line":832},[55,2137,2138],{"class":82},"        TotalOrders:       user.TotalOrders,\n",[55,2140,2141],{"class":57,"line":849},[55,2142,2143],{"class":82},"        AverageOrderValue: user.AverageOrderValue,\n",[55,2145,2146],{"class":57,"line":858},[55,2147,861],{"class":82},[55,2149,2150],{"class":57,"line":864},[55,2151,303],{"emptyLinePlaceholder":302},[55,2153,2154,2156,2158,2161,2163],{"class":57,"line":869},[55,2155,807],{"class":82},[55,2157,755],{"class":68},[55,2159,2160],{"class":82}," svc.ruleEngineSvc.",[55,2162,204],{"class":61},[55,2164,2165],{"class":82},"(offerCard)\n",[55,2167,2168,2170,2172,2174,2176],{"class":57,"line":874},[55,2169,835],{"class":68},[55,2171,838],{"class":82},[55,2173,841],{"class":68},[55,2175,844],{"class":252},[55,2177,538],{"class":82},[55,2179,2180,2183,2186,2188,2191],{"class":57,"line":879},[55,2181,2182],{"class":82},"        logger.Log.",[55,2184,2185],{"class":61},"Error",[55,2187,357],{"class":82},[55,2189,2190],{"class":75},"\"get user offer rule engine failed\"",[55,2192,2193],{"class":82},", err)\n",[55,2195,2196],{"class":57,"line":914},[55,2197,861],{"class":82},[55,2199,2200],{"class":57,"line":920},[55,2201,303],{"emptyLinePlaceholder":302},[55,2203,2204,2206],{"class":57,"line":944},[55,2205,718],{"class":68},[55,2207,2208],{"class":82}," offerCard.UserOfferOutput.IsOfferApplicable\n",[55,2210,2211],{"class":57,"line":949},[55,2212,368],{"class":82},[55,2214,2215],{"class":57,"line":965},[55,2216,303],{"emptyLinePlaceholder":302},[55,2218,2219,2221,2223],{"class":57,"line":971},[55,2220,339],{"class":68},[55,2222,342],{"class":61},[55,2224,345],{"class":82},[55,2226,2227,2229,2231,2233,2236],{"class":57,"line":1004},[55,2228,1975],{"class":82},[55,2230,755],{"class":68},[55,2232,2086],{"class":82},[55,2234,2235],{"class":61},"NewRuleEngineSvc",[55,2237,512],{"class":82},[55,2239,2240,2243,2245,2247],{"class":57,"line":1017},[55,2241,2242],{"class":82},"    offerSvc ",[55,2244,755],{"class":68},[55,2246,2001],{"class":61},[55,2248,2249],{"class":82},"(ruleEngineSvc)\n",[55,2251,2252],{"class":57,"line":1026},[55,2253,303],{"emptyLinePlaceholder":302},[55,2255,2256,2259,2261,2263],{"class":57,"line":1031},[55,2257,2258],{"class":82},"    userA ",[55,2260,755],{"class":68},[55,2262,1850],{"class":61},[55,2264,1595],{"class":82},[55,2266,2267,2270,2273],{"class":57,"line":1036},[55,2268,2269],{"class":82},"        Name:              ",[55,2271,2272],{"class":75},"\"Mohit Khare\"",[55,2274,2275],{"class":82},",\n",[55,2277,2278,2281,2284],{"class":57,"line":1042},[55,2279,2280],{"class":82},"        Username:          ",[55,2282,2283],{"class":75},"\"mkfeuhrer\"",[55,2285,2275],{"class":82},[55,2287,2288,2291,2294],{"class":57,"line":1068},[55,2289,2290],{"class":82},"        Email:             ",[55,2292,2293],{"class":75},"\"me@mohitkhare.com\"",[55,2295,2275],{"class":82},[55,2297,2298,2301,2304],{"class":57,"line":1081},[55,2299,2300],{"class":82},"        Gender:            ",[55,2302,2303],{"class":75},"\"Male\"",[55,2305,2275],{"class":82},[55,2307,2308,2311,2314],{"class":57,"line":1088},[55,2309,2310],{"class":82},"        Age:               ",[55,2312,2313],{"class":252},"25",[55,2315,2275],{"class":82},[55,2317,2318,2321,2324],{"class":57,"line":1093},[55,2319,2320],{"class":82},"        TotalOrders:       ",[55,2322,2323],{"class":252},"50",[55,2325,2275],{"class":82},[55,2327,2328,2331,2334],{"class":57,"line":1098},[55,2329,2330],{"class":82},"        AverageOrderValue: ",[55,2332,2333],{"class":252},"225",[55,2335,2275],{"class":82},[55,2337,2338],{"class":57,"line":1104},[55,2339,861],{"class":82},[55,2341,2342],{"class":57,"line":1120},[55,2343,303],{"emptyLinePlaceholder":302},[55,2345,2346,2349,2351,2353,2356,2359,2361],{"class":57,"line":1135},[55,2347,2348],{"class":82},"    fmt.",[55,2350,354],{"class":61},[55,2352,357],{"class":82},[55,2354,2355],{"class":75},"\"offer validity for user A: \"",[55,2357,2358],{"class":82},", offerSvc.",[55,2360,2064],{"class":61},[55,2362,2363],{"class":82},"(userA))\n",[55,2365,2366],{"class":57,"line":1148},[55,2367,303],{"emptyLinePlaceholder":302},[55,2369,2370,2373,2375,2377],{"class":57,"line":1155},[55,2371,2372],{"class":82},"    userB ",[55,2374,755],{"class":68},[55,2376,1850],{"class":61},[55,2378,1595],{"class":82},[55,2380,2381,2383,2386],{"class":57,"line":1160},[55,2382,2269],{"class":82},[55,2384,2385],{"class":75},"\"Pranjal Sharma\"",[55,2387,2275],{"class":82},[55,2389,2390,2392,2395],{"class":57,"line":1168},[55,2391,2280],{"class":82},[55,2393,2394],{"class":75},"\"pj\"",[55,2396,2275],{"class":82},[55,2398,2400,2402,2405],{"class":57,"line":2399},76,[55,2401,2290],{"class":82},[55,2403,2404],{"class":75},"\"pj@abc.com\"",[55,2406,2275],{"class":82},[55,2408,2410,2412,2414],{"class":57,"line":2409},77,[55,2411,2300],{"class":82},[55,2413,2303],{"class":75},[55,2415,2275],{"class":82},[55,2417,2419,2421,2423],{"class":57,"line":2418},78,[55,2420,2310],{"class":82},[55,2422,2313],{"class":252},[55,2424,2275],{"class":82},[55,2426,2428,2430,2433],{"class":57,"line":2427},79,[55,2429,2320],{"class":82},[55,2431,2432],{"class":252},"10",[55,2434,2275],{"class":82},[55,2436,2438,2440,2443],{"class":57,"line":2437},80,[55,2439,2330],{"class":82},[55,2441,2442],{"class":252},"80",[55,2444,2275],{"class":82},[55,2446,2448],{"class":57,"line":2447},81,[55,2449,861],{"class":82},[55,2451,2453],{"class":57,"line":2452},82,[55,2454,303],{"emptyLinePlaceholder":302},[55,2456,2458,2460,2462,2464,2467,2469,2471],{"class":57,"line":2457},83,[55,2459,2348],{"class":82},[55,2461,354],{"class":61},[55,2463,357],{"class":82},[55,2465,2466],{"class":75},"\"offer validity for user B: \"",[55,2468,2358],{"class":82},[55,2470,2064],{"class":61},[55,2472,2473],{"class":82},"(userB))\n",[55,2475,2477],{"class":57,"line":2476},84,[55,2478,368],{"class":82},[11,2480,2481],{},"Just run the main file and you should see the output.",[45,2483,2485],{"className":47,"code":2484,"language":49,"meta":50,"style":50},"go run main.go\n\noffer validity for user A:  true\noffer validity for user B:  false\n",[52,2486,2487,2496,2500,2520],{"__ignoreMap":50},[55,2488,2489,2491,2494],{"class":57,"line":58},[55,2490,260],{"class":61},[55,2492,2493],{"class":75}," run",[55,2495,276],{"class":75},[55,2497,2498],{"class":57,"line":65},[55,2499,303],{"emptyLinePlaceholder":302},[55,2501,2502,2505,2508,2511,2514,2517],{"class":57,"line":89},[55,2503,2504],{"class":61},"offer",[55,2506,2507],{"class":75}," validity",[55,2509,2510],{"class":75}," for",[55,2512,2513],{"class":75}," user",[55,2515,2516],{"class":75}," A:",[55,2518,2519],{"class":252},"  true\n",[55,2521,2522,2524,2526,2528,2530,2533],{"class":57,"line":95},[55,2523,2504],{"class":61},[55,2525,2507],{"class":75},[55,2527,2510],{"class":75},[55,2529,2513],{"class":75},[55,2531,2532],{"class":75}," B:",[55,2534,2535],{"class":252},"  false\n",[11,2537,2538,2539,2542,2543,2545],{},"Tada 🎉 Congrats, you've just implemented your first rule engine. Test your knowledge by adding more rules. You'll need to add a new file similar as ",[52,2540,2541],{},"offer.go"," with your own data attributes. Don't forget to update the ",[52,2544,1632],{}," file.",[26,2547],{},[29,2549,2551],{"id":2550},"benefits-of-rule-engine","Benefits of Rule engine",[122,2553,2554,2561,2568,2575],{},[125,2555,2556,2557,2560],{},"Easy ",[37,2558,2559],{},"understanding"," for non-tech folks since rules are defined in normal logical statements.",[125,2562,2563,2564,2567],{},"Logic is independent from the code. This allows the same logic to be used at multiple places. (",[37,2565,2566],{},"Reusability FTW",")",[125,2569,2570,2571,2574],{},"No changes in code are required if the business needs changes on same attributes. Frequent changes are feasible, you ",[37,2572,2573],{},"won't need deployments"," each time.",[125,2576,2577],{},"Central place for all your business rules instead of being distributed at multiple codebases.",[170,2579,2581],{"id":2580},"when-to-avoid-rule-engine","When to avoid Rule Engine",[11,2583,2584],{},"Rule engines are not an alternate to your developers. In most situations building services, using AI models, proper system design is the way to go for scalable and efficient solutions. Rule engines are extra supplies that can help you in solving business problems.",[26,2586],{},[29,2588,2590],{"id":2589},"resources","Resources",[122,2592,2593,2600],{},[125,2594,2595],{},[15,2596,2599],{"href":2597,"rel":2598},"https:\u002F\u002Fmartinfowler.com\u002Fbliki\u002FRulesEngine.html",[19],"Should I use a Rules Engine?",[125,2601,2602],{},[15,2603,2606],{"href":2604,"rel":2605},"https:\u002F\u002Fwww.hyperon.io\u002Fblog\u002Fwhat-is-a-rules-engine",[19],"Guide on Rule Engine",[170,2608,2610],{"id":2609},"popular-libraries","Popular Libraries",[122,2612,2613,2621],{},[125,2614,2615,2620],{},[15,2616,2619],{"href":2617,"rel":2618},"https:\u002F\u002Fwww.drools.org\u002F",[19],"Drools"," - Open source, Java",[125,2622,2623,2626],{},[15,2624,230],{"href":228,"rel":2625},[19]," - Open source, Golang",[2628,2629,2630],"blockquote",{},[11,2631,2632,2633,2638,2639,2644],{},"Do explore articles on ",[15,2634,2637],{"href":2635,"rel":2636},"https:\u002F\u002Fwww.mohitkhare.com\u002Fcategories\u002Fgolang",[19],"Golang"," and ",[15,2640,2643],{"href":2641,"rel":2642},"https:\u002F\u002Fwww.mohitkhare.com\u002Fcategories\u002Fsystem%20design",[19],"System Design",". You'll learn something new 💡",[11,2646,2647],{},"I hope you learned something new. Feel free to suggest improvements ✅",[11,2649,2650,2651,2656],{},"I share regular updates and resources on ",[15,2652,2655],{"href":2653,"rel":2654},"https:\u002F\u002Ftwitter.com\u002Fmkfeuhrer",[19],"Twitter",". Let’s connect!",[11,2658,2659],{},[37,2660,2661],{},"Keep exploring 🔎 Keep learning 🚀",[2663,2664,2665],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":50,"searchDepth":65,"depth":65,"links":2667},[2668,2669,2672,2673,2676],{"id":31,"depth":65,"text":32},{"id":160,"depth":65,"text":161,"children":2670},[2671],{"id":172,"depth":89,"text":173},{"id":219,"depth":65,"text":220},{"id":2550,"depth":65,"text":2551,"children":2674},[2675],{"id":2580,"depth":89,"text":2581},{"id":2589,"depth":65,"text":2590,"children":2677},[2678],{"id":2609,"depth":89,"text":2610},[2637,2680],"Programming","Rule Engines help in solving changing business requirements with ease. Learn all about Rule engines, it's working, benefits and how to implement one in Golang",false,"md","blog\u002Fguide-to-rule-engines\u002Fguide-to-rule-engines-card.webp","rule engine, what is rule engine, rule engine open source, rule engine example",{},"guide-to-rule-engines","\u002Fblog\u002Fguide-to-rule-engines",{"title":5,"description":2681},"blog\u002Fguide-to-rule-engines","2022-09-12","OBrgNfsQjXjWJfg-Sac9I7eoHV3Em-GDZX94z3UqwEw",[2694,2701,2707,2715,2724,2730,2737,2744,2750,2756,2762,2768,2774,2780,2787,2793,2799,2805,2811,2817,2823,2829,2835,2842,2849,2855,2861,2863,2869,2875,2881,2887,2893,2899,2905,2911,2917,2923,2930,2936,2942,2948,2955,2961,2967,2974,2981,2987,2994,3000,3007,3013,3020,3026,3032,3038,3044,3050,3056,3062,3068,3074,3080,3086,3092,3099,3105,3112,3118,3124,3130,3137,3143],{"path":2695,"title":2696,"description":2697,"categories":2698,"draft":302,"year":2700,"series":6},"\u002Fblog\u002Fai-assisted-workstation","Building an AI-Assisted Personal Workstation","A living log of building a practical AI-assisted workstation for software and startup work.",[2699,2680],"Productivity","2026-08-08",{"path":2702,"title":2703,"description":2704,"categories":2705,"draft":2682,"year":2706,"series":6},"\u002Fblog\u002Faws-s3-golang","Uploading images to AWS S3 in Golang","In this tutorial I cover how to upload, fetch and manage other operations for objects on AWS S3 in Golang",[2637,2680],"2020-01-12",{"path":2708,"title":2709,"description":2710,"categories":2711,"draft":2682,"year":2714,"series":6},"\u002Fblog\u002Fbooks-for-engineers","Best Books for Software Engineers","Best Books to help you build you software engineering career - ranging from fundamentats, interview prep to productivity.",[2712,2713],"Books","Life","2021-12-26",{"path":2716,"title":2717,"description":2718,"categories":2719,"draft":2682,"year":2723,"series":6},"\u002Fblog\u002Fbuilding-acrons","Building Acrons 🚀","Building Acrons, a one-stop tool to decode everyday acronyms like DIY, FOMO, and BRB without losing your flow.",[2720,2721,2722],"Side Projects","Web","Tools","2020-05-26",{"path":2725,"title":2726,"description":2727,"categories":2728,"draft":2682,"year":2729,"series":6},"\u002Fblog\u002Fcap-theorem","CAP Theorem Explained","Learn the concept and misconceptions around popular CAP theorem in system design.",[2643,2680],"2021-07-26",{"path":2731,"title":2732,"description":2733,"categories":2734,"draft":2682,"year":2736,"series":6},"\u002Fblog\u002Fcode-reviews","Code Review Checklist","Why code reviews matter, and best practices that catch bugs early and keep code quality high before merge.",[2735],"Engineering Principles","2020-07-20",{"path":2738,"title":2739,"description":2740,"categories":2741,"draft":2682,"year":2743,"series":6},"\u002Fblog\u002Fdark-mode","Add Dark mode to websites","Dark mode is ❤️️ Add it to your websites with little CSS and JS",[2742,2721],"Javascript","2020-07-04",{"path":2745,"title":2746,"description":2747,"categories":2748,"draft":2682,"year":2749,"series":6},"\u002Fblog\u002Fdate-time-golang","Working with Date and Time in Go","Learn how to use time in Golang - Multiple formats, locations and using date.",[2637,2680],"2020-10-09",{"path":2751,"title":2752,"description":2753,"categories":2754,"draft":2682,"year":2755,"series":6},"\u002Fblog\u002Fdefer-in-golang","Understanding Defer In Golang","Learn about defer keyword in golang and how it can help you avoid panics due to bugs.",[2637,2680],"2021-05-05",{"path":2757,"title":2758,"description":2759,"categories":2760,"draft":2682,"year":2761,"series":6},"\u002Fblog\u002Fenums-golang","Implementing Enums in Golang","Enums are a way to defined set of constant values. Learn how to implement enums in Go using iota with examples.",[2637,2680],"2021-12-18",{"path":2763,"title":2764,"description":2765,"categories":2766,"draft":2682,"year":2767,"series":6},"\u002Fblog\u002Fenvironment-variable-golang","Guide to Environment variables in Go","Learn what are environment variables and how to use them in Go",[2637,2680],"2020-08-14",{"path":2769,"title":2770,"description":2771,"categories":2772,"draft":2682,"year":2773,"series":6},"\u002Fblog\u002Ferror-handling-golang","Handle errors the right way — Golang","How to handle errors in golang to make your life easy",[2637,2680],"2020-01-30",{"path":2775,"title":2776,"description":2777,"categories":2778,"draft":2682,"year":2779,"series":6},"\u002Fblog\u002Ffile-upload-golang","Uploading Files in Golang with Multipart Request","Learn how to upload files from your client to server as a multipart request in Golang.",[2637,2680],"2021-03-13",{"path":2781,"title":2782,"description":2783,"categories":2784,"draft":2682,"year":2786,"series":6},"\u002Fblog\u002Fgit-branch","Git Branch 101","Branching is a new path of development that makes it a lot easier to build features. Learn why and how to use branching in git.",[2785,2680],"Git","2022-03-20",{"path":2788,"title":2789,"description":2790,"categories":2791,"draft":2682,"year":2792,"series":6},"\u002Fblog\u002Fgit-pull-request-template","Guide to Pull Request Templates","Improve collaboration and code reviews with pull request templates. Blog include PR template and how to create one on github\u002Fgitlab",[2785,2680],"2023-08-24",{"path":2794,"title":2795,"description":2796,"categories":2797,"draft":2682,"year":2798,"series":6},"\u002Fblog\u002Fgit-remove-sensitive-info","Securing Git: Remove Sensitive Information","Protect your code from security breaches by using BFG tool to remove sensitive information from Git history. Learn how to do it in this comprehensive guide.",[2785,2680],"2023-10-16",{"path":2800,"title":2801,"description":2802,"categories":2803,"draft":2682,"year":2804,"series":6},"\u002Fblog\u002Fgit-tags-explained","Git tags : Explained","What Git tags are, why and when to use them, and how to start tagging releases in your own projects.",[2785,2680],"2020-06-18",{"path":2806,"title":2807,"description":2808,"categories":2809,"draft":2682,"year":2810,"series":6},"\u002Fblog\u002Fgo-dependency-injection","Dependency Injection in Go using Wire","Learn about dependency injection, its benefits and how to implement it in Go services using wire",[2637,2680],"2022-11-26",{"path":2812,"title":2813,"description":2814,"categories":2815,"draft":2682,"year":2816,"series":6},"\u002Fblog\u002Fgo-generics","Introduction to Generics in Go","Learn about generics in Golang, it's benefits and how to implement it in applications.",[2637,2680],"2022-11-27",{"path":2818,"title":2819,"description":2820,"categories":2821,"draft":2682,"year":2822,"series":6},"\u002Fblog\u002Fgo-in-memory-cache","Building In-Memory Cache in Go","Learn about in-memory caching in Golang, it's benefits and how to implement it with and without generics with a TTL(expiry).",[2637,2680],"2024-03-28",{"path":2824,"title":2825,"description":2826,"categories":2827,"draft":2682,"year":2828,"series":6},"\u002Fblog\u002Fgo-makefile","Ultimate Makefile for Golang","Boost your productivity and save time with ultimate Makefile for Golang projects.",[2637,2680],"2024-06-10",{"path":2830,"title":2831,"description":2832,"categories":2833,"draft":2682,"year":2834,"series":6},"\u002Fblog\u002Fgo-middleware","Mastering Middlewares in Golang","Learn about middlewares, their use cases and how to implement them in Golang applications",[2637,2680],"2022-03-13",{"path":2836,"title":2837,"description":2838,"categories":2839,"draft":2682,"year":2841,"series":6},"\u002Fblog\u002Fgo-naming-conventions","Naming Conventions in Golang","Why naming conventions matter in Go, with best practices and practical examples for clear, readable, maintainable code.",[2637,2680,2840],"Code Quality","2023-05-19",{"path":2843,"title":2844,"description":2845,"categories":2846,"draft":2682,"year":2848,"series":6},"\u002Fblog\u002Fgo-with-redis","Go with Redis","A practical introduction to using Redis with Golang to make your applications faster with in-memory data storage.",[2637,2847,2680],"Database","2020-05-03",{"path":2850,"title":2851,"description":2852,"categories":2853,"draft":2682,"year":2854,"series":6},"\u002Fblog\u002Fgolang-maps","Learn Maps in Golang (with examples)","A complete guide to maps in Golang: creating maps, adding and removing items, iterating, and how map equality works.",[2637,2680],"2020-09-10",{"path":2856,"title":2857,"description":2858,"categories":2859,"draft":2682,"year":2860,"series":6},"\u002Fblog\u002Fguide-to-cdn","Guide to Content Delivery Network","CDN is one of the backbone of modern world internet infrastructure. Learn about Content Delivery Network, it's working, types and benefits.",[2643,2680],"2022-01-23",{"path":2688,"title":5,"description":2681,"categories":2862,"draft":2682,"year":2691,"series":6},[2637,2680],{"path":2864,"title":2865,"description":2866,"categories":2867,"draft":2682,"year":2868,"series":6},"\u002Fblog\u002Fhexagonal-architecture","Guide to Hexagonal Architecture","Learn how to design efficient application with hexagonal architecture with practical example",[2643,2680],"2020-12-13",{"path":2870,"title":2871,"description":2872,"categories":2873,"draft":2682,"year":2874,"series":6},"\u002Fblog\u002Fhttp-status-codes","Learn HTTP Status Codes","A tour of HTTP response status codes, what each class means, and when to use which code in your applications.",[2721,2680],"2020-07-30",{"path":2876,"title":2877,"description":2878,"categories":2879,"draft":2682,"year":2880,"series":6},"\u002Fblog\u002Fintroduction-to-goroutines","Introduction to Goroutines","Understand the basics of concurrency and learn how to work with Goroutines in golang.",[2637,2680],"2021-04-10",{"path":2882,"title":2883,"description":2884,"categories":2885,"draft":2682,"year":2886,"series":6},"\u002Fblog\u002Fjson-in-postgres-with-golang","Storing JSON in Postgres with Golang","Learn how to store JSON objects in Postgres and how to implement it in Golang.",[2680,2847,2637],"2021-02-13",{"path":2888,"title":2889,"description":2890,"categories":2891,"draft":2682,"year":2892,"series":6},"\u002Fblog\u002Fjson-web-token","Complete Guide to JWT","JSON Web Tokens are a very compact way to carry information. Learn about JWTs in depth, from its structure to when to use it.",[2680,2721],"2021-11-20",{"path":2894,"title":2895,"description":2896,"categories":2897,"draft":2682,"year":2898,"series":6},"\u002Fblog\u002Flearn-to-say-no","Learning to say No","Learn why it's important to say 'NO'. How it helps in increasing productivity and explore strategies for saying No",[2713,2712],"2022-04-09",{"path":2900,"title":2901,"description":2902,"categories":2903,"draft":2682,"year":2904,"series":6},"\u002Fblog\u002Flearn-unlearn-relearn","Learn - Unlearn - Relearn","Unlearning things to learn new is the way to grow. Discover how to do that!",[2699,2713],"2020-09-25",{"path":2906,"title":2907,"description":2908,"categories":2909,"draft":2682,"year":2910,"series":6},"\u002Fblog\u002Flinting-in-golang","Introduction to Linting in Go","Introduction to improving code quality using linting. Learn how to add linting in your Go projects.",[2637,2680],"2021-07-07",{"path":2912,"title":2913,"description":2914,"categories":2915,"draft":2682,"year":2916,"series":6},"\u002Fblog\u002Fload-balancing","Load Balancing 101","Complete guide on load balancers explaining the internal working and how does it help in making applications efficient.",[2643,2680],"2021-05-29",{"path":2918,"title":2919,"description":2920,"categories":2921,"draft":2682,"year":2922,"series":6},"\u002Fblog\u002Fmaking-decisions-the-right-way","Making Decisions: The right way","Decisions are hard! Learn how to make the right decisions always",[2699,2713],"2020-06-07",{"path":2924,"title":2925,"description":2926,"categories":2927,"draft":2682,"year":2929,"series":6},"\u002Fblog\u002Fmanage-logs-with-logrotate","Using Logrotate to manage logs","Learn how to use logrotate system utility to manage logs with example",[2928,2680],"Linux","2020-09-08",{"path":2931,"title":2932,"description":2933,"categories":2934,"draft":2682,"year":2935,"series":6},"\u002Fblog\u002Fmarshal-structs-golang","Marshal structs the right way: Golang","Why Golang marshals empty structs into your JSON instead of null, and how to marshal structs the right way.",[2637,2680],"2020-03-31",{"path":2937,"title":2938,"description":2939,"categories":2940,"draft":2682,"year":2941,"series":6},"\u002Fblog\u002Fnotes-almanack-naval","Book Notes : Almanack of Naval Ravikant","My notes\u002Fhighlights from Almanack of Naval Ravikant book by Eric Jorgenson",[2712,2713],"2020-10-17",{"path":2943,"title":2944,"description":2945,"categories":2946,"draft":2682,"year":2947,"series":6},"\u002Fblog\u002Fnotes-anything-you-want","Book Notes : Anything you want","My notes\u002Fhighlights from Anything you want book by Derek Sivers",[2712,2713],"2021-09-25",{"path":2949,"title":2950,"description":2951,"categories":2952,"draft":2682,"year":2954,"series":6},"\u002Fblog\u002Fnotes-getting-real","Book Notes : Getting Real","My notes and highlights from Getting Real by Jason Fried and David Heinemeier Hansson on building web applications.",[2712,2953],"Startups","2020-11-03",{"path":2956,"title":2957,"description":2958,"categories":2959,"draft":2682,"year":2960,"series":6},"\u002Fblog\u002Fnotes-hell-yeah-or-no","Book Notes : Hell Yeah or No","My notes\u002Fhighlights from Hell Yeah or No book by Derek Sivers",[2712,2713],"2020-09-16",{"path":2962,"title":2963,"description":2964,"categories":2965,"draft":2682,"year":2966,"series":6},"\u002Fblog\u002Fnotes-how-to-be-a-capitalist","Book Notes : How to Be a Capitalist Without Any Capital","My notes\u002Fhighlights from How to Be a Capitalist Without Any Capital by Nathan Latka",[2712,2953],"2020-01-07",{"path":2968,"title":2969,"description":2970,"categories":2971,"draft":2682,"year":2973,"series":6},"\u002Fblog\u002Fnotes-lean-b2b","Book Notes : Lean B2B","My notes and highlights from Lean B2B by Étienne Garbugli on assessing markets, building MVPs, and selling to businesses.",[2712,2972],"Entrepreneurship","2022-07-02",{"path":2975,"title":2976,"description":2977,"categories":2978,"draft":2682,"year":2980,"series":6},"\u002Fblog\u002Fnotes-lets-talk-money","Book Notes : Let's Talk Money","My notes and highlights from Let's Talk Money by Monica Halan on managing personal finances and savings.",[2712,2979],"Personal Finance","2021-02-26",{"path":2982,"title":2983,"description":2984,"categories":2985,"draft":2682,"year":2986,"series":6},"\u002Fblog\u002Fnotes-obviously-awesome","Book Notes : Obviously Awesome","My notes and highlights from Obviously Awesome by April Dunford on product positioning and marketing strategy.",[2712,2953],"2020-04-26",{"path":2988,"title":2989,"description":2990,"categories":2991,"draft":2682,"year":2993,"series":6},"\u002Fblog\u002Fnotes-refactoring-ui","Book Notes: Refactoring UI","My notes and highlights from Refactoring UI by Adam Wathan and Steve Schoger, full of practical design tips for engineers.",[2712,2992],"Design","2020-05-09",{"path":2995,"title":2996,"description":2997,"categories":2998,"draft":2682,"year":2999,"series":6},"\u002Fblog\u002Fnotes-rework","Book Notes: Rework","My notes and highlights from Rework by Jason Fried and David Heinemeier Hansson on a better way to succeed in business.",[2712,2953],"2021-04-14",{"path":3001,"title":3002,"description":3003,"categories":3004,"draft":2682,"year":3006,"series":6},"\u002Fblog\u002Fone-on-one-meetings","Guide to Effective 1:1 Meetings","One on One meetings are important for your personal & professional growth. Learn how to master 1:1s with your manager and peers.",[3005,2699],"Career","2023-03-05",{"path":3008,"title":3009,"description":3010,"categories":3011,"draft":2682,"year":3012,"series":6},"\u002Fblog\u002Fpersonal-okrs","Personal OKRs for Success","Why one should set personal OKRs and how to achieve success with them",[2699,2713],"2020-06-27",{"path":3014,"title":3015,"description":3016,"categories":3017,"draft":2682,"year":3019,"series":6},"\u002Fblog\u002Fpoker-tips","Poker Tips: Johns Hopkins Poker Class","Notes from Johns Hopkins poker course. This guide will help you improve in Poker and win some large pots.",[2713,3018],"Poker","2020-06-13",{"path":3021,"title":3022,"description":3023,"categories":3024,"draft":2682,"year":3025,"series":6},"\u002Fblog\u002Fpomodoro","Get work done: The Pomo Way","Learn to focus and get productive by following the Pomodoro Technique",[2699],"2020-10-24",{"path":3027,"title":3028,"description":3029,"categories":3030,"draft":2682,"year":3031,"series":6},"\u002Fblog\u002Fpostgres-constraints","Postgres Constraints","Constraints are line of defense for database. Explore various types of constrainsts in postgres",[2847,2680],"2020-11-07",{"path":3033,"title":3034,"description":3035,"categories":3036,"draft":2682,"year":3037,"series":6},"\u002Fblog\u002Fppf-explained","PPF Explained","Learn basics about Public Provident Fund and why you should invest",[2713,2979],"2020-12-24",{"path":3039,"title":3040,"description":3041,"categories":3042,"draft":2682,"year":3043,"series":6},"\u002Fblog\u002Fproductivity-chrome-extensions","Boost Productivity with Chrome Extensions","Utitizing chrome extensions to boost your productivity!",[2699,2722,2721],"2020-04-24",{"path":3045,"title":3046,"description":3047,"categories":3048,"draft":2682,"year":3049,"series":6},"\u002Fblog\u002Fproductivity-in-vscode","Improve your productivity with VS Code","Key VS Code features like the integrated terminal, shortcuts, and extensions that improved my everyday productivity.",[2699,2680],"2020-03-12",{"path":3051,"title":3052,"description":3053,"categories":3054,"draft":2682,"year":3055,"series":6},"\u002Fblog\u002Freading-101","Improving Reading 101","Why reading matters, how to build a reading habit, and what to read next - from my own journey into books.",[2712,2713],"2020-04-04",{"path":3057,"title":3058,"description":3059,"categories":3060,"draft":2682,"year":3061,"series":6},"\u002Fblog\u002Freverse-proxy","Understanding Reverse Proxy","Learn about reverse proxy, how it is different from forward proxy and explore advantages of using it in system design.",[2643,2680],"2021-10-03",{"path":3063,"title":3064,"description":3065,"categories":3066,"draft":2682,"year":3067,"series":6},"\u002Fblog\u002Frunning-periodic-background-task-golang","Running periodic background tasks in Golang","How to run periodic background tasks in Golang by combining cron-style scheduling with background execution.",[2637,2680],"2019-11-21",{"path":3069,"title":3070,"description":3071,"categories":3072,"draft":2682,"year":3073,"series":6},"\u002Fblog\u002Fsessions-in-golang","Sessions using Golang and Redis","How cookies and sessions work, and how to implement persistent login sessions in Golang using Redis.",[2637,2847,2680],"2020-02-25",{"path":3075,"title":3076,"description":3077,"categories":3078,"draft":2682,"year":3079,"series":6},"\u002Fblog\u002Fsolid-dry-kiss-yagni","Solid Dry Kiss Yagni","An introduction to the SOLID, DRY, KISS, and YAGNI principles and how they help you write cleaner, robust code.",[2735],"2020-07-17",{"path":3081,"title":3082,"description":3083,"categories":3084,"draft":2682,"year":3085,"series":6},"\u002Fblog\u002Fstack-in-golang","Implement Stack in Golang","Learn how to implement stack data structure in Golang (Full code)",[2637,2680],"2020-09-14",{"path":3087,"title":3088,"description":3089,"categories":3090,"draft":2682,"year":3091,"series":6},"\u002Fblog\u002Fstart-oss-today","Start your Open Source journey today","Start your OSS journey with intro to GIT. Participate in Hacktoberfest!",[2785,2680],"2020-09-19",{"path":3093,"title":3094,"description":3095,"categories":3096,"draft":2682,"year":3098,"series":6},"\u002Fblog\u002Fsticky-social-bar","Sticky social share component in HTML","Learn how to build a social media sharing component in HTML and add it to your website.",[2680,3097],"Frontend","2021-02-05",{"path":3100,"title":3101,"description":3102,"categories":3103,"draft":2682,"year":3104,"series":6},"\u002Fblog\u002Fterm-insurance","Term insurance Simplified","Everything you need to know before you buy a term insurance.",[2713,2979],"2020-11-29",{"path":3106,"title":3107,"description":3108,"categories":3109,"draft":2682,"year":3111,"series":6},"\u002Fblog\u002Fterminal-output-with-redirection","Handling terminal outputs with Redirection","Learn how to handle terminal outputs with Redirection and saving it to files",[2928,3110,2680],"Terminal","2020-09-06",{"path":3113,"title":3114,"description":3115,"categories":3116,"draft":2682,"year":3117,"series":6},"\u002Fblog\u002Fthink-and-grow-rich","Book Notes: Think and Grow Rich","My notes and highlights from Think and Grow Rich by Napoleon Hill, covering its process for building wealth.",[2712,2713],"2020-05-19",{"path":3119,"title":3120,"description":3121,"categories":3122,"draft":2682,"year":3123,"series":6},"\u002Fblog\u002Ftransactions-postgres-golang","Transactions on Postgres with Golang","Performing Postgres database operations in Golang with GORM, from basic queries to full transaction support.",[2637,2847,2680],"2020-03-18",{"path":3125,"title":3126,"description":3127,"categories":3128,"draft":2682,"year":3129,"series":6},"\u002Fblog\u002Fwaitgroups-in-golang","WaitGroups in Golang","Learn about WaitGroups in golang and how to use them to perform concurrent operations without blocking the main thread.",[2637,2680],"2022-05-31",{"path":3131,"title":3132,"description":3133,"categories":3134,"draft":2682,"year":3136,"series":6},"\u002Fblog\u002Fwhat-i-use","What I Use: Products and Softwares","List of what I use in my day to day life ranging from terminal, editors, softwares, devices to accessories",[2713,3135],"Tech","2024-06-01",{"path":3138,"title":3139,"description":3140,"categories":3141,"draft":2682,"year":3142,"series":6},"\u002Fblog\u002Fyear-in-review-2020","Year in Review: 2020","It's a wrap! 2020 was a crazy year, See how my year went!",[2713],"2020-12-31",{"path":3144,"title":3145,"description":3146,"categories":3147,"draft":2682,"year":3148,"series":6},"\u002Fblog\u002Fyear-in-review-2021","Year in Review: 2021","It's a wrap! 2021 was a mixed bag, full of ups and downs. Key Goal for 2022: Start now!",[2713],"2021-12-31",1787743427758]