SlideShare a Scribd company logo
1 of 109
Data::Manager
Just because your users may suck
  doesn’t mean you should, too
Jay Shirley



• Infinity Interactive   http://www.infinityinteractive.com

• Cold Hard Code        http://www.coldhardcode.com/

• j@shirley.im          http://j.shirley.im/
A Brief Introduction
A rant, perhaps.
Definitely a diatribe.
Tools
Make us better.
Do one thing really well.
Used together.
Synergy!
Example: Catalyst
Catalyst grows Tools
    HTTP::Body, others
Forms
WTF is a Form?
Modern Perl
Modern Applications
Mobile. JavaScript. Apps.
Forms are dead.
Data Validation
      =
Form Generator
Data Validation
      ≠
Form Generator
2011
1999 called...
 they don’t
 want their
  CGI.pm
    back
Tools should grow with you.
Don’t marry tools.
Easy to get away from.
Single Purpose!
Imagine in 5 years…
Why is old embarrassing?
How to pick a tool.
Don’t judge a tool by typing.
Opinions are ok.
Leverages other tools.
Doesn’t impose.
Introducing (finally)
Data::Manager
A very good way of managing incoming data.
In case you missed it…
Bad:
              Error Message!
              Error Message!




  Line Item 1             Line Item 1
Delivery Options          Gift Options




  Line Item 2             Line Item 2
Delivery Options          Gift Options
Good:

Error Message!

  Line Item 1       Line Item 1
Delivery Options    Gift Options




                   Error Message!

  Line Item 2       Line Item 2
Delivery Options    Gift Options
GETTING STARTED
my $dv = Data::Verifier->new(…);
my $results = $dv->verify(%params);
if($results->success) {
    # o/
} else {
    # :(
}
Data::Manager
my $dm = Data::Manager->new;
my $verifier = Data::Verifer->new(...);

$dm->set_verifier('address', $verifier);

$dm->verify('address', $data);

if ( $dm->success ) {
    # o/
} else {
    # :(
}
Data::Manager Scopes
my $dm = Data::Manager->new;
my $verifier = Data::Verifer->new(...);

$dm->set_verifier('address', $verifier);

$dm->verify('address', $data);

if ( $dm->success ) {
    # o/
} else {
    # :(
}
Data::Manager and Messages


$dm->verify('address', $data);

my $messages = $dm->messages_for_scope('address');
Data::Manager and Results


$dm->verify('address', $data);

my $results = $dm->get_results('address');

# $results can serialize
# $results is Data::Verifier::Results
A Year in Review

• Data::Verifier
  • 15+ releases and now version 0.47
• Data::Manager
  • 2 releases, could use more. 0.07
• Message::Stack
  • Stable API, simple workhorse. 0.19.
Where we are now.

• Elegant handling of multiple scopes.
• We know how to use this stuff better.
• The code hasn’t changed that much.
• API is stable.
• Supports more things as needed. Fork it!
From A to Z
In the beginning…
Markup by hand
Inconsistent
Subtle or just broken
Became complex
Hard to change
Married to bad/old markup
Solution?
Not form generators!
Macros!
Form Template:
<fieldset>
 <legend>[% c.loc('About You') %]</legend>
 [%
 context.scope = 'person';
 text_field({ label => 'Your Name',
      name => 'name', hint => 'Your Name',
      required => 1 });
 text_field({ label => 'Your Email', name => 'email',
      hint => 'you@company.com', type='email',
      required => 1,
      more => 'This will be your username.' });
 context.scope = 'identity';
 text_field({ label => 'Password', type => 'password',
      name => 'password', required => 1 });
 text_field({ label => 'Confirm Password',
      type => 'password',
      name => 'confirm_password', required => 1 });
%]
</fieldset>
Results in
“Person” Scope
“Identity” Scope
And what we want
We get.
Scopes
<fieldset>
 <legend>[% c.loc('About You') %]</legend>
 [%
 context.scope = 'person';
 text_field({ label => 'Your Name',
      name => 'name', hint => 'Your Name',
      required => 1 });
 text_field({ label => 'Your Email', name => 'email',
      hint => 'you@company.com', type=>'email',
      required => 1,
      more => 'This will be your username.' });
 context.scope = 'identity';
 text_field({ label => 'Password', type => 'password',
      name => 'password', required => 1 });
 text_field({ label => 'Confirm Password',
      type => 'password',
      name => 'confirm_password', required => 1 });
%]
</fieldset>
Just markup.

• Easily define the layout form.
• Macros make it sensible.
• Markup for forms can be provided by designers
 and easily adapted.

• Multiple macro “styles” can be included.
We have the biggest Macros
       of them all.

• Too big to put on a slide, so they’re on github.
• Well defined.
• Easy to use.
• Not that hard to update.
The gist of the macro

• Too big to put on a slide (288L).
• Ask me to see them, happy to share.
• Looks at context.scope, determines:
  • Message::Stack scope.
  • Data::Verifier::Results
Priorities:


• Good Ideal user experience.
Priorities:


• Good Ideal user experience.
• Maximize reliability.
Priorities:


• Good Ideal user experience.
• Maximize reliability.
• Optimize for use, hide the complexity.
CRUD ≠ User Experience

• CRUD principles are awesome.
CRUD ≠ User Experience

• CRUD principles are awesome.
• Behind the scene.
CRUD ≠ User Experience

