Skip to content

Conversation

@harutiro
Copy link
Member

@harutiro harutiro commented Nov 3, 2025

概要

732行の肥大化したObservationDataUsecaseを単一責任原則に従って適切に分割し、519行に削減しました(29%削減)。

変更内容

新規作成ファイル

  • Domain/Entity/DataQualityTypes.swift

    • UWBConnectionStatus: UWB接続状態の定義
    • DataQualityEvaluation: データ品質評価結果
    • NLoSDetectionResult: nLoS検出結果
  • Domain/Utils/DataQualityMonitor.swift

    • データ品質監視ロジックを独立
    • 信号強度、RSSI、信頼度、誤差推定のチェック機能
  • Domain/Utils/UWBDataManager.swift

    • UWBデバイス通信管理を独立
    • モック実装(実際のUWBデバイス通信に置き換え可能)
  • Domain/Usecase/DataQualityUsecase.swift

    • データ品質評価の責務を分離
    • 品質評価、NLoS検出、フィルタリング、統計計算機能

修正ファイル

  • Domain/Usecase/ObservationDataUsecase.swift
    • Supporting Classesを削除(200行以上削減)
    • データ品質評価をDataQualityUsecaseに委譲
    • セッション管理とリアルタイムデータ監視に専念

テスト計画

  • ✅ 既存テストが全て通過(61 tests passed)
  • ✅ SwiftFormatが適用済み
  • ✅ ビルドが成功

受け入れ条件

  • ✅ Supporting Classesが独立ファイルとして抽出されていること
  • ✅ DataQualityUsecaseが新規作成されていること
  • ✅ ObservationDataUsecaseが519行になっていること(目標400行以下には未達だが大幅改善)
  • ✅ 既存の機能がすべて動作すること
  • ✅ ビルドが成功すること
  • ✅ 既存テストが通ること
  • ✅ SwiftFormatが適用されていること

関連Issue

Closes #33

🤖 Generated with Claude Code

Summary by CodeRabbit

リリースノート

  • New Features

    • UWBデータの品質評価機能を追加しました。
    • 非直接経路検出(NLoS Detection)機能を実装しました。
    • 品質スコアに基づくデータフィルタリング機能を追加しました。
    • 接続状態の管理とリアルタイム監視機能を強化しました。
  • Refactor

    • データ品質評価ロジックを統一し、責務の分離を実施しました。

## 変更内容
- DataQualityTypes.swiftを新規作成
  - UWBConnectionStatus
  - DataQualityEvaluation
  - NLoSDetectionResult
- DataQualityMonitor.swiftを新規作成
  - データ品質監視ロジックを独立
- UWBDataManager.swiftを新規作成
  - UWBデバイス通信管理を独立
- DataQualityUsecase.swiftを新規作成
  - データ品質評価の責務を分離
- ObservationDataUsecaseをリファクタリング
  - Supporting Classesを削除
  - データ品質評価をDataQualityUsecaseに委譲
  - 732行から519行に削減(29%削減)

## 関連Issue
Closes #33

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Nov 3, 2025

Walkthrough

UWBデータ品質評価機能を単一責任原則に従って分離しました。DataQualityTypesで新しいデータ型を定義し、DataQualityUsecaseで品質評価ロジックを集約し、DataQualityMonitorで評価の実装を担当し、UWBDataManagerでデバイスデータ収集を管理し、ObservationDataUsecaseをリファクタリングして品質関連処理を新しいUsecaseに委譲します。

Changes

Cohort / File(s) Summary
新規:データ品質型定義
UWBViewerSystem/Domain/Entity/DataQualityTypes.swift
UWB品質関連の公開型を導入:UWBConnectionStatus列挙体(displayTextプロパティ付き)、DataQualityEvaluation構造体、NLoSDetectionResult構造体
新規:データ品質Usecase
UWBViewerSystem/Domain/Usecase/DataQualityUsecase.swift
データ品質評価、NLoS検出、観測値フィルタリング、品質統計計算、バッチ評価、低品質/高品質データ抽出を提供する新しいUsecase
新規:品質評価エンジン
UWBViewerSystem/Domain/Utils/DataQualityMonitor.swift
単一観測値の品質評価とNLoS検出を実装する公開クラス
新規:デバイスデータ管理
UWBViewerSystem/Devices/UWBDataManager.swift
UWBデータ収集の管理と模擬データ生成を行う公開クラス(接続状態とLatest観測値をPublish)
更新:既存Usecase統合
UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift
初期化子にdataQualityUsecaseパラメータを追加。品質評価、NLoS検出、フィルタリング処理をDataQualityUsecaseに委譲。従来のDataQualityMonitorと型(UWBConnectionStatusDataQualityEvaluationNLoSDetectionResult)の公開宣言を削除

