コーディング規約の重要性と無い場合の対処

ソースコードを書く上で、好みの書き方は個人によってある程度分かれてくると思います。
例えば、if文で定数を右辺に書くか左辺に書くかは、人によって好みが分かれます。

・右辺に書く例

・左辺に書く例

左辺に書く方法は「ヨーダ記法」と呼ばれ、「==」を誤って「=」と書いてしまった時に、代入が行われて処理が継続するのではなく、異常終了でミスを知らせてくれる、というメリットがあります。
しかし、入門者向けの書籍では右辺に定数を書く場合が多いので、左辺に書く方法の方が見慣れていて馴染みやすい、という方も少なくありません。

どちらの書き方にも良い点と悪い点があり、どちらが良いかは一概に言えません。


しかし、ソースコードの書き方で、明らかに悪い書き方があります。
それは、箇所によって書き方が混在した書き方です。
一人でソースコードを書いている場合は書き方が混在することは少ないのですが、複数人で開発している場合は書き方が混在することが良くあります。

人がソースコードを読む際は、ソースコードの書き方から、記述内容をある程度予測して効率良く読もうとします。
ここで、書き方が混在していると、記述内容の予測を誤り、分析ミスや改修ミスに繋がりかねません。

先の例で言うと、if文の定数が右辺に書かれている箇所と左辺に書かれている箇所が混在している場合、定数値と変数値を逆に読んでしまう可能性があります。
これは、分析ミスや改修ミスに繋がりかねません。
注意深く読めば読み誤りは防げますが、ソースコードを読む時にストレスを感じるでしょう。

ソースコードを効率良く読めるようにするために、書き方を統一することは重要です。
少なくとも、一つのソースファイル中では書き方を統一するのが望ましいです。


コーディング規約が存在している現場であれば、ソースコードの書き方が統一されやすくなります。
しかし、コーディング規約が存在していない現場もありますし、存在していたとしても規約が十分に網羅的でなかったり、規約が読まれなかったりすることもあります。

コーディング規約に頼れない場合は、周りのソースコードの書き方を真似る、というのが良い手になることが多いです。
先輩社員からソースコードの書き方を真似るように言われた人も少なくないと思いますが、そのように言われる理由の一つが統一性の確保です。

しかし、全く新しいプロダクトを作成する場合はソースコードの書き方を真似ることができませんし、真似るべきではない書き方というのも中にはあります。
ソースコードの書き方を真似られない場合の対処や、真似るべきではない書き方の判断のためには、一般的に良いとされるソースコードの書き方を覚えるのが良いです。
書籍のサンプルコードは一般的に良いとされるソースコードの書き方がされていますし、良いソースコードの書き方を解説した書籍も存在します。
また、言語によってはコーディング規約が公開されている場合もあるので、その場合はそれを参考にできます。
例えば、C#はMicrosoft社が公式にコーディング規約を公開していますし、JavaScriptはWordPress社がコーディング規約を公開しています。


いかがでしたでしょうか。

プログラムは単に動けば良いというものではなく、後々の保守を考えて読みやすく修正しやすいように書くべきです。
本文に書いた通り、一般的に良いとされるソースコ―ドや周りのソースコードを真似るだけでも一定の保守性を確保できるので、慣れていない内は意識的に真似ることをお勧めします。

ソース管理のアンチパターン「リポジトリ内のソースが信頼されない」

ソース管理を行う方法としては、今日ではGitベースのプラットフォーム(GitHub、Bitbucket等)を使用するのが主流です。
しかし、ソースコードがCOBOLで書かれているようなレガシーなシステムでは別の方法、極端な話、共有フォルダにソースを格納してライブラリアンが一括管理するような方法が適している場合もあります。

しかし、どのような方法でソースを管理するにしても、確実にアンチパターンと言えるケースがあります。
それは「リポジトリ内のソースが信頼されない」というケースです。