• CRUD principles are awesome.
• Behind the scene.
• Many forms encompass multiple objects.
CRUD ≠ User Experience

• CRUD principles are awesome.
• Behind the scene.
• Many forms encompass multiple objects.
• Making a user view 3 pages to update 3 objects
 is bad form.
Build a UI first.
Pick method and tools
      second.
Our tools let us pick methods
Priorities:


• Ideal user experience.
• Maximize reliability.
• Optimize for use, hide the complexity.
Reliability


• Don’t think about errors.
• Convention makes them happen.
• Users know what to expect.
• Plans + Simple API = Reliability
Having a plan means you
   never have to say sorry.
Not really, but it should stop you from having to
                  apologize twice.
Priorities:


• Ideal user experience.
• Maximize reliability.
• Optimize for use, hide the complexity.
Optimize for use.
Save yourself agony with a testable, nice and clean
                       API
Optimize for use


• Write code behind a clean API.
• Make methods that do smaller work.
• That gives us easy code.
• This is a different topic.
Optimized for use:
# In your controller: (see Catalyst::Action::REST for *_POST)
sub root_POST {
    my ( $self, $c ) = @_;
    my $data    = $c->req->params;
    my $results = $c->model(‘DataManager’)->verify($scope,
$data);

    unless ( $results->success ) {
        $c->message({
            type => ‘error’, message => ‘You Fail‘
        });
        $c->res->redirect(
            $c->uri_for_action('/object/create_form') );
        $c->detach;
    }
    # Success, store from $results, verify and redirect.
}
Simple Model
package MyApp::Model::DataManager;

use Moose;
with 'Catalyst::Component::InstancePerContext';

has 'profiles' => ( ... );

sub build_per_context_instance {
    my ( $self, $c ) = @_;

    my $dm = Data::Manager->new;
    foreach my $scope ( $self->scopes ) {
         $dm->set_verifier(
             $scope => Data::Verifier->new( $self-
>get_profile($scope) )
        );
    }
    $dm;
}
Profiles

