1 . 次のコードは、メール送信の方法が直接固定されています。結合度の観点から、どの改善が望ましいでしょうか?
function sendPasswordReset(user, token) {
const url = `https://example.com/reset?token=${token}`;
const message = `こちらからパスワードを再設定してください: ${url}`;
SmtpClient.send(user.email, message);
}
A.
URLを https ではなく http にする
B.
SmtpClient に直接依存せず、メール送信を抽象化したインターフェースに依存する
C.
message を短くする
D.
user.email を使わないようにする
解説: SmtpClient という具体的な実装にべったり依存しており、メール送信の仕組みを変えるたびにこの関数を修正する必要があります。「メール送信インターフェース」を介して依存し、具体的な実装(SMTP、外部サービスなど)は差し替え可能な形にすることで、結合度を下げられます。
2 . 次のコードは、設定値への依存の仕方があまりよくありません。結合度の観点から適切な改善はどれでしょうか?
function connectDb() {
const client = new DbClient({
host: 'db.example.internal',
port: 5432,
user: 'app_user',
password: 'secret'
});
return client;
}
A.
DbClient のクラス名を短くする
B.
host や user などの設定値を、直接コードにベタ書きするのではなく設定オブジェクトや環境変数から受け取る
C.
port を 3306 に変更する
D.
password を空文字にする
解説: DB接続情報を関数内にベタ書きすると、接続先が変わるたびにコード修正が必要になり、設定との結合度が非常に高くなります。設定オブジェクトや環境変数などに外だしし、呼び出し側から渡すことで、コードと環境設定の結合度を下げつつ、再利用性とテストのしやすさを高めることができます。
3 . 次の関数は、複数のオブジェクトにまたがって状態を更新しています。結合度/凝集度の観点から、どのような設計リスクがありますか?
function completeTask(task, user, project) {
task.completed = true;
task.completedAt = new Date();
user.completedTaskCount++;
project.lastActivityAt = new Date();
}
A.
Date コンストラクタを2回呼んでいること
B.
task, user, project の3つの集約にまたがる更新ロジックを1つの関数にまとめており、複数のものと強く結合している
C.
completed フラグを true にしていること
D.
project に lastActivityAt を持たせていること
解説: 1つの関数が、task・user・project の3つの異なるオブジェクトに対する状態更新を一度に行っており、多くのものと結合した「何でも屋」になっています。どれか1つの仕様が変わるたびにこの関数も影響を受けるため、結合度が高すぎます。更新の責任をどの集約が持つべきかを見直し、モジュールごとに責務を整理する必要があります。
4 . 次のコードは、法則的には「デメテルの法則(LoD)」に違反しやすいパターンです。結合度の観点から、最も問題になりやすい点はどれでしょうか?
function getCustomerCity(order) {
return order.customer.address.city;
}
A.
return を使っていること
B.
city を使っていること
C.
order → customer → address → city とオブジェクトチェーンをたどりすぎて、内部構造に依存していること
D.
関数名が get から始まっていること
解説: `order.customer.address.city` のようにオブジェクトチェーンを深くたどると、「order の中身がどう実装されているか」に強く依存することになります。これはデメテルの法則に反し、結合度を高めてしまいます。`order.getCustomerCity()` のようなメソッドを用意するなど、問合せ先をなるべく直接の隣人に留めることで、変更に強い設計にできます。
5 . 次のクラスは、「メール送信」と「テンプレート生成」を同じ場所で行っています。凝集度/結合度の観点から、どの設計が望ましいでしょうか?
class MailService {
constructor(client) {
this.client = client;
}
sendWelcomeMail(user) {
const body = `ようこそ ${user.name} さん`;
this.client.send(user.email, body);
}
sendByeMail(user) {
const body = `ご利用ありがとうございました ${user.name} さん`;
this.client.send(user.email, body);
}
}
A.
MailService を2つに分割し、1つは send 専用、1つはテンプレート専用にする
B.
テンプレート生成を別クラスや関数に切り出し、MailService は「送る」責務に集中させる
C.
user.name を使わないようにする
D.
client を new するようにする
解説: メール送信の責務と、メール本文テンプレートの生成の責務が1つのクラスに混在しています。テンプレート生成は別のクラスやヘルパーに切り出し、MailService は「どこに何を送るか」に集中させた方が、高凝集かつテストしやすい設計になります。
6 . 次のコードは、UI層からドメインロジックへアクセスする際の結合の仕方を示しています。結合度を下げるために、最も有効な改善はどれでしょうか?
function onClickSaveButton() {
const user = collectFormData();
// ドメインロジックを直接 new
const service = new UserService();
service.save(user);
alert('保存しました');
}
A.
collectFormData を onClickSaveButton の外に移動する
B.
UserService のインスタンスを引数やDIコンテナから注入し、UIコードが new しないようにする
C.
alert のメッセージを変更する
D.
function ではなくアロー関数を使う
解説: UI層のハンドラで `new UserService()` してしまうと、UIとドメインロジックの具体クラスが強く結合してしまいます。依存性注入(DI)やコンストラクタ引数などを通じて外から渡すことで、UI層とドメイン層の結合度を下げ、テストや差し替えをしやすくできます。
7 . 次のコードは、1つの関数が多くのフラグ引数に依存しています。凝集度/結合度の観点から、どのような問題がありますか?
function renderList(items, showHeader, showFooter, highlightActive, allowDelete) {
// たくさんの条件分岐で描画を切り替える
}
A.
items が配列であること
B.
関数の引数としてフラグが多すぎて、1つの関数に多くの役割が詰め込まれている
C.
highlightActive を true にしていること
D.
allowDelete を false にしていること
解説: フラグ引数が増えすぎると、その関数が多くの描画パターンを抱え込むことになり、凝集度が低くなります。「どの画面で使うのか」「どんな用途なのか」に応じて関数やコンポーネントを分け、役割ごとの描画に集中させるのが、高凝集な設計に繋がります。
8 . 次のコードは、「凝集度が低いクラス」の例です。どこが問題でしょうか?
class Utils {
static formatDate(date) { /* ... */ }
static calculateTax(price) { /* ... */ }
static validateEmail(email) { /* ... */ }
static sendMail(to, body) { /* ... */ }
}
A.
static メソッドが使われていること
B.
クラス名が Utils であり、日付、税金計算、バリデーション、メール送信という関係の薄い機能が1つのクラスに詰め込まれていること
C.
メソッド名が英語なこと
D.
コメントがないこと
解説: ユーティリティクラスに関係の薄い機能をどんどん足していくと、「何でもあり」になり、凝集度が極端に低くなります。日付、課税、バリデーション、メール送信はそれぞれ別の関心ごととしてモジュールを分けることで、役割が明確な高凝集な設計になります。
9 . 次の2つのクラスは、互いにお互いを new しています。結合度の観点から、どのような問題がありますか?
class A {
constructor() {
this.b = new B(this);
}
}
class B {
constructor(a) {
this.a = a;
}
}
A.
クラス名が1文字で短すぎる
B.
A と B が循環参照しており、互いに強く結合している
C.
constructor を使っていること
D.
this を保存していること
解説: A が B を new し、B が A を引数で受け取る形になっており、循環依存・強結合の状態です。片方を変更するともう片方にも影響しやすく、テストや差し替えが困難になります。インターフェースを導入して依存方向を一方通行にする、ファクトリを挟むなどして、循環依存を避ける設計が望ましいです。
10 . 次のクラスは、ログ出力と業務ロジックが混ざっています。凝集度/結合度の観点から、どのような改善が望ましいでしょうか?
class PaymentService {
constructor(http) {
this.http = http;
}
async pay(order) {
console.log('PAYMENT START', new Date(), order.id);
const result = await this.http.post('/payments', { orderId: order.id });
console.log('PAYMENT END', new Date(), order.id, result.status);
return result;
}
}
A.
console.log を減らし、1か所だけにする
B.
ログ出力を別のロガーに委譲し、PaymentService は「支払い処理」に集中させる
C.
result を返さないようにする
D.
this.http をグローバル変数にする
解説: 支払い処理とログ出力が同じメソッド内に混在しており、責務が増えて凝集度が下がっています。ログはロガーインターフェースに委譲し、PaymentService は支払いのドメインロジックに集中させることで高凝集になります。ロガーは引数やDIで渡すことで、結合度も下げられます。