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

「バイブス静的解析」でレガシーコードを分析・改善しよう

Avatar for hitode909 hitode909
November 13, 2025
730

 「バイブス静的解析」でレガシーコードを分析・改善しよう

大規模なプロダクトでは、lintや、use漏れチェック、使ってないファイルの検出といった、静的解析を伴う開発支援ツールが重宝されます。
しかし、存在するすべての記法を扱う必要のある汎用ツールでは、どうしても実行時間が伸びてしまったり、プロジェクト固有のかゆいところに手が届きにくかったり、といった課題がつきものです。
発表者が携わる、開発期間約10年・数十万行規模のリポジトリでは、近年注目されている"vibe coding"の考えを下敷きに、プロジェクト専用の軽量なツールを開発して、開発支援に活用しています。
本発表では、プロジェクト固有の静的解析ツールをAIとともに開発し、レガシーコード改善に活用する「バイブス静的解析」を提唱します。

静的解析を用いたツールのこれまで
PPI, PPRを使った汎用ツールのおさらい
汎用的がゆえに、いかなるソースコードも正しく解釈しなければならない宿命
ツールの実行時間増加への利用者側の工夫

バイブス静的解析のアプローチ
プロジェクトに合わせた専用の静的解析ツールを「バイブス」重視、すなわち、勢いで開発する
完璧を目指さず、コードベース上で必要な表現だけに対応する
AIの力を借りて、誰でも保守でき、壊れても機能開発の片手間に短時間で直せるものを目指す

ゴール
「バイブス静的解析」の考えを使って、新たなツールを勢い重視で開発できるようになる
お手元のリポジトリから、数秒以内にuse漏れや不要ファイルといったエラーを検出できるようになる

Avatar for hitode909

hitode909

November 13, 2025
Tweet

