Upgrade to Pro — share decks privately, control downloads, hide ads and more …

yapc_eu_2012

 yapc_eu_2012

Perl programming in Yandex.Direct

Oleg Komarov

August 18, 2012
Tweet

More Decks by Oleg Komarov

Other Decks in Programming

Transcript

  1. Intro Deployment Testing DBTools Plack::* Bonus Yandex.Direct: our successful anti-modern

    Perl project Elena Bolshakova, Oleg Komarov 2012-08-20 1/36
  2. Intro Deployment Testing DBTools Plack::* Bonus Production Web interfaces +

    APIs interfaces for clients, sales managers, agencies etc (> 10 user roles + complicate hierarchy) > 12 mln. transactions/day DB: app. 41 × 109 records Perl: 35 servers of 5 types DB: 50 servers Ubuntu + deb-packages app. 150 our own debs 8/36
  3. Intro Deployment Testing DBTools Plack::* Bonus keeping packages ready easy

    cases: debosh, instant deb packaging Files do deploy (perl scripts, crontabs etc.) + 5 lines of metadata + debosh = .deb ready to upload and install See on github: https://github.com/komarov/debosh For complicated cases: custom script for every package And what’s your way? 9/36
  4. Intro Deployment Testing DBTools Plack::* Bonus Keeping packages in order

    What version of X do we have on DB servers? When version N of X was installed on dev server? dpkg-monitor: script for gathering all that data + web-interface It seems to us to be a good practice And what’s your way? 10/36
  5. Intro Deployment Testing DBTools Plack::* Bonus Keeping DB in order:

    DB migrations about 5 schema or data migrations/week special files under ’deploy’ directory 12/36
  6. Intro Deployment Testing DBTools Plack::* Bonus Keeping DB in order:

    DB migrations /project /deploy /2012_07_06_add_client_limit.migr # schema migration /2012_07_10_convert_favorites.pl # data migration ... /lib /t ... It seems to us to be a good practice And what’s your way? 13/36
  7. Intro Deployment Testing DBTools Plack::* Bonus Keeping DB in order:

    DB migration example 2012_07_06_add_client_limit.migr: { type => ’sql’, heavy => 1, when => ’before’, time_estimate => ’3 min’, sql => ’alter table clients add column some_limit int’, } And what’s your way? 14/36
  8. Intro Deployment Testing DBTools Plack::* Bonus Release testing continuous delivery

    compliance with the Sarbanes-Oxley Act JIRA as bugtracker Thanks CPAN for JIRA::Client branches in svn 15/36
  9. Intro Deployment Testing DBTools Plack::* Bonus Unit tests 1 After

    every commit to mainline (+ personal notifications on fail) What to test: perl server-side js perl + DB (special DB for unit-tests, no mock) It seems to us to be a good practice http, tcp interaction Thanks CPAN for Test::HTTP::Server, AnyEvent::Socket 16/36
  10. Intro Deployment Testing DBTools Plack::* Bonus Unit tests 2: non-functional

    Non-functional tests: encoding of source code i18n (documentation|test) coverage (perl|TT) syntax deprecated subs crontabs extra or missing js & TT (used but absent, present but unused) ... – whatever we can imagine It seems to us to be a good practice 17/36
  11. Intro Deployment Testing DBTools Plack::* Bonus DBTools Our inhouse module

    (MySQL-specific) to handle db configs connects and reconnects boilerplate sql construction Also it is replication-aware supports transactions makes unit-tests easier 18/36
  12. Intro Deployment Testing DBTools Plack::* Bonus DBTools: easy things do_insert_into_table(DB,

    "names", {id => 2, name => ’bb’} ); get_one_field_sql(DB, "SELECT count(*) FROM names"); get_one_column_sql(DB, "SELECT name FROM names"); get_all_sql(DB, "SELECT id, name FROM names"); 19/36
  13. Intro Deployment Testing DBTools Plack::* Bonus DBTools: easy things my

    $id; do_in_transaction { $id = do_insert_into_table(DB, "names", {name => ’gg’} ); do_update_table(DB, "totals", {count__dont_quote => ’count + 1’}, where => {table_name => ’names’} ); }; # do smth with $id 20/36
  14. Intro Deployment Testing DBTools Plack::* Bonus DBTools: sometimes you know

    better get_hashes_hash_sql(DB, [ "SELECT STRAIGHT_JOIN t1.id, t1.name, t2.status, t3.date FROM t1 JOIN t2 ON t1.id = t2.id JOIN t3 ON t2.some_id = t3.id", WHERE => { id => [1, 2, ..., 1000], ’t3.is_active’ => 1 } ]); 21/36
  15. Intro Deployment Testing DBTools Plack::* Bonus DBTools no orm. why?

    full control over executed sql no FOREIGN KEYS in db tables have big rows, SELECT * is bad why not SQL::Abstract? you still need to manipulate with dbh and sth you can’t construct complex JOINs, can you? 22/36
  16. Intro Deployment Testing DBTools Plack::* Bonus DBTools: one more example

    UPDATE names SET name = CASE id WHEN 1 THEN ’aa’ WHEN 2 THEN ’bb’ ... END WHERE id IN (1, 2, ...) 23/36
  17. Intro Deployment Testing DBTools Plack::* Bonus DBTools: one more example

    Construct you CASE with sql_case(DB, "id", {1 => ’a’, 2 => ’b’, ..., }) Pretty simple, right? 24/36
  18. Intro Deployment Testing DBTools Plack::* Bonus DBTools: one more example

    Construct you CASE with sql_case(DB, "id", {1 => ’a’, 2 => ’b’, ..., }) Pretty simple, right? When ”...” hides thousands, the performance might surprise you. 24/36
  19. Intro Deployment Testing DBTools Plack::* Bonus DBTools: one more example

    Too many numeric keys? Construct binary tree of CASEs! IF(id < 50, IF(id < 25, CASE..., CASE...), IF(id < 75, CASE..., CASE...) ) 25/36
  20. Intro Deployment Testing DBTools Plack::* Bonus P::M::DevTools use Aspect ();

    sub call { my ($self, $env) = @_; my @devtools_sections = qw/sql http/; for my $section (@devtools_sections) { $env->{"devtools.$section"} = []; } my @hooks; ... 28/36
  21. Intro Deployment Testing DBTools Plack::* Bonus P::M::DevTools ... push @hooks,

    Aspect::before { my (undef, $url) = $_->args; push @{$env->{’devtools.http’}}, $url; } Aspect::call qr/^LWP::UserAgent::(?:get|post)$/; push @hooks, Aspect::around { # DBI->trace } Aspect::call qr/::exec_sql$/; ... 29/36
  22. Intro Deployment Testing DBTools Plack::* Bonus P::M::DevTools ... push @hooks,

    Aspect::before { my ($response_type, $response) = $_->args; my $devtools = { map {$_ => $env->{"devtools.$_"}} @devtools_sections }; ... # $response->{_devtools} = $devtools; } Aspect::call qr/::respond$/; return $self->app->($env); } 30/36
  23. Intro Deployment Testing DBTools Plack::* Bonus Plack::ResponseHelper A very thin

    layer that abstracts Plack’s specifics. Comes with P::RH::Attachment, P::RH::JSON, P::RH::Redirect, P::RH::Text DRY, give it a name and write a helper! See on CPAN: https://metacpan.org/module/Plack::ResponseHelper 31/36
  24. Intro Deployment Testing DBTools Plack::* Bonus Plack::ResponseHelper Your ”hello world”

    app.psgi use Plack::ResponseHelper text => ’Text’; sub { respond text => ’Hello world!’; } 32/36
  25. Intro Deployment Testing DBTools Plack::* Bonus Plack::ResponseHelper Your real app

    use Plack::ResponseHelper csv => [’Attachment’, {content_type => ’text/csv; charset=utf-8’}], json => ’JSON’, redirect => ’Redirect’, template => [’Template’, {get_tt_object => sub {...}}], page404 => [’Redirect’, {default_location => ’/404.html’}]; sub { # routing, etc respond $controller->($env); } 33/36
  26. Intro Deployment Testing DBTools Plack::* Bonus Thanks! Any questions? Drop

    us a line: [email protected] [email protected] https://speakerdeck.com/u/komarov/p/yapc-eu-2012 http://bit.ly/N853eJ 34/36
  27. Intro Deployment Testing DBTools Plack::* Bonus XMLRPC::Transport::HTTP::Plack sub { my

    $env = shift; my $r = Plack::Request->new($env); my $cmd = router($r); my $multiform = $r->parameters; XMLRPC::Transport::HTTP::Plack ->dispatch_to($path, $module) ->handler($r, $cmd, $multiform); } See on CPAN: https://metacpan.org/module/XMLRPC::Transport::HTTP::Plack 35/36
  28. Intro Deployment Testing DBTools Plack::* Bonus Server-side JS See on

    github: https://github.com/ezhi/javascript-v8 transparent manipulation with objects and functions memoizing of already converted objects See on github: http://bem.github.com/bem-method/html/all.en.html 36/36