Business Rules with

      Brick
          brian d foy
  Nordic Perl Workshop 2007
Field validation is too low-level

 Business rules are high-level

   Code is for programmers

Connect coders and business
Field validation
  is too simple
    is_number( $age );

cookie_expired( $cookie );

amount_ok( $n + $m + $o );

    requi...
Errors too vague

    “Number is out of range”

“Password has invalid characters”

      “Field foo is missing”
Helpful messages

“Number was %s but needs to be %s”

“Password can only be alphabetic, but
            I found %s”

 “Fie...
Loose coupling

Remove business logic from code

  Avoid lock-in to technology

     Separate architecture
Data::FormValidator
Perfectly fine for simple things

        Based on fields

Relationships tough to specify

     Poor e...
Easy for programmers
        presence

      right format

      allowed value

       one-to-one

     ignore business
Hard for business
Many-to-many relationships

 Out-of-band information

      Legacy rules

       Exceptions

     Don’t ...
Programmers think...
Business is...
Full validation
    Presence

      Format

    Valid Value

   Relationships

   Right Value
Programmers
 write code


No one else does
Programmers
 read code


No one else does
Business people
 know the rules


No one else does
Connect both sides
Describe the validation

   Turn it into code

Explain the validation

 Apply it to input data

  Explain the results
Brick
Business

Rules

in

Closures,

‘Kay
A rule is simple

Complex rules compose simple rules

  Rules divorced from input fields

 Re-useable rules close over setup
Still alpha

In active use at a major client

 Detailed, user-defined error
          messages
Describe the situation
     Make it look less like code
