Business Rules with Brick

6,242
-1

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,242
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

×