ソース管理が上手く行われていないと、リポジトリ内のソースが開発者から信頼されなくなります。
例えば、以下のようなケースです。

  • リポジトリ内のソースが最新化されておらず、本番環境にあるソースが最新であった
  • リポジトリ内のソースの改行コードに問題があり、そのままでは使用できない

リポジトリ内のソースが信頼されなくなった場合、開発者に「裏プロセス」を生み出す動機が生まれます。
ここで言う「裏プロセス」とは、リポジトリの管理者・運用担当者を介さない、開発者だけで完結するプロセスのことを指します。
具体的に言えば「開発者自ら本番環境からソースを取りに行くことで、修正元ソースを入手する」「開発者が手元にソースを持ち、そのソースを修正元とする」といったものです。

短期的に見ればこの裏プロセスは上手く行きそうに見えますが、裏プロセスには管理の目が行き届かない、という問題があります。
長期的には見れば、必ずデグレードの危険性が高まります。
特に、同じソースを複数の開発者が開発するようなケースでデグレードが発生しやすくなります。
それどころか、開発者の作業ミスでデグレードが発生することすらあります。


裏プロセスにより開発が行われる状況は、決して放置してはならない状況です。
リポジトリに問題があるのであれば、リポジトリの運用を見直して、その問題を解決する必要があります。
そして、問題を解決した旨を開発者に周知し、リポジトリからソースを取得するように呼びかける必要があります。

また、裏プロセスによる開発を行うことができないように環境やルールを整備することも場合によっては必要です。
例えば、「本番環境のソースを開発者から参照不可にする」という方法は環境整備の方法として検討に値しますし、「開発者に修正元ソースと修正後ソースと修正前後コンペアを提出してもらい、リポジトリ内のソースを元に修正されていることを確認する」という方法も不正なソースを元に開発が行われていないか確認する方法として機能します。


いかがでしたでしょうか。

今回は、経験則を共有するために、ソース管理のアンチパターンを書いてみました。
このようなことが一般的に言われることは少ないと思いますが、仕事をする上ではこのような経験則も重要だと思っています。

類似バグを効率的に見つけ出すための観点

品質を上げる上では、レビューやテストにてあるプログラムのバグを1つ見つけた場合、「他にも同じようなバグが潜んでいないか」という視点で追加でレビューやテストを入れるのが定石です。
類似バグが発生しやすいポイントを押さえて追加レビュー・追加テストを行うことで、少ない工数で品質を上げることができます。

類似バグが潜んでいないかどうかのチェックをIT業界の用語で「横展開」や「水平展開」と呼ぶのですが、このチェックを行うポイントの見極めにはいくつかのコツがあります。
今回の記事では、そのコツについて挙げていきたいと思います。

1.業務ロジックが類似している処理に目をつける

これが基本中の基本です。
「横展開」や「水平展開」と呼ばれるチェックは、多くの場合は業務ロジックが類似している処理のチェックになります。

例えば、小売店のシステムについて、新たな割引制度を導入するシステム対応を行っているとします。
そして、割引後の値段の算出について、端数の扱いの誤りに起因するバグが見つかったとします。
もし、割引後の値段を算出する記述が複数個所にあるのだとしたら、他の記述についても同じ誤りをしている可能性が高いので、それらの記述については全て追加レビューや追加テストをするべきです。
また、割引後の値段を算出するロジックを考える際に参考にしたロジックがあるのであれば、例え既存ロジックだとしてもその記述をチェックするべきです(本番運用でまだ見つかっていないバグが既存ロジック中に潜んでいる場合があります)。

2.特定の担当者や会社に着目する

スキルや仕事の進め方の違いにより、特定の担当者や会社の成果物にバグが集中して発生することがあります。
そのようなケースだと考えられる場合、特定の担当者や会社の成果物について集中的にレビューやテストを行うことで、効率的にバグを見つけ出すことができます。

