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

プログラミング言語に依存しない、質の高いコードを書く技術

 プログラミング言語に依存しない、質の高いコードを書く技術

PHPカンファレンス沖縄 2021で登壇した内容。

922f51d458d6ffee8578b9d3ab0a52b6?s=128

Arakaki Yuji

May 29, 2021
Tweet

Transcript

  1. プログラミング言語に依存しな い、質の高いコードを書く技術 CBcloud 株式会社 新垣 雄志 ( あらかき ゆうじ )

  2. 自己紹介 • 新垣 雄志 ( あらかき ゆうじ ) • Twitter:

    @arakaji • 職歴 ◦ 琉球インタラクティブ株式会社 ◦ 株式会社 Payke ◦ CBcloud 株式会社 ← NOW • PHP 歴 ◦ 前職、前前職ともにサーバーサイドで PHP を使っていた ▪ CakePHP ▪ FuelPHP ◦ 現職ではサーバーサイドは Ruby を使っている
  3. なぜこのテーマを選んだか? • PHP は前職まではがっつり使っていたが、現職は主に Ruby で開発をしている • そのため、個人的にいま「 PHP 」特有のテーマがみつからなかった

    • プログラミング言語に依存しないテーマを探した • 現職ではスタートアップあるあるのスピードと成長優先で書かれたプロダクトを引き継 ぎ、コードの保守性なども改善しながらもプロダクトの成長をさらに加速させるための 開発をしている最中 • 「コードの品質」と「プロダクトの成長速度」をどう両立させていくかがテーマ • そこで出会った名作
  4. 質とスピード

  5. 質とスピード • 和田 卓人 (@t_wada) 先生の登壇資料 • ソフトウェア開発においてよく言われる「コードの品質を一旦犠牲にしてスピード優先 で開発する」という言葉に対する誤解を解く内容 •

    コードの品質と開発スピードはトレードオフではない • 品質の高いコードを書くことにより、開発速度が上がる • 質を上げながら開発速度も上げるにはどうすればいいか?ではない • 質を上げることによって開発速度を上げる
  6. None
  7. 次に出てくる疑問 • 質の高いコードを書くことが開発速度を上げることに繋がることはわかった。 • では「質の高いコードを書く」にはどうすればよいのか ? • 今回はその「プログラミング言語に依存しない質の高いコードを書く技術」について の整理・言語化を試みた

  8. ソフトウェアの品質とは?

  9. None
  10. SQuaREのソフトウェア品質モデル • システム及びソフトウェアの多岐にわたるステークホルダ ( 利用者、発注者、開発者 など ) が持つ多様な品質要求を定義し評価するための基準として定義された国際規 格 SQuaRE

    シリーズ • 品質モデルでは、品質を構成する上位の要素「品質特性」とこの品質特性をささえ る詳細化した下位の要素「品質副特性」を定義している
  11. 保守性の高いコードを書く技術 • 今回掘り下げるのは「保守性」 • 「意図した保守者によって、製品又は システムが修正することができる有効 性及び効率性の度合い」 • 保守性を上げる =

    プロダクトの変更 速度を上げること
  12. モジュール性(modularity) • 「一つの構成要素に対する変更が他の構成要素に与える影響が最小になるように、 システムまたはコンピュータ・プログラムが別々の構成要素から構成されている度合 い」 • つまり、依存関係やそれによる影響範囲を適切にコントロールしたコードを書くため の技術が求められる

  13. SOLID原則

  14. SOLID原則 SOLID 原則の目的は、以下のような性質を持つ中 間レベルのソフトウェア構造を作ること。 • 変更につよいこと • 理解しやすいこと • コンポーネントの基盤として、多くのソフトウェ

    アシステムで利用できること
  15. SOLID原則 • S: 単一責任の原則 (SRP: Sigle Responsibility Principle) ← 着目

    • O: オープン・クローズドの原則 (OCP: Open-Closed Principle) • L: リスコフの置換原則 (LSP: Liskov Substitution Principle) • I: インターフェイス分離の原則 (ISP: Interface Segregation Principle) • D: 依存関係逆転の原則 (DIP: Dependency Inversion Principle)
  16. 単一責任の法則 • 「モジュールを変更する理由はたったひとつだけであるべきである」 • ソフトウェアを変更するのは、ユーザーやステークホルダーを満足させるため • この「ユーザーやステークホルダー」が変更する理由になる。 • ただし複数のユーザーやステークホルダーがシステムをおなじように変更したいと考 えることもある。

    • 変更を望む人たちをひとまとめのグループとして扱いため、そのグループをアクター と呼ぶ • 「モジュールはたった一つのアクターに対して責務を負うべきである」
  17. Employeeクラスの例 • 給与システムにおける従業員クラスの例 • 3 つのメソッドはそれぞれ別のアクターへ の責務を追っている • calculatePay は経理

    (CFO) • reportHours は人事 (COO) • save は DB 管理者 (CTO)
  18. 何が問題か? • アクターの異なるメソッドで同じアルゴリズムを共 有してしまった場合、両方のメソッドに影響が出 てしまう。 • アクターが異なる機能はアルゴリズムが一時的 に似ていても使われ方が変わるし変更タイミング も変わる •

    アクターが異なるコードは最初からモジュール / クラスレベルで分離したほうがよい
  19. 再利用性(reusability) • 「一つ以上のシステムに、又は他の資産づくりに、資産を使用することが出来る度合 い」 • 既存コードを再利用することで新たなコードを書く必要をへらし生産性を上げる ◦ ライブラリ ◦ フレームワーク

    ◦ SaaS • 再利用しやすいコードを自分が書くことでチームメンバー、そして明日の自分の生 産性をあげる
  20. 再利用性を高めるコードを書くための技術/考え方 • ボトムアッププログラミング • 小さいものは美しい (Small is Beautiful) • メタプログラミング

  21. ボトムアッププログラミング Lisp では、プログラムをただプログラミング言語に従って書く ことはしない。プログラミング言語を自分の書くプログラムに 向けて構築するのだ。プログラムを書いているときに、「 Lisp に◦△のオペレーターがあればなあ」と思うことがあるかもし れない。そうしたらそれを書けばいい。後で、新しいオペ レータの使用がプログラムの別の部分のデザインを簡潔に まとめることにつながったと気づくだろう。

  22. ボトムアッププログラミング • プログラミング言語を自分たちの開発しているアプリケーションの適する形に変えて いくこと • フレームワークやライブラリを使うのはそれと同じ ◦ Laravel や CakePHP

    を導入することで PHP が Web アプリケーションの開発により適した形に拡張され る ◦ aws-sdk のライブラリを導入することで、 AWS を操作するのに適した形に拡張される • これをもっと小さい単位で、自分たちのアプリケーションコードを書くときにも行う
  23. 連想配列の値取得の例 連想配列内に指定したキーが存在する場合には その値を、存在しない場合には指定したデフォル ト値を返す。 一見シンプルだが以下の様な問題もある。 • false と評価される空文字や 0 がある場合、

    キー自体はあるのにデフォルト値がかえされ てしまう • この差異に以外ときづかず特定ケースでバ グを発生させることが多々ある
  24. 連想配列の値取得の例 • 非常にシンプルだがより厳密な配列での値を 取得をするのメソッドを定義する • これによりほんの少しだがバグ発生率やコー ド量を削減することができる。 • シンプルなので他の人も理解しやすく再利用 しやすい。

    • この小さな積み重ねが中長期的な生産性の 大幅な向上につながっていく
  25. 連想配列の値取得の例 • 非常にシンプルだがより厳密な配列での値を 取得をするのメソッドを定義する • これによりほんの少しだがバグ発生率やコー ド量を削減することができる。 • シンプルなので他の人も理解しやすく再利用 しやすい。

    • この小さな積み重ねが中長期的な生産性の 大幅な向上につながっていく
  26. 小さいものは美しい • 小さなプログラムはわかりやすい • 小さなプログラムはシステムリソースにやさしい • 小さなプログラムは他のツールとくみあわせしや すい ◦ 再利用性を高める!!

  27. メタプログラミング メタプログラミング (metaprogramming) とはプログラミング技法の一種で、ロジックを直接 コーディングするのではなく、あるパターンをもったロジックを生成する高位ロジックによっ てプログラミングを行う方法、またその高位ロジックを定義する方法のこと (from wikipedia) 別の言い方をすると、 「プログラムを書くプログラムを書くこと」とも言える。

  28. メタプログラミングってPHPで出来る? • メタプログラミングで一級市民的な言語はある ◦ Lisp ◦ Ruby • PHP ではどうか?

    ◦ マジックメソッドを使うことでメタプログラミングのようなことができる
  29. Driverクラスのtype判別メソッドの定義 • 配送ドライバーには複数種類ある ◦ 軽貨物ドライバー (kei_car) ◦ 一般貨物ドライバー (ippan_car) •

    Driver インスタンスがどのタイプかを判別するた めの is_hogehoge() というメソッドを定義 • 問題点 ◦ DRIVER_TYPE が増えるたびに同じようなメソッドを再 定義しないといけない
  30. Driverクラスのtype判別メソッドの定義 • __call マジックメソッドは存在しないインスタン スメソッドがコールされたときに呼び出される • __call マジックメソッド内で呼び出されたメソッ ド名を判別し、より抽象化された type

    判別メ ソッドを呼び出す • これによって DRIVER_TYPES の定数に値を 追加するだけで is_hoge というメソッドが使え るようになる
  31. メタプログラミングのリスク • デバッグが難しい • コードが複雑かつわかりづらくなりがち • 使うことによって得られるメリットとデメリットを天秤にかけて使うかどうか判断したほう がよい • もし使うならメタプログラミングの部分ににはバグが入り込まないように厳密にテストを

    することと使い方を説明するドキュメント(コメント ) が必要。
  32. 解析性(analyzability) • 製品若しくはシステムの一つ以上の部分への意図した変更が製品もしくはシステム に与える影響を総合評価すること、欠陥もしくは故障の原因を診断すること、または 修正しなければならない部分を識別することが可能であることについての有効性及 び効率性の度合い。 • つまり「問題が起きたときの発生箇所、影響範囲、原因の特定がしやすいかどうか」

  33. 解析性を高める技術 • オブザーバビリティを高めるツールの導入 • 適切なログ出力 •

  34. オブザーバビリティ アプリケーション、インフラ、ログなどあらゆ るテレメトリーデータを収集、相関、意味付 け、可視化し、複雑なソフトウェアシステム を理解しやすくするための取り組み - NewRelic - Datadog

  35. NewRelic • NewRelic の APM 、クランド連携、 agent 、ログ収集を行うと問題発生時に以下のよう なことがワンストップできるようになる。 ◦

    エラーレートの可視化 ◦ 発生したエラーのスタックトレースを表示 ▪ どの API( パス ) を叩かれたのかもわかる ◦ そのエラーが発生したときのトランザクション中のログを一覧で表示 • これによって問題発生箇所、影響範囲、原因が非常に素早く把握することができる
  36. 適切なログ出力 • NewRelic で調査しやすくなったとはいえ、適切なログが出力されていないとそこで息 詰まる。 • なにか問題が起きたときに原因調査するための情報があるか?という視点でログ出 力を行う ◦ 本来発生しない例外をキャッチした場合、その内容をエラーログに出力する

    ◦ 外部連携 (SaaS 含む ) をする場合、その Request/Response を INFO ログとして出力する ◦ Web アプリケーション場合 Request のログを出力する (API であれば Response もログ出力する ) ▪ 秘匿情報はマスクするのは前提 ◦ 大きいバッチ処理をする場合経過状況を INFO ログに出力する
  37. 試験性(testability) • システム、製品または構成要素について試験基準を確立することが出来、その基準 が満たされているかどうかを決定するために試験を実行することができる有効性及 び効率性 • つまり、「プロダクトの受け入れ条件など決めて、それを満たせているかどうかをテス トできるかどうか」

  38. テスト駆動開発(TDD) 「動作するきれいなコード」を書くためのプログラミングプラクティス シンプルなテスト駆動開発のルール • まずはシンプルな自動テストを一つ書く • すべてのテストを走らせ、新しいテストの失敗を確認する • 小さな変更を行う •

    すべてのテストを走らせ、すべて成功することを確認する • リファクタリングを行って重複を除去する
  39. テストカバレッジ • ソフトウェアコードのうちテストがなされている比率 ( 網羅率 ) • テストカバレッジが 100 %であれば良いかというとそういう訳ではない。

    コードカバレッジは、コードのテストされていない部分を発見するための有用なツールである。ただテ スト自体がどれだけ良いかという指標としては、テストカバレッジはほとんど役に立たない。 カバレッジの数値がほしい理由はわかる。テストが十分かを知りたいのだ。カバレッジの数値が低い 場合、たとえば 50% 以下の場合は、おそらく問題があるだろう。けれど高いカバレッジの数値にはあま り意味はない。ダッシュボードの数字に意味がなくなる助けをするだけだ。 from: https://bliki-ja.github.io/TestCoverage/
  40. 質の良いテストを書く必要がある

  41. 質の良いテストコードを書く技術 • 3 角測量 ◦ 一つのメソッドをテストするとき、 2 つ以上の実例を持ってテストをする ▪ それによってメソッドの実装の一般化が抽出される

    ▪ ただテストコードの重複によるテスト実行速度の悪化にもつながるので、テストコードを書くとき のフローの中で行うが、実装・テストともに完了したら重複を除去することもある • 欠陥挿入 ◦ プロダクトコードの任意の行の意味合いを変えて、テストが失敗するかどうかを検証する ◦ もし失敗しない場合は適切にテストが書かれていないこと ( 漏れがある ) を示しているのでテストの追 加・修正が必要だとわかる
  42. 修正性(modifiability) • 欠陥の取り込みも既存の製品品質の低下もなく、有効的に、かつ、効率的に製品ま たはシステムを修正することができる。 • つまり、バグやパフォーマンスの悪化などを起こさずにどれだけ早く機能の追加・修 正ができるかどうか

  43. 修正性を高める技術 • 他の要素を高めること = 修正性を高めること ◦ モジュール性 ◦ 再利用性 ◦

    解析性 ◦ 試験性
  44. 質の高いコードを書いて、 良いソフトウェアを作って、 売上をあげて 良い給料を得て よりプログラミングを楽しんでいこうな!

  45. 参考書籍 • クリーンアーキテクチャ • On Lisp • UNIX という考え方 •

    テスト駆動開発
  46. 参考資料 • 質とスピード〜ソフトウェア開発の典型的な誤解を解く〜 (2020 秋バージョン ) ◦ https://speakerdeck.com/twada/quality-and-speed-2020-autumn-edition • つながる世界のソフトウェア品質ガイド

    ◦ https://www.ipa.go.jp/files/000044964.pdf • X 25010 : 2013 (ISO / IEC 25020 : 2011 ) ◦ http://kikakurui.com/x25/X25010-2013-01.html • 開発者が知っておくべき SOLID の原則 ◦ https://postd.cc/solid-principles-every-developer-should-know/ • 単一責任の原則 (Sigle responsibility principle) について、もう一度考える ◦ https://www.ogis-ri.co.jp/otc/hiroba/others/OOcolumn/single-responsibility-principle.html • メタプログラミング ◦ https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%BF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A 9%E3%83%9F%E3%83%B3%E3%82%B0
  47. 参考資料 • Web アプリケーションのログ出力について指針を考えてみた ◦ https://blog.mmmcorp.co.jp/blog/2018/05/25/web_application_logging/ • 「質」のいいユニットテストを書くためのプラクティス ◦ https://speakerdeck.com/hgsgtk/practices-to-write-better-unit-test

    • テストカバレッジ ◦ https://bliki-ja.github.io/TestCoverage/ •