先日以下のような記事を拝見しました。
「うんうん、そうだねぇ・・・」と思いつつ読んでいたのですが、ここ数年ずっとPythonばかりを書いていた身からすると少し違和感を感じるところもあったので頭の整理的に言語化しておきます。
前置き
本記事は元の記事を否定するものではありません。元記事で以下のように書かれている通り、元記事はあくまで「そういう傾向がある」という話ですので本記事はそういった傾向に当てはまらないPythonでの例外的なところに触れる形となります。
これまで色々なプロジェクトを観察(風聞も含む)して来たところ、そういう傾向があるのではないかという仮説です。
本記事はなんとなくPythonだと長期プロジェクトとかコード量が多いと詰むのでは・・・?と感じられた方に対してそういったプロジェクトでも(条件次第で)快適に開発を続けられるよ、と宣伝するためのものです。
逆に本記事に対して強い違和感を感じられる方もいらっしゃると思います(あくまで個人の所感となります)。意見・考え方は様々で良いと思っているためそういった考えの相違も否定しません。
ただし豆腐メンタルなのではてブコメント含めマサカリは弱めだと幸いです。
また、型の記述を書かなくても型を書く形でも共に動き、且つコンパイル(ビルド)などをやらなくてもプログラムを実行できるPythonは動的型付け言語なのか?といったところも本記事では触れません。
※ポエム成分を含みます。苦手な方はご注意ください。
※ここ5年くらいは仕事の都合Pythonばかりを書いていますがその前の6年くらいはほぼ静的型付け言語で書いています。あまりたくさんの言語を使っているわけではないため意見の偏りなどはご容赦ください。
個人的にはPythonでも型を書くことが大半になってきている
Python2系が2020年でEoLとなり、Python3.6~3.10でしっかりとした型アノテーションのサポートが入ったり様々な型の改善が入ったりしてきています。
お仕事で扱っているファーストコミットから8年目くらいの(テストやdocstringなども含めて)53万行くらいのPythonコードのあるプロジェクトでも型を書いていっていますしプライベートで趣味で書いていっている以下のプロジェクトでも型付きでPythonのコードを書いて過ごしています。
また、Jupyterでコードを書く場合でもVS Code上のJupyterの場合Pylanceなどでの型チェックが使えるのでそういったスクリプトでも型付きでPythonコードを書いていっています。
Pythonの書籍、例えば以下の本とかでも全コード型付きで書かれている・・・といったケースも目に付くようになってきました(まだそういったケースは少な目だとは思いますが・・・)。
このようにここ数年の状況の変化によってPythonといっても型付きで書くことがかなり多くなってきています。日々作業をしていてPythonでもしっかりと型の恩恵を得られているように感じています。
Pythonで型を書いていてもリードタイムが長くなっている感じはしない
元記事で以下のように触れられている点があります。
また、静的型付き言語では実行前に型チェックが走る以上、(傾向として)「ちょっと変えて再実行」はより時間がかかります。つまり、試行錯誤の回数が滅茶苦茶多いような状況では、静的型付き言語は時間がかかりがちと言えそうです。
コードを書いてコンパイル(ビルド)して動かして(テストして)・・・という点に関してはPythonの場合型付きで書いても型無しで書いてもどちらも書いてすぐに動かしたりその部分だけテストを流したりといったことは行うことができます。
いちいちビルドが待つまでぼーっとしたりする必要はありません。この点はプロジェクトのコード量が年経過で増えて来てビルド時間が伸びる・・・というものでも無いので変更のイテレーションなどはずっと高速に行うことができます。
※Pythonの型の独特なところなどに慣れるまではあーじゃないこーじゃない・・・と時間がかかったりしていますが、慣れたらその辺は改善するためその時期のことは省きます。
型アノテーションをすることで多少タイピング量は増えますがバグを事前に検知できたりミスを減らせたりといったことも多いのでバグ修正などにかかる時間やコードを読んで内容を把握するための時間などを考えると型を書いてもリードタイムが長くなっているという感じはしていません。
Pylanceなどでのリアルタイムの型チェックは非常に快適
他の静的型付け言語でもコンパイルなどする前からエディタ上で型のミスなどをリアルタイムに表示してくれる・・・といった機能は結構あると思いますが、Pythonでもマイクロソフト公式のVS Code拡張のPylanceとかを入れて設定を有効化するとリアルタイムにプログラミング中にリアルタイムに型のチェックが実行されます。
すぐにミスに気づけるので大変快適です。Type Guards的にnull安全的なところでif文が足りていない・・・といった類のところなども書いていてすぐに知らせてくれます。とても快適です。この辺もプロジェクトの年経過でコード量が多くなってきてもチェックが完了するまで遅くなったりはしません(長期プロジェクトでも快適に利用することができます)。
参考 :
CIへmypyやPyrightなどを組み込めば静的型付け言語のように全体的なチェックを行うこともできる
VS Code上のPylanceだと基本的には開いているファイルが対象になります。リアルタイムのチェックはこれが快適な一方で、特定のタイミングでプロジェクト全体的にチェックしたい時があります(例えばデプロイ前とかマージ前とかのローカルでのLintの実行やCI実行時など)。
そういった場合にはmypyやPyright(Pylanceの型チェックは内部でPyrightが使われています)のコマンドなどを組み込むことでプロジェクト全体に対してチェックを行うことができます。
普段の大半の作業はPylanceなどでリアルタイムにチェックする程度にして高速に実装やテストなどのイテレーションを回し、デプロイやマージ前などに安全のために一通り少し時間をかけてmypyやPyrightなどを流す・・・といったことを行うことができ、効率的に作業しつつも静的型付け言語に近い感じで型チェックの恩恵を得ることができます。
この最後のチェック処理はコード量が多くなってくるとじわりじわりと長くなってきます。使うものや実行環境にもよりますが数万行で15秒~40秒とかかかって来るかなぐらいな感じです。
頻繁にプロジェクト全体をチェックするという感じではないためこのくらいの時間なら十分待てる範囲ではありますが、もし気になって来た場合にはGitHub Actions上で並列化するとか更新されたファイルに絡んだ部分のみをチェックする仕組みとかもしくはお金で解決・・・といった対応は必要になってきます。
※Pyrightはnode.jsとかを考える必要があってPythonプロジェクトで組み込むにはmypyよりも少し煩雑・・・と感じていましたが、今はその辺をシンプルに使えるパッケージを公開してくださっている方がいらっしゃるためシンプルにインストールと組み込みを行うことができるようになっています。
参考 :
長期プロジェクトでは逆に静的型付け言語の方が開発体験が悪くなってくるケースがあるかもしれない
長期プロジェクトでもリードタイムは短く保ち、頻繁にアップデートできている方が好ましいケースも多くあると思います(もう新規で開発することが無くなって来たケース等を除いて)。
そうなってきた時に年経過でプロジェクト内のコード量が膨大になってきていると静的型付け言語でのコンパイル(ビルド)などの時間が辛くなってくる・・・ケースもあります。
結構前にお仕事で担当していたゲーム開発とかでもそうで、開発と保守(定期的なアップデート)などは何年も続く一方で段々とパッケージング(リリースビルド)などの時間が長くなってきたりと開発体験が悪くなって来たりも経験しました(当時と比べると大分世の中のものがより快適になってきているとは思いますが・・・)。
その辺の開発体験の悪化を減らすためにマイクロサービスやマイクロフロントエンド的に分割したり一部コードをライブラリとして切り出したり、もしくはお金で解決する・・・といった対応がありますが分けられない(もしくは分けたりしない方が好ましい)ケースなどもあると思います。
この辺のビルド時間などを考えるとむしろ静的型付け言語ではプロジェクト初期のコードが少ない時期のイテレーションの速度はあまり問題にはなりにくく、長期プロジェクトでコード量などが膨大になってくると静的型付け言語だと問題になってくる・・・場合もあるかもしれません。
そのため一概に「静的言語は長期プロジェクト向き」「動的型付け言語は短期プロジェクト向き」とは限らず、Pythonみたいなプロジェクトのコードが膨大でも部分的に書いてすぐ動かせる言語の方が長期プロジェクトで向いているケースもあるかな・・・という所感はしています。
元記事でも少し触れられているDropboxの記事でもPythonのコードが450万行くらいあることが書かれていますが、大分Pythonコード量が多くても結構耐えられるのではと感じています。
参考 :
自分達で型周りのLintやルールを整備しなくても良いという意味では静的型付け言語は楽で良い
Pythonだと型を書く / 書かないと判断はプロジェクトなどの判断に任されます。Lintなどに関してもどれを選択するのか・どのフォーマットのルールを採用するのかなども自分達で決めたり整備する必要があります。この辺は「どういったものにすればいいのか?」とか「どれを選択すればいいのか?」とかは結構悩ましいですし決めるのが面倒・・・ということもぼちぼちあると言えばあります。
そういった意味では静的型付け言語、例えばRustとかだと型とか厳密に書いていかないといけないためその辺は判断面でシンプルに思います。
Pythonだとプロジェクトでろくに整備していないとかだと長期プロジェクトでカオスなことになり得ます。
余談1: Pythonは誰が書いても読みやすい言語なのか?
少し記事の主題から脱線しますが先日以下のようなツイートがタイムラインで流れていたので拝見しました。
おっしゃる通りで整備やルール決めの状況次第でPythonのコードは相当に読みづらいものになり得ます。
私も昔Pythonのコードで「型の記述が無い」「docstringが無い」「テストが無い」「認知的複雑度が相当高い(ネストが10個以上している)」「1つの関数で1000行超えている」みたいなコードに遭遇したこともあり「いやこれは触るの無理だ・・・」と思ったこともあります。
あくまでPythonで長期プロジェクトが快適になるかどうか・・・という点は(mypyなども含めた)Lintやdocstring、ルールなどを整備した上で成り立つ・・・という点はご留意ください。
余談2: テストやdocstringなどのコードを変えやすく / 読みやすくするものの対応も大切
今までPythonの長期プロジェクトを支えるためのdocstringやらdoctestやらコードスタイルやらLint作ったりやらをちまちまと記事にしてきたりしているのでそちらも役に立ちそうでしたらご利用ください(宣伝)。
参考サイト・文献まとめ