Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

自己紹介 ● 新垣 雄志 ( あらかき ゆうじ ) ● Twitter: @arakaji ● 職歴 ○ 琉球インタラクティブ株式会社 ○ 株式会社 Payke ○ CBcloud 株式会社 ← NOW ● PHP 歴 ○ 前職、前前職ともにサーバーサイドで PHP を使っていた ■ CakePHP ■ FuelPHP ○ 現職ではサーバーサイドは Ruby を使っている

Slide 3

Slide 3 text

なぜこのテーマを選んだか? ● PHP は前職まではがっつり使っていたが、現職は主に Ruby で開発をしている ● そのため、個人的にいま「 PHP 」特有のテーマがみつからなかった ● プログラミング言語に依存しないテーマを探した ● 現職ではスタートアップあるあるのスピードと成長優先で書かれたプロダクトを引き継 ぎ、コードの保守性なども改善しながらもプロダクトの成長をさらに加速させるための 開発をしている最中 ● 「コードの品質」と「プロダクトの成長速度」をどう両立させていくかがテーマ ● そこで出会った名作

Slide 4

Slide 4 text

質とスピード

Slide 5

Slide 5 text

質とスピード ● 和田 卓人 (@t_wada) 先生の登壇資料 ● ソフトウェア開発においてよく言われる「コードの品質を一旦犠牲にしてスピード優先 で開発する」という言葉に対する誤解を解く内容 ● コードの品質と開発スピードはトレードオフではない ● 品質の高いコードを書くことにより、開発速度が上がる ● 質を上げながら開発速度も上げるにはどうすればいいか?ではない ● 質を上げることによって開発速度を上げる

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

次に出てくる疑問 ● 質の高いコードを書くことが開発速度を上げることに繋がることはわかった。 ● では「質の高いコードを書く」にはどうすればよいのか ? ● 今回はその「プログラミング言語に依存しない質の高いコードを書く技術」について の整理・言語化を試みた

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

SQuaREのソフトウェア品質モデル ● システム及びソフトウェアの多岐にわたるステークホルダ ( 利用者、発注者、開発者 など ) が持つ多様な品質要求を定義し評価するための基準として定義された国際規 格 SQuaRE シリーズ ● 品質モデルでは、品質を構成する上位の要素「品質特性」とこの品質特性をささえ る詳細化した下位の要素「品質副特性」を定義している

Slide 11

Slide 11 text

保守性の高いコードを書く技術 ● 今回掘り下げるのは「保守性」 ● 「意図した保守者によって、製品又は システムが修正することができる有効 性及び効率性の度合い」 ● 保守性を上げる = プロダクトの変更 速度を上げること

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

SOLID原則

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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)

Slide 16

Slide 16 text

単一責任の法則 ● 「モジュールを変更する理由はたったひとつだけであるべきである」 ● ソフトウェアを変更するのは、ユーザーやステークホルダーを満足させるため ● この「ユーザーやステークホルダー」が変更する理由になる。 ● ただし複数のユーザーやステークホルダーがシステムをおなじように変更したいと考 えることもある。 ● 変更を望む人たちをひとまとめのグループとして扱いため、そのグループをアクター と呼ぶ ● 「モジュールはたった一つのアクターに対して責務を負うべきである」

Slide 17

Slide 17 text

Employeeクラスの例 ● 給与システムにおける従業員クラスの例 ● 3 つのメソッドはそれぞれ別のアクターへ の責務を追っている ● calculatePay は経理 (CFO) ● reportHours は人事 (COO) ● save は DB 管理者 (CTO)

Slide 18

Slide 18 text

何が問題か? ● アクターの異なるメソッドで同じアルゴリズムを共 有してしまった場合、両方のメソッドに影響が出 てしまう。 ● アクターが異なる機能はアルゴリズムが一時的 に似ていても使われ方が変わるし変更タイミング も変わる ● アクターが異なるコードは最初からモジュール / クラスレベルで分離したほうがよい

Slide 19

Slide 19 text

再利用性(reusability) ● 「一つ以上のシステムに、又は他の資産づくりに、資産を使用することが出来る度合 い」 ● 既存コードを再利用することで新たなコードを書く必要をへらし生産性を上げる ○ ライブラリ ○ フレームワーク ○ SaaS ● 再利用しやすいコードを自分が書くことでチームメンバー、そして明日の自分の生 産性をあげる

Slide 20

Slide 20 text

再利用性を高めるコードを書くための技術/考え方 ● ボトムアッププログラミング ● 小さいものは美しい (Small is Beautiful) ● メタプログラミング

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

ボトムアッププログラミング ● プログラミング言語を自分たちの開発しているアプリケーションの適する形に変えて いくこと ● フレームワークやライブラリを使うのはそれと同じ ○ Laravel や CakePHP を導入することで PHP が Web アプリケーションの開発により適した形に拡張され る ○ aws-sdk のライブラリを導入することで、 AWS を操作するのに適した形に拡張される ● これをもっと小さい単位で、自分たちのアプリケーションコードを書くときにも行う

Slide 23

Slide 23 text

連想配列の値取得の例 連想配列内に指定したキーが存在する場合には その値を、存在しない場合には指定したデフォル ト値を返す。 一見シンプルだが以下の様な問題もある。 ● false と評価される空文字や 0 がある場合、 キー自体はあるのにデフォルト値がかえされ てしまう ● この差異に以外ときづかず特定ケースでバ グを発生させることが多々ある

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