特定の担当者や会社の成果物にバグが集中していることを見つけるためには、客観的な指標としては、メトリクス(品質の高さを示す数値)が参考になります。
例えば、「単体試験バグ数/STEP数」はソースコードの品質を推し量るのに役に立ちますし、「単体試験で見つけるべきバグの発生頻度」を結合試験で測っているのであればそれは単体試験の品質を推し量るのに役立ちます。

また、品質チェックを行う側に十分なスキルがあるのであれば、メトリクスを取るまでもなく、ちょっとしたやりとりから主観的な観点で品質の高さを推し量ることも可能です。

3.低品質のモジュールに着目する

仮に同程度のスキルで同じような仕事の進め方をする担当者・会社が集まっていたとしても、バグが集中的に潜んでいるモジュール(部品)とそうではないモジュールに分かれることが多いです。
一般的に、業務ロジックが複雑なモジュールや、多くの他モジュール・他システムと連携するモジュールは、バグが発生しやすいです。

バグが発生しやすいモジュールに対しても、集中的にレビューやテストを行うことで、効率的にバグを見つけ出すことができます。
注意点として、業務ロジックや連携が複雑なモジュールに関しては、そのモジュールを作成した担当者や管理者がどれだけレビュー・テストを行っても知識不足により十分にバグを見つけ出せない場合があります。
そのため、業務のスペシャリストや、連携先のモジュール・システムの担当者の力を借りることも重要になります。

低品質なモジュールについても、メトリクスのような客観的な指標を用いると見つけやすいです。
また、複雑性が高くバグを埋め込みやすいモジュールは設計段階で何となく気付くので、早い内から集中的にチェック・テストを行う計画を立てておくことも有効です。


いかがでしたでしょうか。

レビューやテストを完璧に行うことは時間的に不可能なので、バグを引き起こしやすい箇所に集中して行う必要があります。
(テストで境界値チェックが有効とされる理由もそこにあります)

今回は、バグを引き起こしやすい箇所の見分け方を、横展開という観点で書いてみました。
参考になれば幸いです。

O/Rマッピングの概要の説明

最近の現場では、SpringFrameworkの導入と共に、O/Rマッピングを取り入れた開発を行うことが増えてきました。
O/Rマッピングについて、背景にある考え方や必要な機能、問題点を簡単にまとめました。

【O/Rマッピングが生まれた背景】

O/Rマッピングは、RDBを用いたシステムにおいて、オブジェクト指向を実現するために用いられる手段の一つです。

RDBは、データ中心アプローチを実現するのに向いています。
「データ中心アプローチ」とは、「データやそれに付随する手続きは変化しにくい」という前提の元、テーブル定義やクエリ、ストアドプロシージャ等に機能を集中させることで、変化に強いシステムを作るアプローチです。

オブジェクト指向はデータ中心アプローチの後に広まった概念です。
システムを責務(クラス)に分解し、その責務同士の関係性をプログラミングで表現することで、変化に強いシステムを作るアプローチです。
仮にデータの持たせ方が変わるようなシステム更改を行う場合、データ中心アプローチよりも変更が容易になります。

先に述べた通り、RDBはデータ中心アプローチを実現するのに向いており、オブジェクト指向を実現するには向いていません。
そこで、SQLによるRDBの操作は最小限に止め、なるべくオブジェクト指向言語であるJava等で処理を実装する、という方針で実装されることが多くなりました。
(データ中心アプローチ/オブジェクト指向という面だけでなく、「カバレッジを取得しやすい」「静的解析をしやすい」といった言語の機能面からも、長いSQL文で実装するよりも短いSQL文+Javaで実装する方が好まれるようになりました)

O/Rマッピングはこの流れの中で生まれた考え方であり、オブジェクトとリレーション(RDB上のデータ)を対応付けようとする考え方です。
O/Rマッピングは、Java等のオブジェクト指向言語でRDBを扱いやすくする手段の一つとして使われることになります。

【O/Rマッピングの実現に必要な機能】