@Description = (

    [ label => method_name => %setup ],

	

 	

...
Explain profile
some_label
   __compose_AND
   __compose_ONE_OF
            __fields_are_something
            __compose_A...
Putting it together
@Description = (

    [ label => constraint_name => %setup ],

	

 	

 );

my $Brick = Brick->new();

...
Results object
             Tree data structure

 Brick::Result can play with it

@Results = (

    [ label => [ 1 | 0 ] =...
Error Hash

$errors = [

	

 { handler => $method1, message => ...,

       errors => [ ... ] },

	

 { handler => $method...
Describe what happened
just_right: passed three_digit_odd_number

too_long: failed three_digit_odd_number
    long_number:...
The brick interface

  Closes over setup data

  Has access to all input

  True if everything is okay

die with a referen...
A validation routine
my $sub = sub {

  my $input = shift;

  return 1 if exists $input->{cat};

  die { # result error me...
Add to bucket
    Put it in the communal bucket

Use the brick in different relationships
   $brick = $bucket->add_to_buck...
Compose bricks
sub _us_postal_code_format
	

 {
	

 my( $bucket, $setup ) = @_;
	

	

 $setup->{exact_length} = 5;
	

	

 ...
Make trees
my $postal   = $brick->_postal_code_format( { ... } );
my $street   = $brick->_address_format( { ... } );
my $u...
Validation profile
 some_label
__compose_AND
  __compose_ONE_OF
                   __fields_are_something
                ...
Get the results
foreach my $item ( @profile ) {
  my $label   = $item->[0];
  my $method = $item->[1];
  my $result =
    ...
How to use Brick

     Plug-in validation (MVC)

        Subclass to adapt

Store all business logic separately
Didn’t cover...

       Filters

     Selectors

     Subclasses

Configuration as code
Conclusion

Many-to-many relationships

Descriptive error messages

    Replay validation
Upcoming SlideShare
Loading in...5
×

Business Rules with Brick

6,126

Published on

My introduction to Brick, my Perl module to handle complex rule validation using composed closures.

Published in: Business, Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
6,126
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Business Rules with Brick

  1. 1. Business Rules with Brick brian d foy Nordic Perl Workshop 2007
  2. 2. Field validation is too low-level Business rules are high-level Code is for programmers Connect coders and business
  3. 3. Field validation is too simple is_number( $age ); cookie_expired( $cookie ); amount_ok( $n + $m + $o ); required( @fields );
  4. 4. Errors too vague “Number is out of range” “Password has invalid characters” “Field foo is missing”
  5. 5. Helpful messages “Number was %s but needs to be %s” “Password can only be alphabetic, but I found %s” “Field bar requires field foo, which was blank”
  6. 6. Loose coupling Remove business logic from code Avoid lock-in to technology Separate architecture
  7. 7. Data::FormValidator Perfectly fine for simple things Based on fields Relationships tough to specify Poor error reporting Tried to subclass Tried to refactor
  8. 8. Easy for programmers presence right format allowed value one-to-one ignore business
  9. 9. Hard for business Many-to-many relationships Out-of-band information Legacy rules Exceptions Don’t know Perl
  10. 10. Programmers think...
  11. 11. Business is...
  12. 12. Full validation Presence Format Valid Value Relationships Right Value
  13. 13. Programmers write code No one else does
  14. 14. Programmers read code No one else does
  15. 15. Business people know the rules No one else does
  16. 16. Connect both sides
  17. 17. Describe the validation Turn it into code Explain the validation Apply it to input data Explain the results
  18. 18. Brick
  19. 19. Business Rules in Closures, ‘Kay
  20. 20. A rule is simple Complex rules compose simple rules Rules divorced from input fields Re-useable rules close over setup
  21. 21. Still alpha In active use at a major client Detailed, user-defined error messages
  22. 22. Describe the situation Make it look less like code @Description = ( [ label => method_name => %setup ], ); Might come from a config file
  23. 23. Explain profile some_label __compose_AND __compose_ONE_OF __fields_are_something __compose_AND __compose_AND _value_length_is_equal_to_greater_than _value_length_is_equal_to_less_than _is_only_decimal_digits _is_only_decimal_digits __compose_ONE_OF __fields_are_something __compose_AND _is_YYYYMMDD_date_format _is_valid_date __compose_ONE_OF __fields_are_something __compose_AND _is_YYYYMMDD_date_format _is_valid_date
  24. 24. Putting it together @Description = ( [ label => constraint_name => %setup ], ); my $Brick = Brick->new(); my $profile = $Brick->profile_class->new( @Description ); my $result = $Brick->apply( $profile, %Input );
  25. 25. Results object Tree data structure Brick::Result can play with it @Results = ( [ label => [ 1 | 0 ] => %errors ], );
  26. 26. Error Hash $errors = [ { handler => $method1, message => ..., errors => [ ... ] }, { handler => $method2, message => ..., errors => [ ... ] }, ... ];
  27. 27. Describe what happened just_right: passed three_digit_odd_number too_long: failed three_digit_odd_number long_number: _value_length: [12345] isn't 3 or fewer characters too_short: failed three_digit_odd_number short_number: _value_length: [13] isn't 3 or more characters even_number: failed three_digit_odd_number even_number: _matches_regex: [24] did not match the pattern even_number: _value_length: [24] isn't 3 or more characters two_fields: failed twofer even_number: _matches_regex: [24] did not match the pattern short_number: _value_length: [13] isn't 3 or more characters
  28. 28. The brick interface Closes over setup data Has access to all input True if everything is okay die with a reference if it isn’t
  29. 29. A validation routine my $sub = sub { my $input = shift; return 1 if exists $input->{cat}; die { # result error message handler => 'Cat key check', failed_field => 'cat' message => quot;No field named 'cat'quot;, }; }
  30. 30. Add to bucket Put it in the communal bucket Use the brick in different relationships $brick = $bucket->add_to_bucket( { name => 'cat key checker', description => quot;Has field named 'cat'quot;, code => $sub } );
  31. 31. Compose bricks sub _us_postal_code_format { my( $bucket, $setup ) = @_; $setup->{exact_length} = 5; my $composed = $bucket->__compose_satisfy_all( $bucket->_value_length_is_exactly( $setup ), $bucket->_is_only_decimal_digits( $setup ), ); }
  32. 32. Make trees my $postal = $brick->_postal_code_format( { ... } ); my $street = $brick->_address_format( { ... } ); my $usps = $brick->_usps_check( { ... } ); my $address = $brick->__compose_satisfy_all( $postal, $street, $usps ); my $basket = $brick->__compose_satisfy_all( ... ); my $order = $brick->__compose_satisfy_all( $address, $basket, ... );
  33. 33. Validation profile some_label __compose_AND __compose_ONE_OF __fields_are_something __compose_AND __compose_AND _value_length_is_equal_to_greater_than _value_length_is_equal_to_less_than _is_only_decimal_digits _is_only_decimal_digits __compose_ONE_OF __fields_are_something __compose_AND _is_YYYYMMDD_date_format _is_valid_date __compose_ONE_OF __fields_are_something __compose_AND _is_YYYYMMDD_date_format _is_valid_date
  34. 34. Get the results foreach my $item ( @profile ) { my $label = $item->[0]; my $method = $item->[1]; my $result = eval{ $brick->$method->( $input ) } my $eval_error = $@; $result = 0 if ref $eval_error; push @results, [ $label, $method, $result, $@ ]; }
  35. 35. How to use Brick Plug-in validation (MVC) Subclass to adapt Store all business logic separately
  36. 36. Didn’t cover... Filters Selectors Subclasses Configuration as code
  37. 37. Conclusion Many-to-many relationships Descriptive error messages Replay validation

×