1. 概要(Overview)
Duplicate Observed Data は、
UI モデルやドメインモデルの中に 同じデータを二重に保持している 状態を解消するリファクタリングです。
よくあるのは:
- GUI クラスとデータモデルの両方が同じデータを持っていて、同期のためのコードが複雑化しているケース
- 一方が更新されてももう一方に反映されない → 不整合やバグの原因 になる
目的は以下の通りです:
- データの重複保持をやめ、唯一の場所に真実を置く(Single Source of Truth)
- 双方向同期の複雑さを取り除き、バグを減らす
- コードの責務を整理する
2. 適用シーン(When to Use)
- データを複数の場所で保持し、同期処理を書いている
- 「一方を更新したのに、もう一方に反映されない」不具合が発生している
- View や Controller が 同じ値を独自に持ってしまっている
- 同期のために無駄なイベント通知・リスナーが増えている
よくある匂い:
- Duplicate Data(データの重複)
- Shotgun Surgery(散弾銃のような変更)
3. 手順(Mechanics / Steps)
- 重複して保持しているデータを特定
- データを 唯一の「本当の持ち主」 に移す
- 他のクラスからは、そのデータを直接参照するように変更
- 必要であれば通知(Observer / Listener)を導入して表示更新を行う
- 同期コードや余分なフィールドを削除
4. Kotlin 例(Before → After)
Before:GUI と Model が同じデータを持っている
// モデル
class Person(var name: String)
// GUI 側が重複して name を持ってしまっている
class PersonWindow {
private var nameField: String = ""
fun loadData(person: Person) {
nameField = person.name
}
fun saveData(person: Person) {
person.name = nameField
}
}
-
PersonWindow
がname
を保持し、Person
との間で手動同期している - 更新忘れ・競合が起きやすい
After:モデルを唯一のデータ保持場所にする
// モデル
class Person(var name: String)
// GUI はモデルを直接参照し、データを持たない
class PersonWindow(private val person: Person) {
fun display() {
println("Name: ${person.name}")
}
fun changeName(newName: String) {
person.name = newName
}
}
-
PersonWindow
がname
を持たなくなり、重複が解消 -
Person
が唯一のデータ保持場所(Single Source of Truth) - GUI 側は表示や入力を通じてモデルを操作するだけ
さらに発展:Observer パターンで UI を更新
class Person(var name: String) {
private val observers = mutableListOf<() -> Unit>()
fun addObserver(observer: () -> Unit) {
observers.add(observer)
}
fun setName(newName: String) {
name = newName
observers.forEach { it() }
}
}
fun main() {
val person = Person("Alice")
person.addObserver { println("UI updated: ${person.name}") }
person.setName("Bob") // UI updated: Bob
}
→ モデルに変更通知を持たせることで、UI と同期を自動化できる。
5. 効果(Benefits)
- データの 重複保持を排除して一貫性を保証
- 双方向同期のコードが不要になり、シンプル化
- バグ(更新忘れ、競合)のリスクが減る
- データの責務が明確になり、保守性が向上
6. 注意点(Pitfalls)
- UI 側で「キャッシュ」や「一時的な編集内容」を持ちたい場合は、完全に排除できないケースもある
- Observer パターンやデータバインディングを導入すると、シンプルさと複雑さのバランスを取る必要がある
- Single Source of Truth を意識しつつ、「どのクラスが持ち主なのか」を設計段階で明確にすることが重要
まとめ
- Duplicate Observed Data は「同じデータを二重に持ち、同期で苦労している」状態を解消するリファクタリング
- 判断基準:このデータの唯一の持ち主はどこか?
- 基本思想:データは一箇所に集約し、他はそれを参照・購読するだけ