ざっくり言うと、RDBの存在を意識することなくオブジェクト指向言語でデータを扱えるようにする機能が必要です。

イメージとしては以下です。

  • Dtoクラスを参照する時に裏側でRDBのテーブルの読み込みが行われる
  • Dtoクラスを更新する時に裏側でRDBのテーブルの更新が行われる

この時にRDBに発行されるSQLは、O/Rマッパーの機能により自動生成されます。

(なお、SQL文をXMLファイル等に開発者自身で事前定義することが可能なO/Rマッパーも存在します。SQL文を事前定義する場合は、後述するO/Rマッパーの問題点が解消されますが、その代わりにRDBの存在を意識せずに実装するという思想も実現できなくなります。)

【O/Rマッピングを実現するツール(O/Rマッパー)】

代表的なO/Rマッパーとしては以下のようなものがあります。

  • Hibernate(JPAを実装したツール)
  • MyBatis(2010年にiBatisから改名)

【O/Rマッパーの問題点】

O/Rマッパーの問題点としては、「どのようなSQL文がどのタイミングで発行されているか分かりにくい」という点に尽きると思います。

具体的には、性能面の調査・改善が難しくなるという問題点があります。
O/Rマッパー導入により、以下のような問題点が引き起こされがちです。

  • ループ内でのSQL発行(N+1問題)
  • インデックスが使用されないSQLの生成
  • 遅いSQLの特定が困難(ソースコードをSQL文で調べても出てこない)

O/Rマッパーの機能を使いこなせばこれらの問題点を解決できるのですが、導入初期の段階で意識する必要がある他、開発者に対する教育コストが必要になります。

あくまでもSIerの場合ですが、SQLの知識・スキルは基本情報処理技術者試験で最低限のレベルは身に付けているはずですし、開発作業や運用作業にてRDBをSQLで操作する機会も多いので、O/RマッパーよりもSQL直書きの方が馴染みやすいという開発者は多いと思います。
SQLを自由に書けるなら性能問題を解決できるのに、O/Rマッパーを使用すると思い通りにSQLを発行・検索できずに性能問題を解決できない、と感じてしまう点が、開発者の不満点になってしまっていると思います。


いかがでしたでしょうか?

SQLを書くことに慣れた技術者からはO/Rマッピングが嫌われがちなようなのですが、O/Rマッピングには単に「SQL文を書かなくて良い」以外のメリットも存在し、そのメリットを享受するためにはコーディングスタイルの見直しとO/Rマッパーの学習が必要になります。
(ただし、O/Rマッパーの学習については、O/Rマッパーの種類毎に使い方が変わる上、現場毎でルールも異なっているので、SESとして働くのであれば現場に入ってからの学習で十分です)

今は多くの現場でO/Rマッパーを使う流れになってきているので、上記のようなことを理解しながら、上手く付き合っていくのが良いと思います。

JavaScript:オブジェクト型の定数値にはObject.freeze()を使う

プリミティブ型(Number型やString型等)の変数は、constで定義することで変更不可にできます。
これを利用して、定数値を定義することができます。

【サンプルコード】

【ChromeのデベロッパーツールのConsoleで実行】


しかし、オブジェクト型の場合、constで保持されるのは変数が指し示すアドレスであり、値は変更可能です。
そのため、定数値を定義するには適していません。

【サンプルコード】

【ChromeのデベロッパーツールのConsoleで実行】


オブジェクト型で定数値を定義したい場合は、Object.freeze()を使う必要があります。
これを使うことで、オブジェクト型の変数が指し示す値を変更不可にすることができます。

【サンプルコード】

【ChromeのデベロッパーツールのConsoleで実行】


いかがでしたでしょうか。

コーディングミスがない限りは定数値を書き変えることはないためお作法的なものに近いのですが、覚えておいて損はない内容でしょう。

来週以降は、コーディングからは一旦離れて、暗黙知的なものや経験則的なものを記事にしていきたいと思います!