-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: ObservationDataUsecaseを分割して責務を明確化 #33 #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
## 変更内容 - 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>
WalkthroughUWBデータ品質評価機能を単一責任原則に従って分離しました。DataQualityTypesで新しいデータ型を定義し、DataQualityUsecaseで品質評価ロジックを集約し、DataQualityMonitorで評価の実装を担当し、UWBDataManagerでデバイスデータ収集を管理し、ObservationDataUsecaseをリファクタリングして品質関連処理を新しいUsecaseに委譲します。 Changes
Sequence DiagramsequenceDiagram
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]
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used📓 Path-based instructions (1)**/*.swift📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (4)📓 Common learnings📚 Learning: 2025-09-23T15:18:09.790ZApplied to files:
📚 Learning: 2025-09-23T15:18:09.790ZApplied to files:
📚 Learning: 2025-09-23T15:18:09.790ZApplied to files:
🧬 Code graph analysis (1)UWBViewerSystem/Devices/UWBDataManager.swift (1)
⏰ 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)
🔇 Additional comments (5)
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. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this 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として適切に公開され、明示的なイニシャライザも提供されています。
今後のテスタビリティ向上のため、
DataQualityEvaluationとNLoSDetectionResultにも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: StringUWBViewerSystem/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
📒 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.swiftUWBViewerSystem/Domain/Utils/UWBDataManager.swiftUWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swiftUWBViewerSystem/Domain/Entity/DataQualityTypes.swiftUWBViewerSystem/Domain/Usecase/DataQualityUsecase.swift
**/*Usecase.swift
📄 CodeRabbit inference engine (CLAUDE.md)
Usecaseのファイル名は「〜Usecase.swift」とする
Files:
UWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swiftUWBViewerSystem/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.pbxprojUWBViewerSystem/Domain/Utils/UWBDataManager.swiftUWBViewerSystem/Domain/Usecase/ObservationDataUsecase.swiftUWBViewerSystem/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つのメソッド(
evaluateDataQuality、detectNonLineOfSight、filterObservations)がDataQualityUsecaseへ正しく委譲されています。
- Line 401: 品質評価の委譲
- Line 416: NLoS検出の委譲
- Lines 439-443: フィルタリングの委譲
委譲パターンにより、データ品質管理ロジックが一元化され、保守性が向上しています。PRの目的である「Supporting Classesの独立化」と「DataQualityUsecaseへの品質評価移行」が達成されています。
| 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 | ||
| } | ||
| } |
There was a problem hiding this comment.
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.
| 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").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この内容は対応が終わっていますか?
There was a problem hiding this comment.
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.swift→Devices/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.
概要
732行の肥大化したObservationDataUsecaseを単一責任原則に従って適切に分割し、519行に削減しました(29%削減)。
変更内容
新規作成ファイル
Domain/Entity/DataQualityTypes.swift
UWBConnectionStatus: UWB接続状態の定義DataQualityEvaluation: データ品質評価結果NLoSDetectionResult: nLoS検出結果Domain/Utils/DataQualityMonitor.swift
Domain/Utils/UWBDataManager.swift
Domain/Usecase/DataQualityUsecase.swift
修正ファイル
テスト計画
受け入れ条件
関連Issue
Closes #33
🤖 Generated with Claude Code
Summary by CodeRabbit
リリースノート
New Features
Refactor