$30 off During Our Annual Pro Sale. View Details »

今年やったこと_20年以上続くWebサービスのリプレイス_書いたコード_私がモダンかもと思うPerl

Masashi-Sutou
November 22, 2022

 今年やったこと_20年以上続くWebサービスのリプレイス_書いたコード_私がモダンかもと思うPerl

今回のテーマは「来年に向けて、今年やったこと、書いたコード」でお願いします at 吉祥寺.pm31 on 2022/11/22

Masashi-Sutou

November 22, 2022
Tweet

More Decks by Masashi-Sutou

Other Decks in Technology

Transcript

  1. 今年やったこと 20年以上続くWebサービスのリプレイス 書いたコード 私がモダンかもと思うPerl 吉祥寺.pm31 on 2022/11/22

  2. 自己紹介 masashi-sutou @kurotyann9696 CTO at Perl歴は半年 / 以前はSwift,Dart,TypeScriptが多め

  3. Diverseの

  4. 来年(これから)に向けて目指したのは? 画面とAPIを疎結合にして開発できること モダンなPerlとモジュールでAPIを開発できること 段階的にv2にリプレイスできる仕組みをつくること つまり、売上と開発環境を同時に改善できるようにしたい

  5. といった目標を 今年の4月ごろに決めて モダンなPerlを書き始めることに

  6. しかし、私はPerlを書いたことがない

  7. モダンなPerlてどこにあるのか?

  8. とにかく調べる、試してみる 1. 現状のv1のPerlはどういう背景と負債をもつのか 2. 他社のPerlの移行事例や活用事例 -> 1と2は時間の関係でスキップ 3. v2に改善するなら、何が足りない、何が必要? 先人(Perl

    Monger)の記事やコードを読み漁る日々
  9. 結果、こんな感じのPerlになった

  10. 実装例:その1 package YYCAPI::Core::Infra::Trim; use strictures 2; use Types::Common -types; use

    Function::Parameters; fun linefeed_code($class, NonEmptyStr $str) { # 改行コード除く(s///g よりy///d の方が高速に動作する) $str =~ y/[\r\n]//d; return $str; } 1;
  11. モダンPerl = 型定義を付与して堅牢に use strictures 2; で必要なものだけ警告に Types::Common -types で型を使う

    Function::Parameters で fun と引数の型を定義 -> 明示的に $self か $class を書く ( method は禁止) -> Function::Return は見送りに -> 返値型のメリットが少なく、引数の型とテストでOK 高速な書き方、より良い書き方に置き換える
  12. 実装例:その2 - 1 package YYCAPI::Announcement::DTO::CodeRequest; use Moo; use experimental qw(try);

    use Types::Common -types; use Function::Parameters; use aliased; my $ErrorResponse = alias 'YYCAPI::Core::DTO::ErrorResponse'; has code => ( is => 'ro', isa => NonEmptyStr, required => 1, documentation => " お知らせを一意で特定するコード" );
  13. 実装例:その2 - 2 ## その2-1 の続き fun new_by($class, (InstanceOf ['Mojolicious::Controller'])

    $c) { try { my $code = $c->param('code'); return __PACKAGE__->new(code => $code); } catch ($e) { $c->app->log->warn($e); return { error => $ErrorResponse->bad_request() }; } } 1;
  14. モダンPerl = OOPとPerlの新機能を使う Moo で実装の意図を集約したりコメントできる aliased で冗長なアーキテクチャ名を最小限に -> クラス名ぽく大文字で定義 ->

    Variable interfaceだとIntellijで定義ジャンプ可能に -> IntellijのPerlプラグインがそこそこ優秀 5.34.0から可能な try-catch で例外処理
  15. Test2でDomainとControllerをテストする is ok like dies ok lives でだいたい書けて楽 Test::Mojo も

    Test2::V0 と併用して大丈夫だった
  16. ORM(DBIx::Mint, Moo, Sub::HandlesVia)の実装で苦戦 苦戦した。一応期待する振る舞いは実装した でも、関数の呼び方が複数あり、良くない実装が残る 15分では時間が足りない どこかで全部アウトプットしてアドバイスがほしい

  17. 苦戦した例

  18. 例えば、話せる言語を記録するとして... has languages => ( is => 'rw', isa =>

    ArrayRef [Enum [qw[japanese english other]]], # MySQL のSET 型から読み込む coerce => $Coerce->comma_separated_coerce, handles_via => 'Array', # Sub::HandlesVia handles => { add_languages => 'push', }, required => 0, default => $Domain->default_value->{languages} # 'japanese' );
  19. MySQLのSET型を扱いやすくしたい MySQLのSET型をPerlでは配列で参照する型変換 保存時は別処理で配列からcsv文字列に変換 fun comma_separated_coerce($class) { return sub { my

    $input = $_[0]; return undef unless defined $input; if (ref($input) eq 'ARRAY') { return [$class->_uniq($input)]; } # 配列は重複を除去しつつ順番を保持する return [$class->_uniq([split(',', $input)])]; }; }
  20. 型制約(coerce)が効かないときがある # [ 非推奨]: 型制約(coerce )が無視されて更新 push @{ $tester->languages },

    'japanese'; is $tester->languages, ['japanese', 'japanese'], "push は型制約を無視"; # [ 推奨]: Sub::HandlesVia だと型制約(coerce )が有効 $tester->add_languages('english'); is $tester->languages, ['japanese', 'english'], "english を追加"; $tester->add_languages('english'); is $tester->languages, ['japanese', 'english'], " 重複は無視"; $tester->languages('english,japanese'); is $tester->languages, ['english', 'japanese'], "csv 上書き"; $tester->languages(['japanese', 'english']); is $tester->languages, ['japanese', 'english'], " 配列上書き";
  21. .perlcriticrc と .perltidyrc に合わせる git commit時にlintとformatを実行する privateな関数の先頭に _ をつけてルールに合わせる Subroutines::ProtectPrivateSubs

    Subroutines::ProhibitUnusedPrivateSubroutines
  22. cpanfileをメンテできる状態にする

  23. cpan-outdatedをGitHub Actionsで実行 need_update=0 while read -r line; do # cpanfile

    の ' モジュール名' に該当する場合、更新対象とする result=$(echo "$(grep -e "'$line'" cpanfile)") if [ -n "$result" ]; then need_update=1 result=$(echo "$result" | perl -pe 's#^requires ##g') echo "OUT-DATED: $result -> https://metacpan.org/dist/${line//::/-}/changes" fi done < <(cpan-outdated -l local -p) if [ $need_update -eq 0 ]; then echo "All modules in api/cpanfile are up to date." fi
  24. Perlを半年書いてみて -> 学びがある 世の中がWeb3.0!て言ってるなか、Web2.0にいた Perlを通して、Web2.0の技術を復習できて良い 良い記事を書いてるPerl Mongerたち今も活躍してる 普段書かない言語を書くと学びが多くて楽しいが他にも仕事 が...

  25. 最後に もっといい方法があるなら、教えてください そもそも、なぜバックエンドをPerlのままに? 続きは来年3月のYAPC Kyoto オンラインで! と言いたいけど、来年2月は第一子が産まれる可能性 オフライン発表とかできるんかな?

  26. 続きに興味ある方はカジュアル面談で!