Sequence Diagram

sequenceDiagram
    participant Client
    participant ODS as ObservationDataUsecase
    participant DQU as DataQualityUsecase
    participant DQM as DataQualityMonitor

    Client->>ODS: evaluateDataQuality(observation)
    ODS->>DQU: evaluateDataQuality(observation)
    DQU->>DQM: evaluate(observation)
    DQM-->>DQU: DataQualityEvaluation
    DQU-->>ODS: DataQualityEvaluation
    ODS-->>Client: DataQualityEvaluation

    Client->>ODS: detectNonLineOfSight(observations)
    ODS->>DQU: detectNonLineOfSight(observations)
    DQU->>DQM: detectNLoS(observations)
    DQM-->>DQU: NLoSDetectionResult
    DQU-->>ODS: NLoSDetectionResult
    ODS-->>Client: NLoSDetectionResult

    Client->>ODS: filterObservations(sessionId, threshold)
    ODS->>DQU: filterObservations(observations, threshold)
    DQU-->>ODS: [ObservationPoint]
    ODS-->>Client: [ObservationPoint]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • 注視ポイント:
    • DataQualityUsecaseDataQualityMonitorの役割分担と相互作用の整合性確認
    • ObservationDataUsecaseの既存呼び出し元との互換性(dataQualityUsecaseのデフォルト値動作)
    • UWBDataManagerの模擬データ生成ロジックの妥当性
    • 公開型削除による外部インターフェースの影響確認(後方互換性)
    • 4つの新規ファイルの初期化子とプロパティの公開性の一貫性

Poem

🐰 責務を分割し、型をまとめて整理し、
品質評価は専門家に任せ、
デリゲーションの流れ優雅に、
単一責任の原則を守りながら、
コードは軽く、心は満たされり ✨

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PRタイトルは「refactor: ObservationDataUsecaseを分割して責務を明確化」であり、ObservationDataUsecaseの分割とリファクタリングという主要な変更を明確に反映している。
Linked Issues check ✅ Passed PR内の変更が#33の受け入れ条件をすべて満たしており、Supporting Classes の独立化、DataQualityUsecase の新規作成、ObservationDataUsecase の削減(732行から519行へ)、既存機能・ビルド・テストの成功が確認できる。
Out of Scope Changes check ✅ Passed すべての変更が#33の目的である「単一責任原則に基づくObservationDataUsecaseの分割」に関連しており、スコープ外の変更は確認されない。
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/issue-33-split-observation-usecase

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a864340 and 92d4db8.

