Slide 1

Slide 1 text

Intro Deployment Testing DBTools Plack::* Bonus Yandex.Direct: our successful anti-modern Perl project Elena Bolshakova, Oleg Komarov 2012-08-20 1/36

Slide 2

Slide 2 text

Intro Deployment Testing DBTools Plack::* Bonus http://yandex.ru 2/36

Slide 3

Slide 3 text

Intro Deployment Testing DBTools Plack::* Bonus http://yandex.com 3/36

Slide 4

Slide 4 text

Intro Deployment Testing DBTools Plack::* Bonus There are ads on yandex 4/36

Slide 5

Slide 5 text

Intro Deployment Testing DBTools Plack::* Bonus http://direct.yandex.com 5/36

Slide 6

Slide 6 text

Intro Deployment Testing DBTools Plack::* Bonus Presentation available at https://speakerdeck.com/u/komarov/p/yapc-eu-2012 http://bit.ly/N853eJ 6/36

Slide 7

Slide 7 text

Intro Deployment Testing DBTools Plack::* Bonus Team and codebase since 2003 14 perl programmers 310 KSLOC Perl 7/36

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

Intro Deployment Testing DBTools Plack::* Bonus Keeping packages in order 11/36

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Intro Deployment Testing DBTools Plack::* Bonus Plack We love Plack 26/36

Slide 28

Slide 28 text

Intro Deployment Testing DBTools Plack::* Bonus Plack::Middleware::* ACL Auth Captcha MemLimit Reqid Usertrack CmdLogs IPREG DevTools 27/36

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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