開発チームの設計力を強化するための考え方とやるべきこと
こんにちは。オンサイトのリードエンジニア、HK.Reisfeld です。
開発チームの設計力について、思いを馳せたことがあるでしょうか?
ある程度の経験を積むと、自身や開発チームの設計力に満足できなくなっていると感じる人もいらっしゃるかと思います。
今回は、どうすれば開発チームの設計力が上がっていくのか、と言うことに着目していこうと思います。
やるべきこと
設計力を高めるためにはチーム内の認識を統一し、実践を重ねてく中で改善し続けることが肝要です。そのためのポイントを以下にまとめてみました。
設計の目的と効果を共通理解にする
ソフトウェア設計の目的は
・変更コストを下げる
・変更が楽で安全になるように、コードの書き方やコードの整理の仕方を工夫する
といった点が挙げられます。
変更コストを下げるには、プログラムの変更に苦しまないようにすることが重要です。
逆にプログラムの変更に苦しんでいる場合は設計が上手くいっていない証拠になります。設計を改善することによって、変更は楽で安全なものになります。
設計の目的と効果をチームのメンバー全員が理解し、効果に実感を持つことが大切です。
設計するタイミング
開発の初期段階で集中的に行うよりも、ある程度コードが増えてきた段階で設計活動を繰り返し行う方が、効果が大きくなります。
毎日の開発作業の中で設計を改善し続けていくことで、改善効果が大きくなります。
コードの書き方や整理の仕方を、毎日メンバー全員が地道に工夫していくことが大切です。
設計力の「ばらつき」を改善する
ソフトウェアの設計力は、個人の経験や知識によって「ばらつき」があります。
多くの場合、「レベル」の違いよりも「ばらつき」が問題となります。
「ばらつき」を改善するには、設計の基本の考え方をメンバーで共有することが重要です。
共有するにあたって、設計のガイドラインやルールを細かく決めるのではなく、「設計の基本の考え方」をチームの共通理解にすることを推し進めます。
ルールを細かく決めてしまうと、設計の思考停止を起こしてしまうし、変更する際にどこに何が書いてあるのかが煩雑になり、より悪化させてしまいます。
基本の考え方を同じにして、チーム全体で一貫した設計を維持することが大切です。
設計力を高めるためにやるべきこと
「変更コスト」を下げるという設計の目的をチームのメンバー全員が理解し、それによる効果に実感を持つ。
毎日の開発作業の中で、メンバー全員が設計を改善し続ける
「設計の基本の考え方」を共通理解にし、メンバー間の「ばらつき」を改善する
設計の考え方
昨今のソフトウェア設計における重要な要素として、
・ドメイン駆動
・モデル駆動
・オブジェクト指向
といったものが挙げられます。
それぞれの考え方をチーム全員が明確に理解することが重要です。
ドメイン駆動
ドメイン駆動は、次の特徴があります。
■ ドメイン駆動の特徴
・プログラムをソフトウェアの対象領域(ドメイン)の用語や考え方に合わせる
・クラス名やパッケージ名を、業務の言葉と一致させる
・メソッド名や変数名も業務の言葉と一致させる
・クラス名と業務用語が一致していることにより、どこを変更すべきか簡単に特定できる
「業務の用語」に沿ってクラス設計やメソッド設計を行うことで、ソフトウェアの変更コストを大きく下げることができる、という考え方です。
ドメインモデル図(STEP1)
エンティティ、値オブジェクト、サービスのレイヤに分けて設計を行います。
【エンティティ】
・オブジェクトの同一性を識別する必要がある
・変更を管理する必要がある
【値オブジェクト】
・何かを計測する、定量化するなどを説明するときに使用する
・変更を管理する必要がない
【サービス】
・ドメインの重要な操作だが、エンティティや値オブジェクトの責務にすると不自然になる要素を割り当てる
▼ドメインモデル図例
ドメインモデル図(STEP2)
STEP1によって出現したモデルを、ドメインの概念に基づいて割り当てます。
モデル駆動
モデル駆動は、次の特徴があります。
■ モデル駆動の特徴
・「モデル」は現実世界の「模型」であり、現実世界を単純化して全体をひと目でわかるようにしたもの
・開発の初期にラフな模型を作成し、正しい全体像をわかりやすく伝えるために「モデル」を常に更新していく
・「モデル」に「世界地図」としての意味合いを持たせ、経験問わず全員で共有していく
システム全体を俯瞰して見ることができる「モデル」を用いることで、チーム全体の認識を合わせやすくするとともに、システム全体の見通しを良くする、という考え方です。
オブジェクト指向
オブジェクト指向は、次の特徴があります。
■ オブジェクト指向の特徴
・関連するデータとロジックを同じクラスに集めることで、見違えるように変更がやりやすくなる
・クラス名やパッケージ名を業務の用語に合わせることで、変更はさらに楽で安全になる
今や当たり前のように使われているオブジェクト指向ですが、元々は設計の考え方であり、設計において重要な要素になります。
カプセル化
メンバーへのアクセス修飾子(public、protected、private)を適切に設定することで、予期せぬバグを防いだり、仕様変更などを行う際に他のクラスへの影響を少なくすることができます。
これによって、クラスの独立性が高まります。
public class Sample {
public static void main (String[] args) {
Cat cat = new Cat();
cat.bark();
cat.changeCry(); // 鳴き声を変える
cat.bark();
}
}
// ねこクラス
class Cat {
private String cry = "ニャンニャンニャン";
public void bark() {
System.out.println("ねこ : " + cry);
}
public void changeCry() {
this.cry = "ニャ~オ";
}
}
▼
ねこ : ニャンニャンニャン
ねこ : ニャ~オ
継承
クラス連携の際、実クラスではなくその親クラスを使用することで、クラス間の結びつきが弱まり、より汎用的になります。
また、親クラスに共通となる処理を実装し、子クラスでは差分のみ実装することで、コードの重複を避けることができます。
public class Sample {
public static void main (String[] args) {
Cat pet = new Cat();
PetCare.giveBait(pet);
}
}
// 動物クラス
class Animal {
public void eat(String food) {
System.out.println(food + "を食べました。");
}
}
// ねこクラス
class Cat extends Animal {
private final String CRY = "ニャンニャンニャン";
public void bark() {
System.out.println("ねこ : " + CRY);
}
}
// ペットの世話用クラス
class PetCare {
// 引数が「動物クラス」のため、「ペットの世話用クラス」は「ねこクラス」専用のクラスではなくなる(汎用化)
// 「動物クラス」を継承する全てのクラスのインスタンスを引数として渡せる
public static void giveBait(Animal animal) {
animal.eat("エサ");
}
}
▼
エサを食べました。
ポリモーフィズム(多態性)
親クラス(抽象クラス)の型を使用して、クラス連携、およびメソッドの呼び出しまでを、実インスタンスを意識することなく行うことができます。
同名のメソッドを呼び出しても、クラスごとに違う振る舞いをさせることができます。
public class Sample {
public static void main (String[] args) {
Animal[] animal = Pet.getAnimal();
for (Animal pet: animal) {
// 実際のインスタンスを区別することなく、動物が鳴くという処理が実行できる
pet.bark();
}
}
}
// ペットクラス
class Pet {
public static Animal[] getAnimal() {
Animal[] animals = {new Cat(), new Dog(), new Frog(), new Duck()};
return animals;
}
}
// 動物クラス(抽象クラス)
abstract class Animal {
public abstract void bark();
}
// ねこクラス
class Cat extends Animal {
public void bark() {
System.out.println("ねこ:ニャンニャンニャン");
}
}
// いぬクラス
class Dog extends Animal {
public void bark() {
System.out.println("いぬ:ワンワンワン");
}
}
// かえるクラス
class Frog extends Animal {
public void bark() {
System.out.println("かえる:ガァーガァーガァー");
}
}
// あひるクラス
class Duck extends Animal {
public void bark() {
System.out.println("あひる:がぁーがぁーがぁー");
}
}
▼
ねこ:ニャンニャンニャン
いぬ:ワンワンワン
かえる:ガァーガァーガァー
あひる:がぁーがぁーがぁー
設計力を高めるための考え方
ドメイン駆動=「業務の用語」に沿ってクラス設計やメソッド設計を行う
モデル駆動=「モデル」を用いることで、チーム全体の認識を合わせやすくすると同時にシステム全体の見通しを良くする
オブジェクト指向=「カプセル化」「継承」「ポリモーフィズム」により、変更をやりやすくする
まとめ
設計力を強化するには、チーム全員で毎日設計に取り組むことが大切です。
システム全体を俯瞰して見ることができる「モデル」で認識を共有し、変更が安全になるように心がけていくことで、見違えるように設計力は強化されていきます。
個人として、チームとして、設計力の伸び悩みを実感していませんか?
実感していると言うことであれば、一度取り組んでみてもらえればと思います。
オンサイトではエンジニアチームのメンバーを募集しています!
少しでも興味のある方は採用サイトからご連絡ください。
リードエンジニア
1997年からエンジニアやってます。C言語から始まり、様々な言語を経験してきました。
生涯プログラマーをモットーにしています。
コードは見やすく、わかりやすく、シンプルに。
流行りに取り残されないように、日々精進していきます。