News for hackers. Stuff that matters.
Re:Using the Specification Pattern to Build a Data-Driven Ru... by NicoJuicy on Tuesday March 24, 2020 @09:26AM (#22674624)
Important to mention, but when I checked out the specification pattern. It's useful to know that it can only be applied if your programming language of choice supports expression trees ( eg. C# )
Re:Using the Specification Pattern to Build a Data-Driven Ru... by TeMPOraL on Tuesday March 24, 2020 @02:09PM (#22677080)
That's not true. You don't need expression trees (or equivalent), you can walk and interpret the specification directly. Expression trees are just a trick to compile this as code. But you can do that in any language that can compile code at runtime (of which there are, unfortunately, few).

From Common Lisp's perspective, the example given is just:

  `(and (> divident 0.025)
        (< payout-ratio 0.5)
        (or (< pe-ratio 20)
            (< price 130)))
You can walk that tree recursively as-is, calling appropriate operators and substituting correct values.

Or, you can wrap it in a (lambda (divident payout-ratio pe-ratio price) ...) and pass to (compile ...), and get a piece of executable code. With perhaps a line or two of book-keeping (that can be added by your code, and not necessarily typed in by the user), you can make the rule declare which variables it cares about. So a full example:

  (let* ((rule '(lambda (data)
                  (destructuring-bind (&key divident payout-ratio pe-ratio price &allow-other-keys) data
                    (and (> divident 0.025)
                         (< payout-ratio 0.5)
                         (or (< pe-ratio 20)
                             (< price 130))))))
         (executable-rule (compile nil rule)))
    (list (funcall executable-rule '(:divident 0.5 :payout-ratio 0.4 :pe-ratio 50 :price 10 :other-data 42))
          (funcall executable-rule '(:divident 0.5 :payout-ratio 0.5 :pe-ratio 50 :price 10 :other-data 42))))
  
  ;; Result:
  (T NIL)
Re:Using the Specification Pattern to Build a Data-Driven Ru... by NicoJuicy on Tuesday March 24, 2020 @05:19PM (#22679134)
Please read my comment about using the specification-pattern with sql :)

Which, for me, is 90% of the use-cases

Re:Using the Specification Pattern to Build a Data-Driven Ru... by jdmichal on Tuesday March 24, 2020 @09:56AM (#22674769)
That's just an optimization layer, though. I actually have a hard time telling this apart from `java.util.function.Predicate` with its default `and`, `or`, and `negate` methods...

I can certainly understand using something like this when your users are building rules, because you don't know what they want to build so you just provide the base implementations and the operators. But if engineers are implementing all the logic, it seems like the criticisms called out in Wikipedia regarding obfuscation and re-implementation of basic operators would apply.

https://en.wikipedia.org/wiki/Specification_pattern#Criticis...

Re:Using the Specification Pattern to Build a Data-Driven Ru... by NicoJuicy on Tuesday March 24, 2020 @11:21AM (#22675307)
Predicates are also related to expression trees in my opinion
Re:Using the Specification Pattern to Build a Data-Driven Ru... by Merad on Tuesday March 24, 2020 @01:07PM (#22676408)
A predicate is really just a test that accepts an input and produces true or false. The expression only becomes necessary when you want to translate the predicate somehow (e.g. to SQL).
Re:Using the Specification Pattern to Build a Data-Driven Ru... by emidln on Tuesday March 24, 2020 @09:38AM (#22674690)
What is an expression tree? I've done this with arrays of structs in C as well as nested dictionaries in python, and sexps in both lisp and python. I could do it trivially in x86 if needed. Maybe sexps are "expression trees", but it seems almost any language can implement this pattern. It was much nicer with data literals than without, but data literals aren't a prerequisite.
Re:Using the Specification Pattern to Build a Data-Driven Ru... by jdmichal on Tuesday March 24, 2020 @09:59AM (#22674785)
Expression trees are a .NET capability to compile a series of expressions during runtime. It's not required for this at all; it's just an optimization. It allows the complex tree of Specification objects to be compiled down into a simple delegate function, rather than evaluating by walking the tree.
Re:Using the Specification Pattern to Build a Data-Driven Ru... by NicoJuicy on Tuesday March 24, 2020 @11:26AM (#22675357)
Well, then your use-case is different than mine. Since I mostly use specification pattern on top of a orm layer.

Orm's support expression trees ( eg, nhibernate,...)

So the specifications pattern for my use-case require expression trees.

There are workarounds ofc, but translating specifications to Sql is not the desired use-case of the pattern.

Specifications make it easy to have a 100% equal business filter ( that translate it to Sql through the ORM) and making it testable.

- Specification.AssertAll(resultset, "not all elements are valid according to this specification");

( Using pseudocode )