Transcript

  1. ‘;’ ߏจ໦ ‘print’ ‘ ‘ List ‘ ‘ ‘ ‘

    ‘1’ ‘ ‘ ‘*’ ‘ ‘ ‘2’ ‘+’ ‘3’ Statement Document print (1 * 2) + 3; 
  2. 11*Ͱߏจ໦ݟ͍ͨ print (1 * 2) + 3; 11*%PDVNFOU 11*4UBUFNFOU 11*5PLFO8PSEQSJOU

    11*5PLFO8IJUFTQBDF 11*4USVDUVSF-JTU   11*4UBUFNFOU&YQSFTTJPO 11*5PLFO/VNCFS 11*5PLFO8IJUFTQBDF 11*5PLFO0QFSBUPS  11*5PLFO8IJUFTQBDF 11*5PLFO/VNCFS 11*5PLFO8IJUFTQBDF 11*5PLFO0QFSBUPS  11*5PLFO8IJUFTQBDF 11*5PLFO/VNCFS 11*5PLFO4USVDUVSF 11*5PLFO8IJUFTQBDFaO use PPI; use PPI::Dumper; my $document = PPI::Document->new($ARGV[0]); my $dumper = PPI::Dumper->new($document); $dumper->print; 
  3. 7JCFDPEJOH74όΠϒε੩తղੳ 7JCFDPEJOHͷߟ͑Ͱ੩తղੳπʔϧΛ։ൃ͢ΔࢼΈ  7JCFDPEJOH όΠϒε੩తղੳ ։ൃεϐʔυ ˕ߴ଎ ˕ߴ଎ ݕূՄೳੑ ☓ಈ͔ͯ͠ΈΔ·Ͱෆ໌

    ̋ਓ͕ؒղऍՄೳͳܗͷग़ྗΛٻΊΔ อकੑ ˚ਓؒ͸ιʔείʔυΛಡΊͳͯ͘΋͍͍ ̋յΕͯ΋௚ͤΔܗʹཹΊΔ ର৅ ͳΜͰ΋ ιʔείʔυղੳ ιʔείʔυॻ͖׵͑
  4. ੩తղੳ74όΠϒε੩తղੳ ಘҙɾෆಘҙ͸͋Δ͕ɺର৅ྖҬʹΑͬͯ͸͏·͍͘͘  ੩తղੳ όΠϒε੩తղੳ ର৅ൣғ ˕ߏจ໦ͱͯ͠ਖ਼͘͠ύʔε ͍͔ͳΔه๏ʹ΋ରԠՄೳ ☓ίʔυϕʔε಺ͷه๏ͷΈѻ͏ ඼࣭

    ˕ੑ্࣭ɺޡ࡞ಈ͸ڐ༰͞Εͳ͍ ඼࣭ॏࢹͷखݎ͍։ൃ ☓ࣗݾ੹೚Ͱ։ൃ յΕͨΒࣗ෼ͨͪͰ௚͢ɺࣺͯΔ อकੑ ˚ߏจ໦Λର৅ͱͨ͠"1*ͷशಘ͕ඞཁ ̋ਖ਼نදݱͳͷͰ ߏจ໦ʹ໌Δ͘ͳ͍ϝϯόʔͰ΋ѻ͑Δ ࣮ߦ࣌ؒ ☓࣮ߦ͕࣌ؒ໰୊ͱͳΔ͜ͱ΋ ϑΥʔϚολద༻ʹ਺෼ͳͲ ˕ສߦͷղੳ΋਺ඵ
  5. ͜ͷίʔυফͤ·͔͢ʁ ِӄੑɺِཅੑͰߟ͑Δ  ҙຯ ى͜Δ͜ͱ ِӄੑ ݟಀ͠ ຊ౰͸ফͤΔͷʹʮফͤͳ͍ʯͱ൑அ σουίʔυ͸࢒Δ ػೳఏڙ্໰୊ͳ͠

    ِཅੑ ޡݕ஌ ຊ౰͸ফͤͳ͍ͷʹʮফͤΔʯͱ൑அ ඞཁͳίʔυΛফͯ͠͠·͏ ෆ۩߹ɺো֐ൃੜ ِӄੑ͸ڐ༰ɺِཅੑ͸ආ͚Δ ׬ᘳΛ໨ࢦͣ͞ɺ࣮֬ʹݕग़Ͱ͖ΔՕॴʹߜΔ
  6. ͞·͟·ͳґଘͷܗ ൚༻πʔϧଆͰ͢΂ͯରԠ͢Δͷ͸೉͍͠  use, require # ར༻ use parent #

    ܧঝ with, extends # Moose, MouseͳͲ࢖͍ͬͯΔ৔߹ # δϣϒΩϡʔ΁packageΛࢦఆͯ͠ΤϯΩϡʔ Worker->insert_job('MyApp::PublishEntry', {id => $entry_id}); # crontab͔ΒδϣϒΩϡʔʹΤϯΩϡʔ */1 * * * * root perl insert-worker-job.pl --job 'MyApp::PublishScheduledEntry' # ϧʔςΟϯά༻DSLΛ࢖ͬͯControllerΛࢦఆ GET '/' => 'MyApp::Controller::Root#index_html'; # `MyApp::Model::Entry`ͳͲ͕ಈతϩʔυ͞ΕΔ $c->model('Entry')->search({id => $entry_id}); # `MyApp::Controller::`ҎԼΛ͢΂ͯϩʔυ Module::Find::useall 'MyApp::Controller';
  7. σουίʔυͷҰੜ  🤖ίʔυ࡟আ 🤖ௐࠪ݁ՌΛఴ͑ͯ13Խ 🧐$*ίʔυϨϏϡʔ 🫣ϚʔδɾϦϦʔε 🤖εΫϦϓτ࣮૷ 🤖εΫϦϓτ࣮ߦ 🤖σουίʔυ ީิൃݟ

    🤖୳ࡧϧʔϧௐ੔ 😀࡟আՄೳͱ൑அ 😅ෆඋ͋Γ 🤖Ϩϙʔτ 🤖HJUHSFQHJUMPH Ϩϙʔτ࡞੒ 😵💫σουίʔυ ࡟আΛࢥཱ͍ͭ 🤨ܦҢ֬ೝ
  8.  IUUQTHJUIVCDPNQFSMEPDKQQFSMEPDKQQVMM ಉ͡ख๏ͰQFSMEPDKQͰσουίʔυൃݟ ߦͷ࡟আʹ੒ޭ sub extract_used_packages { my $file =

    shift; my @packages; open my $fh, '<', $file or return (); while (<$fh>) { # use Package if (/^\s*use\s+([\w:]+)/) { push @packages, $1; } # use parent qw/Package1 Package2/ if (/^\s*use\s+parent\s+qw[\/\(]([^\/\)]+)[\)\/]/) { push @packages, split /\s+/, $1; } # use parent 'Package' if (/^\s*use\s+parent\s+['"]([^'"]+)['"]/) { push @packages, $1; } # Package->method if (/([\w:]+)->\w+/) { push @packages, $1 if $1 =~ /::/; } } close $fh; return @packages; }
  9. 5FTUͷDBMMॻ͖๨Εςετ 5FTUͷPCKFDUςετͰɺ DBMMॻ͖๨ΕΛݕ஌͢ΔςετΛ11*Ͱ༻ҙ͍ͯͨ͠ # OK is $user, object { call

    age => 30; }; # NG is $user, object { age => 30; }; ࣮ߦ࣌ؒɿඵ ಉ݁͡ՌΛฦ͢ಉ͡ਖ਼نදݱ൛Λ։ൃͰ͖Ε͹ߴ଎Խͯ͠͏Ε͍͠ 
  10. 5FTUͷDBMMॻ͖๨Εςετ ࢼ͕ͨ͠ɺ͏·͍͔ͣ͘ ࣅͨΑ͏ͳ݁Ռ͸ಘΒΕΔ͕11*൛ͱݕ஌Օॴ͕ҟͳΔ # ωετͨ͠object is $user, object { call

    parent => object { call age => 60; }; call age => 30; }; ωετͨ͠ߏ଄ʢA\^AɺA<>AͳͲʣ͸ਖ਼نදݱͰ͸ਖ਼֬ʹѻ͑ͳ͍ VTFSFRVJSF͸ωετͷͳ͍୯७ͳߏ଄ͳͷͰਖ਼نදݱͰѻ͑Δ PCKFDUϒϩοΫͷΑ͏ͳෳࡶͳௐࠪΛ͢Δʹ͸11*͕ඞཁ όΠϒε੩తղੳ͸ສೳͰ͸ͳ͍ɻਖ਼نදݱͰѻ͑ΔൣғΛݟۃΊΔ͜ͱ͕େࣄ