has 'profiles' => (
    default => sub { {
       'login' => {
            filters => [   qw(trim) ],
            profile => {
                username   => {
                    type   => 'Str', required => 1,
                },
                password   => {
                    type   => 'Str', required => 1,
                }
            }
        },
Going Further
(with type constraints)


   username => {
       type        => MyEmailType,
       required    => 1,
       coerce      => 1,
   },
Type Checking


• Handles coercion (or not)
• Verifies if data is of type
• Emits “invalid” error in results if invalid.
extend Data::Manager
• Add your own methods.
• Make it better.
• Some ideas:
  • all_valids, hashref of all valid fields.
  • data_for_scope, hashref of fields in scope.
  • error_scopes, list of scopes needing
    attention.
extend Data::Manager


• Setup defaults for verifiers by scope.
• By DBIC result sources.
• By Catalyst models.
• Lots of options.
Example: Checking
   uniqueness
 An often broken endeavor.
Issues:


• Must filter out ‘$self ’ from the result set.
• Must then load $self.
• Must figure out create vs. update.
A simple unique check

my $unique_check = sub {
    my $r = shift;
    my $user = $r->get_value('username');
    my $id   = $r->get_value('id');
    my $rec = $c->model('DB::User')
        ->search({ username => $user })->first;
    return 1 if not defined $rec;
    return 1 if $rec->id == $id;
    return 0;
};
A Problem
Difficulty in testing.


• Verifier doesn’t know the database.
• Verifier shouldn’t know the database.
• Modify verification profiles where it makes
 sense.
Inserting
sub build_per_context_instance {
    my ( $self, $c ) = @_;

    my $unique_check = sub { ... };
    my $dm = Data::Manager->new;
    foreach my $scope ( $self->scopes ) {
        $dm->set_verifier(
            $scope => Data::Verifier->new( $self-
>get_profile($scope) )
        );
    }

    $dm->get_verifier('create_account')
        ->profile->{username}->{post_check} = $unique_check;

    $dm;
}
On a user object…
sub build_per_context_instance {
    my ( $self, $c ) = @_;

    my $unique_check = $c->model(‘DB::User’)->unique_check;
    my $dm = Data::Manager->new;
    foreach my $scope ( $self->scopes ) {
        $dm->set_verifier(
            $scope => Data::Verifier->new( $self-
>get_profile($scope) )
        );
    }

    $dm->get_verifier('create_account')
        ->profile->{username}->{post_check} = $unique_check;

    $dm;
}
Not ideal


• Can add same check for backend tools
• Access in similar fashion
• Verification profiles are modifiable
Still optimized for use:
# Same controller!
sub create_account_POST {
    my ( $self, $c ) = @_;
    my $data    = ‘create_account’;
    my $data    = $c->req->params;
    my $results = $c->model(‘DataManager’)->verify($scope,
$data);

    unless ( $results->success ) {
        $c->message({
            type => ‘error’, message => ‘You Fail‘
        });
        $c->res->redirect(
            $c->uri_for_action('/create_account') );
        $c->detach;
    }
    # Success, store from $results, verify and redirect.
}
Changing validation doesn’t
      change code.
Changing validation shouldn’t
       change code.
.* just works.
(you just have to use it)
Thank you.
Please think about your applications.
     Think about the problems.
          Fix the problems.

More Related Content

What's hot

Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojobpmedley
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowKacper Gunia
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにYuya Takeyama
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
 
Smolder @Silex
Smolder @SilexSmolder @Silex
Smolder @SilexJeen Lee
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2Kacper Gunia
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionIan Barber
 
Teaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersTeaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersIan Barber
 
Keeping objects healthy with Object::Exercise.
Keeping objects healthy with Object::Exercise.Keeping objects healthy with Object::Exercise.
Keeping objects healthy with Object::Exercise.Workhorse Computing
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Kang-min Liu
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationWorkhorse Computing
 
Perl web app 테스트전략
Perl web app 테스트전략Perl web app 테스트전략
Perl web app 테스트전략Jeen Lee
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportBen Scofield
 

What's hot (20)

Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojo
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 
My Development Story
My Development StoryMy Development Story
My Development Story
 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
 
Smolder @Silex
Smolder @SilexSmolder @Silex
Smolder @Silex
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2
 
Debugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 VersionDebugging: Rules And Tools - PHPTek 11 Version
Debugging: Rules And Tools - PHPTek 11 Version
 
Perl5i
Perl5iPerl5i
Perl5i
 
Teaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersTeaching Your Machine To Find Fraudsters
Teaching Your Machine To Find Fraudsters
 
Bag of tricks
Bag of tricksBag of tricks
Bag of tricks
 
Keeping objects healthy with Object::Exercise.
Keeping objects healthy with Object::Exercise.Keeping objects healthy with Object::Exercise.
Keeping objects healthy with Object::Exercise.
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command InterpolationBSDM with BASH: Command Interpolation
BSDM with BASH: Command Interpolation
 
Perl web app 테스트전략
Perl web app 테스트전략Perl web app 테스트전략
Perl web app 테스트전략
 
Agile database access with CakePHP 3
Agile database access with CakePHP 3Agile database access with CakePHP 3
Agile database access with CakePHP 3
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack Support
 
Metadata-driven Testing
Metadata-driven TestingMetadata-driven Testing
Metadata-driven Testing
 

Similar to Building Better Applications with Data::Manager

Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015CiaranMcNulty
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress DeveloperJoey Kudish
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Michelangelo van Dam
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007Rabble .
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I thinkWim Godden
 
Drupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary EditionDrupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary Editionddiers
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsMike Subelsky
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormMichelangelo van Dam
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
Persistant Cookies and LDAP Injection
Persistant Cookies and LDAP InjectionPersistant Cookies and LDAP Injection
Persistant Cookies and LDAP InjectionMaulikLakhani
 
2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD WorkshopWolfram Arnold
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From IusethisMarcus Ramberg
 

Similar to Building Better Applications with Data::Manager (20)

Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015Why Your Test Suite Sucks - PHPCon PL 2015
Why Your Test Suite Sucks - PHPCon PL 2015
 
Ruby For Startups
Ruby For StartupsRuby For Startups
Ruby For Startups
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress Developer
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007Introduction to Active Record at MySQL Conference 2007
Introduction to Active Record at MySQL Conference 2007
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
 
Drupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary EditionDrupal - dbtng 25th Anniversary Edition
Drupal - dbtng 25th Anniversary Edition
 
QA for PHP projects
QA for PHP projectsQA for PHP projects
QA for PHP projects
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
SOLID Ruby, SOLID Rails
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Persistant Cookies and LDAP Injection
Persistant Cookies and LDAP InjectionPersistant Cookies and LDAP Injection
Persistant Cookies and LDAP Injection
 
2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From Iusethis
 

Recently uploaded

Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 

Recently uploaded (20)

Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 

Building Better Applications with Data::Manager

  • 1. Data::Manager Just because your users may suck doesn’t mean you should, too
  • 2. Jay Shirley • Infinity Interactive http://www.infinityinteractive.com • Cold Hard Code http://www.coldhardcode.com/ • j@shirley.im http://j.shirley.im/
  • 8. Do one thing really well.
  • 12. Catalyst grows Tools HTTP::Body, others
  • 13. Forms
  • 14. WTF is a Form?
  • 19. Data Validation = Form Generator
  • 20. Data Validation ≠ Form Generator
  • 21. 2011
  • 22.
  • 23.
  • 24. 1999 called... they don’t want their CGI.pm back
  • 25. Tools should grow with you.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32. Easy to get away from.
  • 34. Imagine in 5 years…
  • 35. Why is old embarrassing?
  • 36. How to pick a tool.
  • 37. Don’t judge a tool by typing.
  • 42. Data::Manager A very good way of managing incoming data.
  • 43. In case you missed it…
  • 44. Bad: Error Message! Error Message! Line Item 1 Line Item 1 Delivery Options Gift Options Line Item 2 Line Item 2 Delivery Options Gift Options
  • 45. Good: Error Message! Line Item 1 Line Item 1 Delivery Options Gift Options Error Message! Line Item 2 Line Item 2 Delivery Options Gift Options
  • 46. GETTING STARTED my $dv = Data::Verifier->new(…); my $results = $dv->verify(%params); if($results->success) { # o/ } else { # :( }
  • 47. Data::Manager my $dm = Data::Manager->new; my $verifier = Data::Verifer->new(...); $dm->set_verifier('address', $verifier); $dm->verify('address', $data); if ( $dm->success ) { # o/ } else { # :( }
  • 48. Data::Manager Scopes my $dm = Data::Manager->new; my $verifier = Data::Verifer->new(...); $dm->set_verifier('address', $verifier); $dm->verify('address', $data); if ( $dm->success ) { # o/ } else { # :( }
  • 49. Data::Manager and Messages $dm->verify('address', $data); my $messages = $dm->messages_for_scope('address');
  • 50. Data::Manager and Results $dm->verify('address', $data); my $results = $dm->get_results('address'); # $results can serialize # $results is Data::Verifier::Results
  • 51. A Year in Review • Data::Verifier • 15+ releases and now version 0.47 • Data::Manager • 2 releases, could use more. 0.07 • Message::Stack • Stable API, simple workhorse. 0.19.
  • 52. Where we are now. • Elegant handling of multiple scopes. • We know how to use this stuff better. • The code hasn’t changed that much. • API is stable. • Supports more things as needed. Fork it!
  • 57. Subtle or just broken
  • 64. Form Template: <fieldset> <legend>[% c.loc('About You') %]</legend> [% context.scope = 'person'; text_field({ label => 'Your Name', name => 'name', hint => 'Your Name', required => 1 }); text_field({ label => 'Your Email', name => 'email', hint => 'you@company.com', type='email', required => 1, more => 'This will be your username.' }); context.scope = 'identity'; text_field({ label => 'Password', type => 'password', name => 'password', required => 1 }); text_field({ label => 'Confirm Password', type => 'password', name => 'confirm_password', required => 1 }); %] </fieldset>
  • 68. And what we want
  • 70. Scopes <fieldset> <legend>[% c.loc('About You') %]</legend> [% context.scope = 'person'; text_field({ label => 'Your Name', name => 'name', hint => 'Your Name', required => 1 }); text_field({ label => 'Your Email', name => 'email', hint => 'you@company.com', type=>'email', required => 1, more => 'This will be your username.' }); context.scope = 'identity'; text_field({ label => 'Password', type => 'password', name => 'password', required => 1 }); text_field({ label => 'Confirm Password', type => 'password', name => 'confirm_password', required => 1 }); %] </fieldset>
  • 71. Just markup. • Easily define the layout form. • Macros make it sensible. • Markup for forms can be provided by designers and easily adapted. • Multiple macro “styles” can be included.
  • 72. We have the biggest Macros of them all. • Too big to put on a slide, so they’re on github. • Well defined. • Easy to use. • Not that hard to update.
  • 73. The gist of the macro • Too big to put on a slide (288L). • Ask me to see them, happy to share. • Looks at context.scope, determines: • Message::Stack scope. • Data::Verifier::Results
  • 74. Priorities: • Good Ideal user experience.
  • 75. Priorities: • Good Ideal user experience. • Maximize reliability.
  • 76. Priorities: • Good Ideal user experience. • Maximize reliability. • Optimize for use, hide the complexity.
  • 77. CRUD ≠ User Experience • CRUD principles are awesome.
  • 78. CRUD ≠ User Experience • CRUD principles are awesome. • Behind the scene.
  • 79. CRUD ≠ User Experience • CRUD principles are awesome. • Behind the scene. • Many forms encompass multiple objects.
  • 80. CRUD ≠ User Experience • CRUD principles are awesome. • Behind the scene. • Many forms encompass multiple objects. • Making a user view 3 pages to update 3 objects is bad form.
  • 81. Build a UI first.
  • 82. Pick method and tools second.
  • 83. Our tools let us pick methods
  • 84. Priorities: • Ideal user experience. • Maximize reliability. • Optimize for use, hide the complexity.
  • 85. Reliability • Don’t think about errors. • Convention makes them happen. • Users know what to expect. • Plans + Simple API = Reliability
  • 86. Having a plan means you never have to say sorry. Not really, but it should stop you from having to apologize twice.
  • 87. Priorities: • Ideal user experience. • Maximize reliability. • Optimize for use, hide the complexity.
  • 88. Optimize for use. Save yourself agony with a testable, nice and clean API
  • 89. Optimize for use • Write code behind a clean API. • Make methods that do smaller work. • That gives us easy code. • This is a different topic.
  • 90. Optimized for use: # In your controller: (see Catalyst::Action::REST for *_POST) sub root_POST { my ( $self, $c ) = @_; my $data = $c->req->params; my $results = $c->model(‘DataManager’)->verify($scope, $data); unless ( $results->success ) { $c->message({ type => ‘error’, message => ‘You Fail‘ }); $c->res->redirect( $c->uri_for_action('/object/create_form') ); $c->detach; } # Success, store from $results, verify and redirect. }
  • 91. Simple Model package MyApp::Model::DataManager; use Moose; with 'Catalyst::Component::InstancePerContext'; has 'profiles' => ( ... ); sub build_per_context_instance { my ( $self, $c ) = @_; my $dm = Data::Manager->new; foreach my $scope ( $self->scopes ) { $dm->set_verifier( $scope => Data::Verifier->new( $self- >get_profile($scope) ) ); } $dm; }
  • 92. Profiles has 'profiles' => ( default => sub { { 'login' => { filters => [ qw(trim) ], profile => { username => { type => 'Str', required => 1, }, password => { type => 'Str', required => 1, } } },
  • 93. Going Further (with type constraints) username => { type => MyEmailType, required => 1, coerce => 1, },
  • 94. Type Checking • Handles coercion (or not) • Verifies if data is of type • Emits “invalid” error in results if invalid.
  • 95. extend Data::Manager • Add your own methods. • Make it better. • Some ideas: • all_valids, hashref of all valid fields. • data_for_scope, hashref of fields in scope. • error_scopes, list of scopes needing attention.
  • 96. extend Data::Manager • Setup defaults for verifiers by scope. • By DBIC result sources. • By Catalyst models. • Lots of options.
  • 97. Example: Checking uniqueness An often broken endeavor.
  • 98. Issues: • Must filter out ‘$self ’ from the result set. • Must then load $self. • Must figure out create vs. update.
  • 99. A simple unique check my $unique_check = sub { my $r = shift; my $user = $r->get_value('username'); my $id = $r->get_value('id'); my $rec = $c->model('DB::User') ->search({ username => $user })->first; return 1 if not defined $rec; return 1 if $rec->id == $id; return 0; };
  • 101. Difficulty in testing. • Verifier doesn’t know the database. • Verifier shouldn’t know the database. • Modify verification profiles where it makes sense.
  • 102. Inserting sub build_per_context_instance { my ( $self, $c ) = @_; my $unique_check = sub { ... }; my $dm = Data::Manager->new; foreach my $scope ( $self->scopes ) { $dm->set_verifier( $scope => Data::Verifier->new( $self- >get_profile($scope) ) ); } $dm->get_verifier('create_account') ->profile->{username}->{post_check} = $unique_check; $dm; }
  • 103. On a user object… sub build_per_context_instance { my ( $self, $c ) = @_; my $unique_check = $c->model(‘DB::User’)->unique_check; my $dm = Data::Manager->new; foreach my $scope ( $self->scopes ) { $dm->set_verifier( $scope => Data::Verifier->new( $self- >get_profile($scope) ) ); } $dm->get_verifier('create_account') ->profile->{username}->{post_check} = $unique_check; $dm; }
  • 104. Not ideal • Can add same check for backend tools • Access in similar fashion • Verification profiles are modifiable
  • 105. Still optimized for use: # Same controller! sub create_account_POST { my ( $self, $c ) = @_; my $data = ‘create_account’; my $data = $c->req->params; my $results = $c->model(‘DataManager’)->verify($scope, $data); unless ( $results->success ) { $c->message({ type => ‘error’, message => ‘You Fail‘ }); $c->res->redirect( $c->uri_for_action('/create_account') ); $c->detach; } # Success, store from $results, verify and redirect. }
  • 108. .* just works. (you just have to use it)
  • 109. Thank you. Please think about your applications. Think about the problems. Fix the problems.

Editor's Notes

  1. \n
  2. \n
  3. This is more a story. Partially an adventure story, for those who find building applications adventurous. In the beginning, we built applications. Applications accepted user input via silly things like strings with regular expressions applied to them. Perhaps just a simple, &amp;#x201C;is it there&amp;#x201D; check.\n
  4. This was all really stupid. It was really bad, too. It was stupid and bad.\n
  5. It always bothered me so I&amp;#x2019;m going to talk about what we set out to fix it. When I say we I mostly mean me and Cory Watson. I talked a lot and he wrote good code. I talked more and he told me patches welcome. I then talked and provided patches.\n
  6. And we built something. At first it wasn&amp;#x2019;t very good. It was a tool.\n
  7. And we create tools because they make us better. They help us do our job better, rather. That is their job.\n
  8. The best tools are simple tools. They do one thing and do it very well.\n
  9. The power of tools is not to make a swiss army knife that does everything, but to have everything that is needed to do something. You use them together.\n
  10. There is a word for this. Usually only tools use it.\n
  11. And I have an example of something comprised of many tools that works really well. Catalyst! It&amp;#x2019;s a great framework that holds things together, but the power is that you can use any tool you like with it.\n
  12. It even grew some new tools. Taking things it did that would be better suited by something doing it exclusively. HTTP::Body came about this way and is very useful. Plack uses HTTP::Body. It benefits the ecosystem to have tools do one thing. Even if that one thing is using many tools together.\n
  13. Forms are a tool.\n
  14. Or maybe better said, they were a tool. Forms are changing.\n
  15. So is Perl\n
  16. So is the world.\n
  17. The new world doesn&amp;#x2019;t have this notion of forms. It doesn&amp;#x2019;t have this idea that you load a page to edit a record in a database. It&amp;#x2019;s seamless and connected, the interface may have many faces.\n
  18. The old way of doing things is quickly changing. By changing I mean dying and going away. html5 changes a lot in the way forms are handled. Just local storage changes a lot of what is possible. The file browsing in html5. The very shape of building web applications is changing.\n
  19. And I bring this up because of this very bad assertion.\n
  20. The two have nothing to do with each other. Attempting to bind them together is bad.\n
  21. The world is quickly advancing. Far faster than I thought when I was a child. Now I have children. It&amp;#x2019;s spooky. But faster than that is how quickly technology advances.\n
  22. We&amp;#x2019;re not building apps that talk over old copper wires anymore.\n
  23. We&amp;#x2019;re building apps that are apps that run on devices with no wires.\n
  24. We&amp;#x2019;re building apps that are apps that run on devices with no wires.\n
  25. We&amp;#x2019;re building apps that are apps that run on devices with no wires.\n
  26. We&amp;#x2019;re building apps that are apps that run on devices with no wires.\n
  27. We&amp;#x2019;re building apps that are apps that run on devices with no wires.\n
  28. I don&amp;#x2019;t think our tools have grown with us.\n
  29. It&amp;#x2019;s because we were too committed. There are lots of things a person should be married to.\n
  30. \n
  31. \n
  32. \n
  33. Tools don&amp;#x2019;t make sense. You can be passionate about a tool without marrying it.\n
  34. So just say no, and move on, and improve and grow.\n
  35. How do you tell if you&amp;#x2019;re successful? Well, I think it&amp;#x2019;s pretty easy. If you need to hire someone, like a lawyer, to get away from it you are probably married. If you can just stop talking to it, you&amp;#x2019;re good.\n
  36. Keeping your tools single purpose helps keep this line uncrossed.\n
  37. And now everybody close your eyes and think about the application you are building now. Whatever it is, and imagine in 5 years you are called in to work on it.\n
  38. How many people here cringed? How many people here think back to what they did 5 years ago and laugh? It&amp;#x2019;s because tool-marriage. Applications were architected in such a way they could not grow.\n
  39. It&amp;#x2019;s because programming was itself quite young. We didn&amp;#x2019;t have the knowledge we have today. Now we know better, and we know how to pick tools.\n
  40. First is syntax. Ignore it. We aren&amp;#x2019;t paid to type, we&amp;#x2019;re paid to produce awesome applications. Arguing about syntax and style is foolish. I&amp;#x2019;m pretty sure lawyers don&amp;#x2019;t bitch about the font in their case law books. Rise above such silliness and pick a tool for what it does, what it can do and more importantly what is has been proven to do.\n
  41. Second is to seek out opinions. Opinions are very valid. Sometimes it&amp;#x2019;s just feel, but talk to people. I don&amp;#x2019;t like jquery but I love YUI3. It&amp;#x2019;s my opinion. I can back it with reasoned discourse. Talking it out helps clear things up, sometimes just clarifying a nagging worry that is unable to be articulated.\n
  42. Third is how it uses other tools. Does it include everything itself even if something better exists? Does it tell you how to do everything, even things unrelated to its purpose?\n
  43. If it does, it imposes. Pick tools that don&amp;#x2019;t impose on you. Imposing is one step away from marriage.\n
  44. We went through all that and didn&amp;#x2019;t find anything. So we built our own. We didn&amp;#x2019;t want to, we wanted someone to do something for us.\n
  45. But nobody did, so we first wrote Data::Verifier and then Message::Stack. After that we wrapped it up in Data::Manager. There was much rejoicing. Mostly from our users.\n
  46. Here&amp;#x2019;s a quick recap on the usage for those who missed the talk at YAPC last year or from OPW in January.\n
  47. This is bad messaging. It makes users guess. Don&amp;#x2019;t make your users guess.\n
  48. This is good messaging. It tells people where to look.\n
  49. This is the usage, taken from Cory&amp;#x2019;s original talk on it. It&amp;#x2019;s very simple. You create your verifier, call verify with a hashref, and it gives you a results object. If it&amp;#x2019;s successful, you party.\n
  50. Data::Manager introduces multiple verifiers and a consistent serializable object. This means you can say, &amp;#x201C;Verify this address!&amp;#x201D; and against the same object verify something else.\n
  51. These are called scopes. It&amp;#x2019;s important when you are binding this with messaging.\n
  52. Messages are easy to get. Just ask for them. What are my messages related to address verification?\n
  53. The results are also serializable and just Data::Verifier::Results. It&amp;#x2019;s a decorated hash ref, really. Nothing fancy.\n
  54. Since YAPC last year, we&amp;#x2019;ve still been adding more to it. Data::Verifier has had the most. Message::Stack only had one release which was to make it work better with internationalization.\n
  55. As far as our usage, we&amp;#x2019;ve also done more. The more applications we build the more it does. The better we do. Through the years we&amp;#x2019;ve still never changed the API and haven&amp;#x2019;t needed to. It&amp;#x2019;s on github and we accept patches.\n
  56. Right now we&amp;#x2019;re about half way through. I told you why we built Data::Manager and the current status, but I haven&amp;#x2019;t spoken about how we use it. That&amp;#x2019;s really important because it shows how we build better applications.\n
  57. Right, so back to the story.\n
  58. We used Catalyst and had controllers and we wrote markup by hand like a lot of people do.\n
  59. We had the same problems other people do.\n
  60. Sometimes our users were confused. Sometimes annoyed.\n
  61. Sometimes our developers became confused or annoyed. Sometimes both.\n
  62. Then we would get a designer suggesting some change. We really hated that.\n
  63. We were in a bad relationship.\n
  64. We thought and looked at a lot. We looked at form generators and played with them. Reflectors and all that.\n
  65. We never seemed to find one that worked the way we did. I&amp;#x2019;ll explain more later, but they all were frustrating. I deleted many, many branches after porting to form generators.\n
  66. So we got married (slightly) to our templating engine. Most templating engines support macros to some extent, so I think this is safe. We just use macros.\n
  67. The usage isn&amp;#x2019;t bad. It&amp;#x2019;s not good but there are worse things out there. Like form generators.\n
  68. It renders consistently.\n
  69. We have multiple scopes, which is something we always had trouble with when using form generators. Here we store our person information, stored in a person table.\n
  70. But here we have our user information, stored in an identities table.\n
  71. But we get messaging on both, on the same screen.\n
  72. And it does a good job checking it&amp;#x2019;s not garbage in.\n
  73. But there is no messaging on the macros. There isn&amp;#x2019;t anything more than what we need. We only need to define what scope to look for results and messages in. That&amp;#x2019;s really the only &amp;#x201C;convention&amp;#x201D; thing here. No magic, though.\n
  74. This gives us the ability to create complex and beautiful forms, exactly what the user would expect. Designed by a human, passed off and generated with simple macros. It&amp;#x2019;s easy to change, since you just edit the macros in one place, and it is consistent.\n
  75. I&amp;#x2019;d show you the macros, but they&amp;#x2019;re really big. It&amp;#x2019;s basically broken up in the main structure, the label field, input, a messaging section. I use YUI3 grids for layout and it works really well. I can create all sorts of complex forms that look great.\n
  76. The context.scope just tells the macros where to look. The information is in the stash, just have to get at it. It&amp;#x2019;s what I call &amp;#x201C;sensible defaults&amp;#x201D;. You can override or add messaging explicitly in the macros, or it can fetch it from the results or message::stack.\n
  77. It gives us the three things I think are key to building good applications. I don&amp;#x2019;t know if we&amp;#x2019;ll ever build a Good user experience. Not without a true to form user experience engineer. Those guys are picky *and* expensive. So let&amp;#x2019;s settle for ideal. No surprises, consistent and works. We maximize reliability, we want it to always work the same way. Emails are validated the same way, passwords, too. We optimize it for the developer, developers should want to use these tools. Hide the complexity but it should always be accessible.\n
  78. It gives us the three things I think are key to building good applications. I don&amp;#x2019;t know if we&amp;#x2019;ll ever build a Good user experience. Not without a true to form user experience engineer. Those guys are picky *and* expensive. So let&amp;#x2019;s settle for ideal. No surprises, consistent and works. We maximize reliability, we want it to always work the same way. Emails are validated the same way, passwords, too. We optimize it for the developer, developers should want to use these tools. Hide the complexity but it should always be accessible.\n
  79. It gives us the three things I think are key to building good applications. I don&amp;#x2019;t know if we&amp;#x2019;ll ever build a Good user experience. Not without a true to form user experience engineer. Those guys are picky *and* expensive. So let&amp;#x2019;s settle for ideal. No surprises, consistent and works. We maximize reliability, we want it to always work the same way. Emails are validated the same way, passwords, too. We optimize it for the developer, developers should want to use these tools. Hide the complexity but it should always be accessible.\n
  80. When I&amp;#x2019;m talking about complexity, it&amp;#x2019;s usually for things not complex for geeks. Like CRUD. Very easy. You get a page, you edit a record. That&amp;#x2019;s a really bad experience for the user. The way a user will logically join and separate objects is not how it makes sense in a database. Don&amp;#x2019;t impose this on your users because of inadequate tool usage. This system works for that.\n
  81. When I&amp;#x2019;m talking about complexity, it&amp;#x2019;s usually for things not complex for geeks. Like CRUD. Very easy. You get a page, you edit a record. That&amp;#x2019;s a really bad experience for the user. The way a user will logically join and separate objects is not how it makes sense in a database. Don&amp;#x2019;t impose this on your users because of inadequate tool usage. This system works for that.\n
  82. When I&amp;#x2019;m talking about complexity, it&amp;#x2019;s usually for things not complex for geeks. Like CRUD. Very easy. You get a page, you edit a record. That&amp;#x2019;s a really bad experience for the user. The way a user will logically join and separate objects is not how it makes sense in a database. Don&amp;#x2019;t impose this on your users because of inadequate tool usage. This system works for that.\n
  83. When I&amp;#x2019;m talking about complexity, it&amp;#x2019;s usually for things not complex for geeks. Like CRUD. Very easy. You get a page, you edit a record. That&amp;#x2019;s a really bad experience for the user. The way a user will logically join and separate objects is not how it makes sense in a database. Don&amp;#x2019;t impose this on your users because of inadequate tool usage. This system works for that.\n
  84. I don&amp;#x2019;t like coding the data model first. I go for a UI.\n
  85. I see how the application is going to work and then I pick the tools. It&amp;#x2019;s like test driven development, but more like User Acceptance Test Driven Development. The users of my applications often do so for their jobs, at least in some capacity, and I should respect that. Just like if someone asks me for technical help I expect them to respect my job.\n
  86. Once we do pick these tools the methods fall into place. If you use form generators, usually it&amp;#x2019;s a simple 1 to 1 CRUD system. That&amp;#x2019;s not good for the users.\n
  87. I&amp;#x2019;m going to talk more about reliability now\n
  88. Reliability is best dealt with by not dealing with it. Use tools that do it that you can tap into when you need to. Convention works. Rails does this well. If you don&amp;#x2019;t have to think about making sure your users see the errors, you can focus on making sure the errors happen. And that they happen correctly. You build simple APIs and a plan for how it happens.\n
  89. And this makes your users happy. Or it should, but it may not immediately. Sometimes it takes a bit longer. The key is to learn from your mistakes!\n
  90. The final point is about developers. Optimizing for development speed is just as important as optimizing for operational speed. Imagine in 5 years...\n
  91. If your APIs, including your data validation, are all well tested they will be easy to change. Easy to update. You have the tests to prove it.\n
  92. Think of everything in your application as single purpose. Each method should do one thing. Each method should be behind a simple API. Each simple API should have an easy test. This is really outside the scope so I&amp;#x2019;m going to move on.\n
  93. To a method that does only one thing. It&amp;#x2019;s a POST action. This is how we verify data. Nearly all of our controller actions that handle a POST follow this pattern or a similar pattern. Because it is so similar, we use either base classes or roles.\n
  94. In the simplest form, you just create a simple class that builds Data::Manager objects. You have a big list of profiles (just hashes) and you create Data::Verifier objects from it.\nI prefer creating this per request (lazily) because I never have to worry about data leakage. The Data::Manager belongs to that request and that request alone.\n
  95. This is the profile hash. It is keyed by scope and the body is all of what gets passed into Data::Verifier.\n
  96. When you start to impose more rigid business rules, it&amp;#x2019;s much easier to adapt using this. You can define Moose types (which are easily testable), coercions and run from there. It gives you a great deal of increasing flexibility on data verification. If you decide usernames should be email addresses, just define an email type. All done.\n
  97. The type checking is one of the coolest features of Data::Verifier. You can specify to use the default coercion, your own coercion or none at all. It just verifies if the incoming data passes the type constraint. You get the reason why from Data::Verifier, but the automatic parsing that Data::Manager uses just throws &amp;#x201C;invalid&amp;#x201D; since it&amp;#x2019;s the lowest common denominator.\n
  98. Data::Manager is also easily extended. In a lot of applications we end up adding our own methods for whatever we need. I have one that generates a list of traits based on what scopes. It&amp;#x2019;s application specific, but works well. Some ideas maybe should go into Data::Manager itself but we&amp;#x2019;re not sure. We don&amp;#x2019;t want to clutter it with a confusing set of methods.\n
  99. The other way is that you can automatically setup profiles. I have code that crawls the loaded DBIC result sources, looks at the columns and generates a verification profile for them. Another similar one for any Catalyst model loaded, crawling all models if they have a Verification trait applied and then loading the profile accordingly. There&amp;#x2019;s a lot of ways to handle this. I still don&amp;#x2019;t think I have one that unlocked the Awesome Badge.\n
  100. This section covers a more advanced situation. Something often done in the controller that shouldn&amp;#x2019;t be done in the controller. Depending upon the application, this would either be in the model layer or beneath in the business/domain layer.\n
  101. Why is this hard? Well, it has its hands in many pies. The case of create or update must be looked at.\n
  102. Here is a simple closure that does the work. The $r is the Data::Verifier::Results object *after* filter, coerce and validation but before post-checking. Data::Verifier fails on the first failure, so a post_check won&amp;#x2019;t be called if a coerce or type fail.\n
  103. Immediately this shows some problems. Not functional or logical problems, but the problems of a more difficult variety. Problems 6 months later. Those are the worst problems.\n
  104. It&amp;#x2019;s hard to test, and this is the biggest problem. When things are hard to test we don&amp;#x2019;t test them. We have more important things to do! The solution is to write code that is easy to test, obviously.\n
  105. So here&amp;#x2019;s how we use this. It&amp;#x2019;s specific to the model in the application. This is Catalyst syntax, but any other framework could do the same thing. When the Data::Manager object is instantiated for the request, you just shove the closure in and be done with it.\nSince the closure can reside anywhere you can get a scalar out of, it&amp;#x2019;s easy to put it where it makes sense. Maybe an attribute on your user object.\n
  106. So here&amp;#x2019;s how we use this. It&amp;#x2019;s specific to the model in the application. This is Catalyst syntax, but any other framework could do the same thing. When the Data::Manager object is instantiated for the request, you just shove the closure in and be done with it.\nSince the closure can reside anywhere you can get a scalar out of, it&amp;#x2019;s easy to put it where it makes sense. Maybe an attribute on your user object.\n
  107. Now you can put your unique check where it is easily accessible, some method that just returns the code ref. If you follow this, you can access and modify your verification profiles and not worry. More importantly, as long as you unit test your unique_check method appropriately (which you can do outside the confines of Data::Verifier) you can succeed in testing everything. Data::Verifier::Results-&gt;new is the secret here, stuff it with what you want.\n
  108. The great thing here is that our controller is the same as it was. No modification to the controller for what is a business or model level decision. Using these techniques, you still get the same exact errors, split up by scope and subject but they&amp;#x2019;re more informative and you have more coverage. No template change, no markup change, no controller change. Just inserting a post_check into your profile.\n
  109. And that&amp;#x2019;s the point of this story.\n
  110. We&amp;#x2019;ve done something that is consistent for the user, reliable in use, easily testable and optimized for the developer. If you look at this and go, &amp;#x201C;No, no, I don&amp;#x2019;t want this solid messaging in my application&amp;#x201D; then I&amp;#x2019;ve failed to tell this story. I hope everybody here says, &amp;#x201C;YES! This is what I want!&amp;#x201D; Maybe not with these tools, after all, we&amp;#x2019;re not married to them.\n
  111. But this is what we use and it works for us. I hope you find something that just works for you and your users. Building better applications is hard. You have just witnessed 100 slides of me telling the story of how we got to where we are. It&amp;#x2019;s been a long, hard road. Arduous even, but I think we&amp;#x2019;ve succeeded. We took one of the most painful parts *for users* of building applications and creating a system we, as developers, can easily cope with.\n
  112. \n