1 . 次の関数は、1つのパラメータオブジェクトに大量の値を詰め込んでいます。凝集度の観点から、何が問題になりやすいでしょうか?
function createReport(params) {
// params = {
// userId, userName, userAge,
// projectId, projectName,
// startDate, endDate,
// includePrivate, includeDeleted,
// ...
// }
// 複雑なレポート生成処理
}
A.
オブジェクトリテラルを使っていること
B.
パラメータが1つだけであること
C.
関係の薄い情報が1つの「なんでも詰め込み」オブジェクトに集められていて、関係性のまとまり(凝集)が見えにくいこと
D.
コメントを書いていること
解説: 「params」という1つの入れ物に、ユーザー情報・プロジェクト情報・期間・フラグなどの異なる関心ごとが詰め込まれており、何がまとまりなのか分かりづらくなっています。レポート条件・ユーザー条件・プロジェクト条件など、意味のまとまりごとに型やオブジェクトを分けることで、情報の凝集度を高め、理解しやすく変更しやすい設計になります。
2 . 次のコードは、注文処理とメール送信を1つの関数にまとめています。凝集度/結合度の観点から、最も問題がある点はどれでしょうか?
function placeOrder(order, db, mailer) {
// DBへ保存
db.insert('orders', order);
// ユーザーにメール送信
const message = `ご注文ありがとうございます:${order.id}`;
mailer.send(order.userEmail, message);
// 画面用メッセージを返す
return {
message: '注文完了しました',
orderId: order.id
};
}
A.
db と mailer を引数で受け取っていること
B.
DB保存・メール送信・画面用メッセージ作成という異なる責務が1つの関数に詰め込まれていること
C.
テンプレートリテラルを使っていること
D.
order.id を返していること
解説: この関数は「注文の永続化」「メール送信」「画面表示用メッセージ生成」という異なる責務を1つにまとめた低凝集な設計です。さらに、DBやメール送信への依存も直接書かれており結合度も高くなっています。DB操作・通知・UI用レスポンス生成は、それぞれ別の関数/モジュールに分けて凝集度を高め、依存は注入などで整理するのが望ましいです。
3 . 次のクラスは、リポジトリとサービスが分かれていません。結合度/凝集度の観点から、改善ポイントはどこでしょうか?
class UserManager {
constructor(db) {
this.db = db;
}
async findById(id) {
return this.db.query('SELECT * FROM users WHERE id = ?', [id]);
}
async changeEmail(id, newEmail) {
const user = await this.findById(id);
// ドメインルールのチェック(省略)
await this.db.execute('UPDATE users SET email = ? WHERE id = ?', [newEmail, id]);
}
}
A.
SQLを使っていること
B.
db をコンストラクタで受け取っていること
C.
データアクセス(リポジトリ)とドメインルール適用(サービス)が同じクラスに混在していること
D.
async/await を使っていること
解説: UserManager が「DBへの問い合わせ」と「ドメインルールの適用」の両方を担当しています。リポジトリ(データアクセス)とサービス(ビジネスルール)は役割を分けておくと、各モジュールの凝集度が高まり、テスト・変更・再利用がしやすくなります。
4 . 次のコードは、メール送信の方法が直接固定されています。結合度の観点から、どの改善が望ましいでしょうか?
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、外部サービスなど)は差し替え可能な形にすることで、結合度を下げられます。
5 . 次のクラスは、ログ出力と業務ロジックが混ざっています。凝集度/結合度の観点から、どのような改善が望ましいでしょうか?
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で渡すことで、結合度も下げられます。
6 . 次のコードは、1つのクラスが「設定の読み込み」と「業務ロジック」をまとめて行っています。凝集度の観点から、改善するべき点はどれでしょうか?
class ReportGenerator {
generate() {
const config = JSON.parse(localStorage.getItem('report-config') || '{}');
// config をもとにレポートを生成
}
}
A.
localStorage を使っていること
B.
JSON.parse を使っていること
C.
設定の取得とレポート生成という異なる責務が1つのクラスに混在していること
D.
クラス名が長いこと
解説: 「どこから設定を取得するか」と「設定をどう解釈してレポートを作るか」は本来別の関心ごとです。設定の取得は別のコンポーネントに任せ、ReportGenerator はレポート生成のロジックに集中させた方が、高凝集な設計になります。
7 . 次のコードは、法則的には「デメテルの法則(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()` のようなメソッドを用意するなど、問合せ先をなるべく直接の隣人に留めることで、変更に強い設計にできます。
8 . 次のコードは、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層とドメイン層の結合度を下げ、テストや差し替えをしやすくできます。
9 . 次のコードでは、テストしづらい結合が生まれています。結合度の観点から、どこが問題でしょうか?
function calculateDiscount(user, now = new Date()) {
if (user.isPremium && now.getDay() === 5) {
return 0.2;
}
return 0;
}
A.
user.isPremium を参照していること
B.
Date をデフォルト引数として new しており、時間に強く結合していること
C.
割引率が 0.2 であること
D.
getDay を使っていること
解説: 関数内部で現在時刻を new してしまうと、「時間」という外部環境と強く結合し、テストしづらくなります。now を必須引数にする・クロックサービスから取得するなどして、時間の扱いを分離することで、結合度を下げつつテスト容易性を高められます。
10 . 次のクラスは、ユーザー情報の表示と更新の両方を担当しています。結合度/凝集度の観点から、最も適切な改善方針はどれでしょうか?
class UserProfileScreen {
constructor(apiClient) {
this.apiClient = apiClient;
}
async loadUser(userId) {
const user = await this.apiClient.get(`/users/${userId}`);
this.render(user);
}
async updateUser(user) {
await this.apiClient.put(`/users/${user.id}`, user);
this.render(user);
}
render(user) {
// DOMを書き換えてプロフィール画面を描画
}
}
A.
APIクライアントの利用をやめて、すべてローカルストレージで管理する
B.
loadUser と updateUser を別クラスとして分離し、表示専用のViewと更新ロジックを分ける
C.
render メソッドを static にする
D.
userId をクラスのフィールドに保存しないようにする
解説: このクラスは「画面表示」と「APIを通した更新ロジック」を同時に担当しており、責務が混ざった低凝集なクラスです。ビュー(描画)とアプリケーションロジック(取得・更新)は分け、View は描画に専念し、ユースケースやサービス層がデータ取得・更新を担当する方が、高凝集かつ適度な結合度にできます。