小さいものは美しい ● 小さなプログラムはわかりやすい ● 小さなプログラムはシステムリソースにやさしい ● 小さなプログラムは他のツールとくみあわせしや すい ○ 再利用性を高める!!

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

メタプログラミングってPHPで出来る? ● メタプログラミングで一級市民的な言語はある ○ Lisp ○ Ruby ● PHP ではどうか? ○ マジックメソッドを使うことでメタプログラミングのようなことができる

Slide 29

Slide 29 text

Driverクラスのtype判別メソッドの定義 ● 配送ドライバーには複数種類ある ○ 軽貨物ドライバー (kei_car) ○ 一般貨物ドライバー (ippan_car) ● Driver インスタンスがどのタイプかを判別するた めの is_hogehoge() というメソッドを定義 ● 問題点 ○ DRIVER_TYPE が増えるたびに同じようなメソッドを再 定義しないといけない

Slide 30

Slide 30 text

Driverクラスのtype判別メソッドの定義 ● __call マジックメソッドは存在しないインスタン スメソッドがコールされたときに呼び出される ● __call マジックメソッド内で呼び出されたメソッ ド名を判別し、より抽象化された type 判別メ ソッドを呼び出す ● これによって DRIVER_TYPES の定数に値を 追加するだけで is_hoge というメソッドが使え るようになる

Slide 31

Slide 31 text

メタプログラミングのリスク ● デバッグが難しい ● コードが複雑かつわかりづらくなりがち ● 使うことによって得られるメリットとデメリットを天秤にかけて使うかどうか判断したほう がよい ● もし使うならメタプログラミングの部分ににはバグが入り込まないように厳密にテストを することと使い方を説明するドキュメント(コメント ) が必要。

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

NewRelic ● NewRelic の APM 、クランド連携、 agent 、ログ収集を行うと問題発生時に以下のよう なことがワンストップできるようになる。 ○ エラーレートの可視化 ○ 発生したエラーのスタックトレースを表示 ■ どの API( パス ) を叩かれたのかもわかる ○ そのエラーが発生したときのトランザクション中のログを一覧で表示 ● これによって問題発生箇所、影響範囲、原因が非常に素早く把握することができる

Slide 36

Slide 36 text

適切なログ出力 ● NewRelic で調査しやすくなったとはいえ、適切なログが出力されていないとそこで息 詰まる。 ● なにか問題が起きたときに原因調査するための情報があるか?という視点でログ出 力を行う ○ 本来発生しない例外をキャッチした場合、その内容をエラーログに出力する ○ 外部連携 (SaaS 含む ) をする場合、その Request/Response を INFO ログとして出力する ○ Web アプリケーション場合 Request のログを出力する (API であれば Response もログ出力する ) ■ 秘匿情報はマスクするのは前提 ○ 大きいバッチ処理をする場合経過状況を INFO ログに出力する

Slide 37

Slide 37 text

試験性(testability) ● システム、製品または構成要素について試験基準を確立することが出来、その基準 が満たされているかどうかを決定するために試験を実行することができる有効性及 び効率性 ● つまり、「プロダクトの受け入れ条件など決めて、それを満たせているかどうかをテス トできるかどうか」

Slide 38

Slide 38 text

テスト駆動開発(TDD) 「動作するきれいなコード」を書くためのプログラミングプラクティス シンプルなテスト駆動開発のルール ● まずはシンプルな自動テストを一つ書く ● すべてのテストを走らせ、新しいテストの失敗を確認する ● 小さな変更を行う ● すべてのテストを走らせ、すべて成功することを確認する ● リファクタリングを行って重複を除去する

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

質の良いテストを書く必要がある

Slide 41

Slide 41 text

質の良いテストコードを書く技術 ● 3 角測量 ○ 一つのメソッドをテストするとき、 2 つ以上の実例を持ってテストをする ■ それによってメソッドの実装の一般化が抽出される ■ ただテストコードの重複によるテスト実行速度の悪化にもつながるので、テストコードを書くとき のフローの中で行うが、実装・テストともに完了したら重複を除去することもある ● 欠陥挿入 ○ プロダクトコードの任意の行の意味合いを変えて、テストが失敗するかどうかを検証する ○ もし失敗しない場合は適切にテストが書かれていないこと ( 漏れがある ) を示しているのでテストの追 加・修正が必要だとわかる

Slide 42

Slide 42 text

修正性(modifiability) ● 欠陥の取り込みも既存の製品品質の低下もなく、有効的に、かつ、効率的に製品ま たはシステムを修正することができる。 ● つまり、バグやパフォーマンスの悪化などを起こさずにどれだけ早く機能の追加・修 正ができるかどうか

Slide 43

Slide 43 text

修正性を高める技術 ● 他の要素を高めること = 修正性を高めること ○ モジュール性 ○ 再利用性 ○ 解析性 ○ 試験性

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

参考書籍 ● クリーンアーキテクチャ ● On Lisp ● UNIX という考え方 ● テスト駆動開発

Slide 46

Slide 46 text

参考資料 ● 質とスピード〜ソフトウェア開発の典型的な誤解を解く〜 (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

Slide 47

Slide 47 text

参考資料 ● 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/ ●