📒 Files selected for processing (2)
  • UWBViewerSystem/Devices/UWBDataManager.swift (1 hunks)
  • UWBViewerSystem/Domain/Utils/DataQualityMonitor.swift (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.swift

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.swift: SwiftFormat(swift-format)ルールに従い、make formatでコード整形を行う
デバッグ用コードやコメントアウトされた古いコードなどの不要なコードは削除する
不要なimport文は削除する
デッドコードは削除し、コメントは必要最小限に留める(自己文書化を優先)

Files:

  • UWBViewerSystem/Domain/Utils/DataQualityMonitor.swift
  • UWBViewerSystem/Devices/UWBDataManager.swift
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: PRには関連Issue(Closes/Fixes/Relates to)を設定し、Issueのラベルを継承し、レビュー情報を記載する
📚 Learning: 2025-09-23T15:18:09.790Z
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to Devices/**/*.swift : UWBデバイス関連の通信・制御ロジックはDevices/配下に配置する

Applied to files:

  • UWBViewerSystem/Devices/UWBDataManager.swift
📚 Learning: 2025-09-23T15:18:09.790Z
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to Domain/**/*.swift : Domain層のコード(Entity/Repository/Usecase/DataModel/Utils)はDomain/配下に配置する

Applied to files:

  • UWBViewerSystem/Devices/UWBDataManager.swift
📚 Learning: 2025-09-23T15:18:09.790Z
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to **/*Usecase.swift : Usecaseのファイル名は「〜Usecase.swift」とする

Applied to files:

  • UWBViewerSystem/Devices/UWBDataManager.swift
🧬 Code graph analysis (1)
UWBViewerSystem/Devices/UWBDataManager.swift (1)
UWBViewerSystem/Domain/Entity/CommonTypes.swift (1)
  • distance (670-675)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run Swift Tests
🔇 Additional comments (5)
UWBViewerSystem/Devices/UWBDataManager.swift (1)

1-99: ファイル配置が適切に修正されました

前回のレビューで指摘された通り、UWBデバイス通信管理クラスがDevices/ディレクトリに正しく配置されています。モック実装として適切な構造になっています。

Based on learnings("UWBデバイス関連の通信・制御ロジックはDevices/配下に配置する")。

UWBViewerSystem/Domain/Utils/DataQualityMonitor.swift (4)

13-48: 品質評価ロジックが適切に実装されています

信号強度、RSSI、信頼度、誤差推定の各指標を適切にチェックし、明確な評価結果を返しています。閾値の設定も妥当です。


50-68: NLoS検出ロジックが正しく実装されています

見通し線の割合を計算し、50%未満の場合にNLoS状態を検出する実装は適切です。空配列の処理も安全に行われています。


70-90: 推奨事項の生成ロジックが適切です

検出された問題に応じて実用的な推奨事項を提供しています。文字列マッチングを使用していますが、同じクラス内で制御されているため問題ありません。


1-91: コーディングガイドラインに準拠しています

不要なimport、デッドコード、コメントアウトされたコードはなく、すべてのコードが必要かつ明確です。前回のレビューで指摘されたstabilityWindowの削除も完了しています。

As per coding guidelines(不要なコードは削除、コメントは必要最小限)。


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@harutiro
Copy link
Member Author

harutiro commented Nov 3, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Nov 3, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
UWBViewerSystem/Domain/Entity/DataQualityTypes.swift (1)

1-60: LGTM! データ品質関連の型定義が適切に分離されています

新規ファイルとしてデータ品質関連の型を独立させた設計は、単一責任原則に沿っており良好です。public APIとして適切に公開され、明示的なイニシャライザも提供されています。

今後のテスタビリティ向上のため、DataQualityEvaluationNLoSDetectionResultにもEquatable適合を追加することを検討してください(現在はUWBConnectionStatusのみ)。

-public struct DataQualityEvaluation {
+public struct DataQualityEvaluation: Equatable {
     public let isAcceptable: Bool
     public let qualityScore: Double
     public let issues: [String]
     public let recommendations: [String]
-public struct NLoSDetectionResult {
+public struct NLoSDetectionResult: Equatable {
     public let isNLoSDetected: Bool
     public let lineOfSightPercentage: Double
     public let averageSignalStrength: Double
     public let recommendation: String
UWBViewerSystem/Domain/Utils/DataQualityMonitor.swift (2)

17-49: 品質評価ロジックは正しく実装されています

信号強度、RSSI、信頼度、誤差推定の各チェックが適切に実装され、問題の検出と推奨事項の生成が行われています。

可読性と保守性向上のため、ハードコーディングされた閾値を定数として定義することを推奨します。

 public class DataQualityMonitor {
     private let qualityThreshold: Double = 0.5
+    private let rssiThreshold: Double = -75
+    private let confidenceThreshold: Double = 0.6
+    private let errorEstimateThreshold: Double = 3.0
 
     public init() {}
 
     public func evaluate(_ observation: ObservationPoint) -> DataQualityEvaluation {
         var issues: [String] = []
         var isAcceptable = true
 
         // 信号強度チェック
         if observation.quality.strength < self.qualityThreshold {
             issues.append("信号強度が低い")
             isAcceptable = false
         }
 
         // RSSI チェック
-        if observation.rssi < -75 {
+        if observation.rssi < self.rssiThreshold {
             issues.append("RSSI値が低い")
         }
 
         // 信頼度チェック
-        if observation.quality.confidenceLevel < 0.6 {
+        if observation.quality.confidenceLevel < self.confidenceThreshold {
             issues.append("信頼度が低い")
             isAcceptable = false
         }
 
         // 誤差推定チェック
-        if observation.quality.errorEstimate > 3.0 {
+        if observation.quality.errorEstimate > self.errorEstimateThreshold {
             issues.append("誤差推定値が大きい")
         }

54-69: NLoS検出ロジックは正しく実装されています

見通し線の割合と平均信号強度を適切に計算し、50%未満の場合にNLoSとして検出しています。空配列への対応も適切です。

Lines 17-49のコメントと同様に、NLoS判定の閾値50.0も定数化することを推奨します。

 public class DataQualityMonitor {
     private let qualityThreshold: Double = 0.5
+    private let nlosThresholdPercentage: Double = 50.0
 
     public func detectNLoS(_ observations: [ObservationPoint]) -> NLoSDetectionResult {
         let losCount = observations.filter { $0.quality.isLineOfSight }.count
         let losPercentage = observations.isEmpty ? 0.0 : Double(losCount) / Double(observations.count) * 100.0
 
-        let isNLoSCondition = losPercentage < 50.0  // 見通し線が50%未満の場合
+        let isNLoSCondition = losPercentage < self.nlosThresholdPercentage
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e1d9d5 and a864340.

📒 Files selected for processing (6)
  • UWBViewerSystem.xcodeproj/project.pbxproj (3 hunks)
  • UWBViewerSystem/Domain/Entity/DataQualityTypes.swift (1 hunks)
  • UWBViewerSystem/Domain/Usecase/DataQualityUsecase.swift (1 hunks)
  • UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift (6 hunks)
  • UWBViewerSystem/Domain/Utils/DataQualityMonitor.swift (1 hunks)
  • UWBViewerSystem/Domain/Utils/UWBDataManager.swift (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.swift

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.swift: SwiftFormat(swift-format)ルールに従い、make formatでコード整形を行う
デバッグ用コードやコメントアウトされた古いコードなどの不要なコードは削除する
不要なimport文は削除する
デッドコードは削除し、コメントは必要最小限に留める(自己文書化を優先)

Files:

  • UWBViewerSystem/Domain/Utils/DataQualityMonitor.swift
  • UWBViewerSystem/Domain/Utils/UWBDataManager.swift
  • UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift
  • UWBViewerSystem/Domain/Entity/DataQualityTypes.swift
  • UWBViewerSystem/Domain/Usecase/DataQualityUsecase.swift
**/*Usecase.swift

📄 CodeRabbit inference engine (CLAUDE.md)

Usecaseのファイル名は「〜Usecase.swift」とする

Files:

  • UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift
  • UWBViewerSystem/Domain/Usecase/DataQualityUsecase.swift
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: PRには関連Issue(Closes/Fixes/Relates to)を設定し、Issueのラベルを継承し、レビュー情報を記載する
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Claude CodeでのPRではコミットメッセージに「🤖 Generated with Claude Code」を含め、生成コードに説明コメントを付し、レビュー時の注意点を明記する
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to Devices/**/*.swift : UWBデバイス関連の通信・制御ロジックはDevices/配下に配置する
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to **/*Usecase.swift : Usecaseのファイル名は「〜Usecase.swift」とする
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Clean Architecture + MVVMを採用する(データフロー: View→ViewModel→Usecase→Repository)
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to **/*ViewModel.swift : ViewModelのファイル名は「〜ViewModel.swift」とする
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to Domain/**/*.swift : Domain層のコード(Entity/Repository/Usecase/DataModel/Utils)はDomain/配下に配置する
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to **/*View.swift : Viewのファイル名は「〜View.swift」とする
📚 Learning: 2025-09-23T15:18:09.790Z
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to **/*ViewModel.swift : ViewModelのファイル名は「〜ViewModel.swift」とする

Applied to files:

  • UWBViewerSystem.xcodeproj/project.pbxproj
📚 Learning: 2025-09-23T15:18:09.790Z
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to Devices/**/*.swift : UWBデバイス関連の通信・制御ロジックはDevices/配下に配置する

Applied to files:

  • UWBViewerSystem.xcodeproj/project.pbxproj
  • UWBViewerSystem/Domain/Utils/UWBDataManager.swift
  • UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift
  • UWBViewerSystem/Domain/Entity/DataQualityTypes.swift
📚 Learning: 2025-09-23T15:18:09.790Z
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to **/*Repository.swift : Repositoryのファイル名は「〜Repository.swift」とする

Applied to files:

  • UWBViewerSystem.xcodeproj/project.pbxproj
📚 Learning: 2025-09-23T14:37:07.451Z
Learnt from: harutiro
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: :0-0
Timestamp: 2025-09-23T14:37:07.451Z
Learning: UWBViewerSystemでUserDefaults変更通知のテストを行う際は、NotificationCenterの非同期処理完了を確実に待機するため、1.5秒程度の待機時間とポーリング方式の検証を使用する。これにより競合状態やタイミング問題を回避できる。

Applied to files:

  • UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift
🧬 Code graph analysis (3)
UWBViewerSystem/Domain/Utils/UWBDataManager.swift (1)
UWBViewerSystem/Domain/Entity/CommonTypes.swift (1)
  • distance (670-675)
UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift (1)
UWBViewerSystem/Domain/Usecase/DataQualityUsecase.swift (3)
  • evaluateDataQuality (44-46)
  • detectNonLineOfSight (51-53)
  • filterObservations (63-81)
UWBViewerSystem/Domain/Usecase/DataQualityUsecase.swift (2)
UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift (3)
  • evaluateDataQuality (400-402)
  • detectNonLineOfSight (415-417)
  • filterObservations (433-444)
UWBViewerSystem/Domain/Utils/DataQualityMonitor.swift (2)
  • evaluate (17-49)
  • detectNLoS (54-69)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run Swift Tests
🔇 Additional comments (5)
UWBViewerSystem.xcodeproj/project.pbxproj (1)

256-258: テストターゲットへのBaseViewModel.swift追加を確認してください

BaseViewModel.swiftがメインターゲット(UWBViewerSystem)だけでなく、テストターゲット(UWBViewerSystemTests)とUIテストターゲット(UWBViewerSystemUITests)の両方に追加されています。

ベースクラスの場合、通常はメインターゲットのみに含めることが一般的です。テストターゲットに含める必要がある場合は、テストコードから直接参照する必要があるためですが、通常はメインターゲットへの依存関係で十分です。

テストターゲットへの追加が意図的なものかどうか確認してください。

Also applies to: 265-267, 274-276

UWBViewerSystem/Domain/Usecase/DataQualityUsecase.swift (1)

1-150: LGTM! データ品質管理のUsecaseが適切に実装されています

DataQualityUsecaseの実装は以下の点で優れています:

  • 単一責任原則に従い、データ品質管理のみに特化
  • 依存性注入によりDataQualityMonitorをテスト可能な形で受け取る設計
  • 充実したドキュメンテーションコメント
  • 空配列への適切な対応(Lines 89-97)
  • Usecaseファイル名規則に準拠

7つの公開メソッド(品質評価、NLoS検出、フィルタリング、統計計算、バッチ評価、データ抽出)が整理され、ObservationDataUsecaseから品質管理の責務を適切に分離しています。

As per coding guidelines(Usecaseのファイル名は「〜Usecase.swift」とする)。

UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swift (3)

7-8: LGTM! ドキュメンテーションが責務の変更を適切に反映しています

クラスのドキュメンテーションコメントが更新され、DataQualityUsecaseへの委譲が明記されています。セッション管理とリアルタイムデータ監視に専念することが明確になっており、単一責任原則に沿っています。


124-152: LGTM! 依存性注入により品質管理の責務が適切に分離されています

DataQualityUsecaseを依存性注入により受け取る設計が良好です:

  • デフォルト値によりテスタビリティを確保
  • プライベートプロパティとして適切にカプセル化
  • 初期化処理が明確

この設計により、ObservationDataUsecaseは732行から519行へ29%削減され、セッション管理とリアルタイム監視に専念できるようになっています。


400-443: LGTM! データ品質管理が適切に委譲されています

3つのメソッド(evaluateDataQualitydetectNonLineOfSightfilterObservations)がDataQualityUsecaseへ正しく委譲されています。

  • Line 401: 品質評価の委譲
  • Line 416: NLoS検出の委譲
  • Lines 439-443: フィルタリングの委譲

委譲パターンにより、データ品質管理ロジックが一元化され、保守性が向上しています。PRの目的である「Supporting Classesの独立化」と「DataQualityUsecaseへの品質評価移行」が達成されています。

Comment on lines +1 to +99
import Combine
import Foundation

/// UWBデータ管理(モックとして実装)
///
/// UWBデバイスとの通信を管理し、観測データの収集を行うクラスです。
/// 現在はシミュレーションデータを生成していますが、実際のUWBデバイスとの通信に置き換え可能です。
@MainActor
public class UWBDataManager: ObservableObject {
@Published public var connectionStatus: UWBConnectionStatus = .disconnected
@Published public var latestObservation: ObservationPoint?

private var activeSessions: Set<String> = []
private var simulationTimer: Timer?

public init() {}

/// データ収集を開始
/// - Parameters:
/// - antennaId: 対象アンテナID
/// - sessionId: セッションID
public func startDataCollection(for antennaId: String, sessionId: String) async throws {
self.activeSessions.insert(sessionId)
self.connectionStatus = .connected

// シミュレーション用タイマー開始
self.startSimulation(for: antennaId, sessionId: sessionId)
print("📡 UWBデータ収集開始: \(antennaId)")
}

/// データ収集を停止
/// - Parameter sessionId: セッションID
public func stopDataCollection(sessionId: String) async throws {
self.activeSessions.remove(sessionId)
if self.activeSessions.isEmpty {
self.simulationTimer?.invalidate()
self.simulationTimer = nil
}
print("📡 UWBデータ収集停止: \(sessionId)")
}

/// データ収集を一時停止
/// - Parameter sessionId: セッションID
public func pauseDataCollection(sessionId: String) async throws {
// 実装は省略
}

/// データ収集を再開
/// - Parameter sessionId: セッションID
public func resumeDataCollection(sessionId: String) async throws {
// 実装は省略
}

/// 最新の観測データを取得
/// - Parameter sessionId: セッションID
/// - Returns: 観測データの配列
public func getLatestObservations(for sessionId: String) async -> [ObservationPoint] {
// 実際の実装では、UWBデバイスから最新データを取得
[]
}

/// シミュレーションを開始
/// - Parameters:
/// - antennaId: アンテナID
/// - sessionId: セッションID
private func startSimulation(for antennaId: String, sessionId: String) {
self.simulationTimer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { [weak self] _ in
Task { @MainActor in
self?.generateSimulatedObservation(antennaId: antennaId, sessionId: sessionId)
}
}
}

/// シミュレーション用の観測データを生成
/// - Parameters:
/// - antennaId: アンテナID
/// - sessionId: セッションID
private func generateSimulatedObservation(antennaId: String, sessionId: String) {
let observation = ObservationPoint(
antennaId: antennaId,
position: Point3D(
x: Double.random(in: -10...10),
y: Double.random(in: -10...10),
z: Double.random(in: 0...3)
),
quality: SignalQuality(
strength: Double.random(in: 0.3...1.0),
isLineOfSight: Bool.random(),
confidenceLevel: Double.random(in: 0.5...1.0),
errorEstimate: Double.random(in: 0.1...2.0)
),
distance: Double.random(in: 1...20),
rssi: Double.random(in: -80...(-30)),
sessionId: sessionId
)

self.latestObservation = observation
}
}
Copy link

@coderabbitai coderabbitai bot Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

ファイルの配置場所を見直してください

UWBデバイスとの通信・制御ロジックは、プロジェクトのLearningsによればDevices/**/*.swift配下に配置すべきです。現在Domain/Utils/に配置されていますが、これはUWBデバイス固有の通信管理クラスであるため、Devices/配下への移動を推奨します。

Based on learnings("UWBデバイス関連の通信・制御ロジックはDevices/配下に配置する")。

推奨配置先: UWBViewerSystem/Devices/UWBDataManager.swift

また、モック実装として良好ですが、以下の空実装メソッドに実装予定の旨をコメントで明記することを推奨します:

 /// データ収集を一時停止
 /// - Parameter sessionId: セッションID
 public func pauseDataCollection(sessionId: String) async throws {
-    // 実装は省略
+    // TODO: 実デバイス実装時に一時停止ロジックを追加
+    print("⏸️ データ収集一時停止: \(sessionId)")
 }
 
 /// データ収集を再開
 /// - Parameter sessionId: セッションID
 public func resumeDataCollection(sessionId: String) async throws {
-    // 実装は省略
+    // TODO: 実デバイス実装時に再開ロジックを追加
+    print("▶️ データ収集再開: \(sessionId)")
 }
 
 /// 最新の観測データを取得
 /// - Parameter sessionId: セッションID
 /// - Returns: 観測データの配列
 public func getLatestObservations(for sessionId: String) async -> [ObservationPoint] {
-    // 実際の実装では、UWBデバイスから最新データを取得
+    // TODO: 実デバイス実装時にバッファから最新データを取得
     []
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import Combine
import Foundation
/// UWBデータ管理(モックとして実装)
///
/// UWBデバイスとの通信を管理し、観測データの収集を行うクラスです。
/// 現在はシミュレーションデータを生成していますが、実際のUWBデバイスとの通信に置き換え可能です。
@MainActor
public class UWBDataManager: ObservableObject {
@Published public var connectionStatus: UWBConnectionStatus = .disconnected
@Published public var latestObservation: ObservationPoint?
private var activeSessions: Set<String> = []
private var simulationTimer: Timer?
public init() {}
/// データ収集を開始
/// - Parameters:
/// - antennaId: 対象アンテナID
/// - sessionId: セッションID
public func startDataCollection(for antennaId: String, sessionId: String) async throws {
self.activeSessions.insert(sessionId)
self.connectionStatus = .connected
// シミュレーション用タイマー開始
self.startSimulation(for: antennaId, sessionId: sessionId)
print("📡 UWBデータ収集開始: \(antennaId)")
}
/// データ収集を停止
/// - Parameter sessionId: セッションID
public func stopDataCollection(sessionId: String) async throws {
self.activeSessions.remove(sessionId)
if self.activeSessions.isEmpty {
self.simulationTimer?.invalidate()
self.simulationTimer = nil
}
print("📡 UWBデータ収集停止: \(sessionId)")
}
/// データ収集を一時停止
/// - Parameter sessionId: セッションID
public func pauseDataCollection(sessionId: String) async throws {
// 実装は省略
}
/// データ収集を再開
/// - Parameter sessionId: セッションID
public func resumeDataCollection(sessionId: String) async throws {
// 実装は省略
}
/// 最新の観測データを取得
/// - Parameter sessionId: セッションID
/// - Returns: 観測データの配列
public func getLatestObservations(for sessionId: String) async -> [ObservationPoint] {
// 実際の実装では、UWBデバイスから最新データを取得
[]
}
/// シミュレーションを開始
/// - Parameters:
/// - antennaId: アンテナID
/// - sessionId: セッションID
private func startSimulation(for antennaId: String, sessionId: String) {
self.simulationTimer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { [weak self] _ in
Task { @MainActor in
self?.generateSimulatedObservation(antennaId: antennaId, sessionId: sessionId)
}
}
}
/// シミュレーション用の観測データを生成
/// - Parameters:
/// - antennaId: アンテナID
/// - sessionId: セッションID
private func generateSimulatedObservation(antennaId: String, sessionId: String) {
let observation = ObservationPoint(
antennaId: antennaId,
position: Point3D(
x: Double.random(in: -10...10),
y: Double.random(in: -10...10),
z: Double.random(in: 0...3)
),
quality: SignalQuality(
strength: Double.random(in: 0.3...1.0),
isLineOfSight: Bool.random(),
confidenceLevel: Double.random(in: 0.5...1.0),
errorEstimate: Double.random(in: 0.1...2.0)
),
distance: Double.random(in: 1...20),
rssi: Double.random(in: -80...(-30)),
sessionId: sessionId
)
self.latestObservation = observation
}
}
import Combine
import Foundation
/// UWBデータ管理(モックとして実装)
///
/// UWBデバイスとの通信を管理し、観測データの収集を行うクラスです。
/// 現在はシミュレーションデータを生成していますが、実際のUWBデバイスとの通信に置き換え可能です。
@MainActor
public class UWBDataManager: ObservableObject {
@Published public var connectionStatus: UWBConnectionStatus = .disconnected
@Published public var latestObservation: ObservationPoint?
private var activeSessions: Set<String> = []
private var simulationTimer: Timer?
public init() {}
/// データ収集を開始
/// - Parameters:
/// - antennaId: 対象アンテナID
/// - sessionId: セッションID
public func startDataCollection(for antennaId: String, sessionId: String) async throws {
self.activeSessions.insert(sessionId)
self.connectionStatus = .connected
// シミュレーション用タイマー開始
self.startSimulation(for: antennaId, sessionId: sessionId)
print("📡 UWBデータ収集開始: \(antennaId)")
}
/// データ収集を停止
/// - Parameter sessionId: セッションID
public func stopDataCollection(sessionId: String) async throws {
self.activeSessions.remove(sessionId)
if self.activeSessions.isEmpty {
self.simulationTimer?.invalidate()
self.simulationTimer = nil
}
print("📡 UWBデータ収集停止: \(sessionId)")
}
/// データ収集を一時停止
/// - Parameter sessionId: セッションID
public func pauseDataCollection(sessionId: String) async throws {
// TODO: 実デバイス実装時に一時停止ロジックを追加
print("⏸️ データ収集一時停止: \(sessionId)")
}
/// データ収集を再開
/// - Parameter sessionId: セッションID
public func resumeDataCollection(sessionId: String) async throws {
// TODO: 実デバイス実装時に再開ロジックを追加
print("▶️ データ収集再開: \(sessionId)")
}
/// 最新の観測データを取得
/// - Parameter sessionId: セッションID
/// - Returns: 観測データの配列
public func getLatestObservations(for sessionId: String) async -> [ObservationPoint] {
// TODO: 実デバイス実装時にバッファから最新データを取得
[]
}
/// シミュレーションを開始
/// - Parameters:
/// - antennaId: アンテナID
/// - sessionId: セッションID
private func startSimulation(for antennaId: String, sessionId: String) {
self.simulationTimer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { [weak self] _ in
Task { @MainActor in
self?.generateSimulatedObservation(antennaId: antennaId, sessionId: sessionId)
}
}
}
/// シミュレーション用の観測データを生成
/// - Parameters:
/// - antennaId: アンテナID
/// - sessionId: セッションID
private func generateSimulatedObservation(antennaId: String, sessionId: String) {
let observation = ObservationPoint(
antennaId: antennaId,
position: Point3D(
x: Double.random(in: -10...10),
y: Double.random(in: -10...10),
z: Double.random(in: 0...3)
),
quality: SignalQuality(
strength: Double.random(in: 0.3...1.0),
isLineOfSight: Bool.random(),
confidenceLevel: Double.random(in: 0.5...1.0),
errorEstimate: Double.random(in: 0.1...2.0)
),
distance: Double.random(in: 1...20),
rssi: Double.random(in: -80...(-30)),
sessionId: sessionId
)
self.latestObservation = observation
}
}
🤖 Prompt for AI Agents
In UWBViewerSystem/Domain/Utils/UWBDataManager.swift lines 1-99: the UWB device
communication/management class belongs under Devices/ per project conventions,
so move the file to UWBViewerSystem/Devices/UWBDataManager.swift (update any
import paths or module references accordingly); additionally, add brief TODO
comments inside the currently empty methods pauseDataCollection(sessionId:),
resumeDataCollection(sessionId:) and getLatestObservations(for:) indicating they
are intentionally left unimplemented for the mock and will be implemented when
integrating real UWB device logic (e.g., "// TODO: implement pause behavior when
replacing mock with real device logic").

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この内容は対応が終わっていますか?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the current content of the file to verify implementation status
cat UWBViewerSystem/Devices/UWBDataManager.swift | grep -A 3 "pauseDataCollection\|resumeDataCollection\|getLatestObservations"

Length of output: 339


@harutiro さん、対応状況を確認しました:

✅ 完了した項目:

  • ファイルの配置場所:Domain/Utils/UWBDataManager.swiftDevices/UWBDataManager.swift へ移動済み

⏳ 未完了の項目:

  • TODOコメントの追加:以下のメソッドに、より具体的なTODOコメント(実装予定の旨を明記)を追加する提案がまだ反映されていません
    • pauseDataCollection - 現在は // 実装は省略 のまま
    • resumeDataCollection - 現在は // 実装は省略 のまま
    • getLatestObservations - 現在は // 実際の実装では、UWBデバイスから最新データを取得 のまま

ファイル配置の変更は完了していますが、コメントの改善提案はまだ対応されていない状態です。このコメント改善は必須ではありませんが、将来の実装者にとってより明確な指針となります。

このまま進めるか、コメントも更新されますか?


🧠 Learnings used
Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to Devices/**/*.swift : UWBデバイス関連の通信・制御ロジックはDevices/配下に配置する

Learnt from: harutiro
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: :0-0
Timestamp: 2025-09-23T14:37:07.451Z
Learning: UWBViewerSystemでUserDefaults変更通知のテストを行う際は、NotificationCenterの非同期処理完了を確実に待機するため、1.5秒程度の待機時間とポーリング方式の検証を使用する。これにより競合状態やタイミング問題を回避できる。

Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to **/*.swift : デッドコードは削除し、コメントは必要最小限に留める(自己文書化を優先)

Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to Domain/**/*.swift : Domain層のコード(Entity/Repository/Usecase/DataModel/Utils)はDomain/配下に配置する

Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Applies to **/*Usecase.swift : Usecaseのファイル名は「〜Usecase.swift」とする

Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: PRには関連Issue(Closes/Fixes/Relates to)を設定し、Issueのラベルを継承し、レビュー情報を記載する

Learnt from: CR
Repo: kajiLabTeam/UWBViewerSystem PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T15:18:09.790Z
Learning: Claude CodeでのPRではコミットメッセージに「🤖 Generated with Claude Code」を含め、生成コードに説明コメントを付し、レビュー時の注意点を明記する

…ation

- Deleted all references to BaseViewModel.swift in the project.pbxproj file.
- This cleanup helps streamline the project configuration and removes unused components.

No functional changes were made to the application.
- Added UWBDataManager class to handle data collection from UWB devices, including starting, stopping, pausing, and resuming data collection.
- Introduced simulation functionality to generate mock observation data for testing purposes.
- Updated DataQualityMonitor by removing an unused stabilityWindow property.

This addition lays the groundwork for future integration with actual UWB devices.
@harutiro harutiro merged commit 56b6994 into main Nov 3, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ObservationDataUsecaseを分割して責務を明確化

2 participants