-2

Let’s imagine system like Garmin connect, you run, record your workout and then once you finish workout is uploaded to the system and being analyzed. Based on analysis you can receive badge: for 5 km run, for 10 km run, for 3 runs in a row (3 days), for run in the morning etc. I assume that it is possible to enter new rule definition without coding or at least without recompilation of the system. Probably similar method could be used for defining rules for promotions in e-stores. Do you know any battle tested pattern to design something that may help here?

I’m not trying to solve particular problem here, I’m just showing the use case of common business case that you can map to whatever you want: baggie, promotion, medicine to take etc.

1
  • 4
    Why do you think new badges wouldn't require additional coding? Instead of asking for a pattern that fits a vague description of a product, please edit your question to include more details about the problem you are trying to solve. Nov 19, 2022 at 22:21

1 Answer 1

2

You could design a rule engine. E.g. you might start with a data model:

class BadgeRule { Condition, Name }
interface Condition { bool MatchesUser(User u); }
class DistanceCondition { MinimumDistance; ... }

badges = [
  { Name = "5km", Condition = DistanceCondition { MinimumDistance = 5'000 } }
  { Name = "10km", Condition = DistanceCondition { MinimumDistance = 10'000 } }
]

But as you want to design more complex rules, you'll likely have to do additional development work to make that information available to the rule engine. Also, there's a risk of running into Greenspun's Tenth Rule, that your rule engine eventually becomes so complex that it's just an ad-hoc programming language.

Instead, you could embed an existing scripting language (e.g. JavaScript, Lua, Python) into your application, allowing new rules to be defined as plugins without having to redeploy the software. This can be quite reasonable and secure, actually (e.g. consider a Wasm sandbox). But it requires that you create suitable bindings between the scripting language and your internal data model. In systems where controlling access to the data isn't important, just letting the plugin define custom SQL queries might be an easy way out.

Many systems don't need this degree of configurability. In particular where the rules are defined by the same organization that creates and runs the software, it could be more appropriate to just modify and re-deploy the software. At the very latest since the popularization of “DevOps”, the software development community now has really good ideas about making deployments fairly painless.

Letting the rule implementation involve coding can also help the new badge go through a Q&A process, to ensure that it works. Testability is often limited in “low-code” systems or rule engines, where new rules might have to be tried out in prod.

5
  • Thanks a lot, also please have a look at this: github.com/microsoft/RulesEngine. What do you think about it?
    – Snorlax
    Nov 20, 2022 at 11:35
  • Also if it would require coding then which design latter/technique would you use? Each badge would be a separate class and then when an event is propagated “run completed” code will somehow iterate through instances of all classes of badge and check if it is ok? Any hints, keywords what I can read about?
    – Snorlax
    Nov 20, 2022 at 11:39
  • @Snorlax The Microsoft rule engine is a great example of the difficulties here. It allows you to define rules/conditions in a subset of C#. Super flexible, no need to create bindings. But I'm not sure whether there are meaningful security boundaries. Maybe that's useful for your scenario, maybe not.
    – amon
    Nov 20, 2022 at 12:23
  • @Snorlax For just writing the code explicitly, I have no particular architecture recommendations. Badges or discounts are part of your ordinary business logic. So I would start by putting the code for checking whether a badge should be created into a function, and calling the function wherever appropriate. (cont)
    – amon
    Nov 20, 2022 at 12:23
  • 1
    Once you have a couple such functions, you can think about how to architect those better. Perhaps some design patterns like Chain of Responsibility or Observer become appropriate. Perhaps the badge processing logic should run in an event-driven manner as a separate microservice. Perhaps all actual badges are very similar, enabling you to move to a configuration-driven approach instead. But don't start by over-engineering. Start with a simple solution, and then gradually discover better designs through refactoring.
    – amon
    Nov 20, 2022 at 12:24

Not the answer you're looking for? Browse other questions tagged or ask your own question.