Building Advanced Modules¶
Overview¶
Advanced modules provide sophisticated functionality that goes beyond basic health data management. This guide covers building modules with complex features like machine learning, research capabilities, and enterprise integrations.
Module Architecture¶
Core Components¶
Advanced modules typically consist of:
import Spezi
// 1. Module Protocol
protocol AdvancedModule: Module {
var configuration: AdvancedModuleConfiguration { get }
var dependencies: [ModuleDependency] { get }
}
// 2. Configuration
struct AdvancedModuleConfiguration {
let enableML: Bool
let enableResearch: Bool
let securityLevel: SecurityLevel
let dataRetention: TimeInterval
}
// 3. Dependencies
enum ModuleDependency {
case healthKit
case user
case storage
case networking
}
// 4. Main Module Implementation
@MainActor
final class MyAdvancedModule: AdvancedModule {
let configuration: AdvancedModuleConfiguration
let dependencies: [ModuleDependency]
private var mlEngine: MLEngine?
private var researchManager: ResearchManager?
private var securityManager: SecurityManager?
init(configuration: AdvancedModuleConfiguration) {
self.configuration = configuration
self.dependencies = [.healthKit, .user, .storage]
}
func configure() async throws {
// Initialize components based on configuration
if configuration.enableML {
mlEngine = try await MLEngine.initialize()
}
if configuration.enableResearch {
researchManager = try await ResearchManager.initialize()
}
securityManager = SecurityManager(level: configuration.securityLevel)
}
}
Machine Learning Integration¶
Building ML-Enabled Modules¶
import CoreML
import CreateML
struct MLHealthPredictor {
private let model: MLModel
private let featureExtractor: FeatureExtractor
init(modelURL: URL) throws {
self.model = try MLModel(contentsOf: modelURL)
self.featureExtractor = FeatureExtractor()
}
func predictHealthRisk(from data: HealthData) async throws -> HealthRiskPrediction {
let features = try await featureExtractor.extractFeatures(from: data)
let prediction = try model.prediction(from: features)
return HealthRiskPrediction(
riskLevel: prediction.riskLevel,
confidence: prediction.confidence,
factors: prediction.contributingFactors
)
}
}
class MLEngine {
private var predictors: [String: MLHealthPredictor] = [:]
static func initialize() async throws -> MLEngine {
let engine = MLEngine()
// Load pre-trained models
try await engine.loadModel("heart_risk", from: "HeartRiskModel.mlmodel")
try await engine.loadModel("anomaly_detection", from: "AnomalyModel.mlmodel")
return engine
}
private func loadModel(_ name: String, from filename: String) async throws {
guard let modelURL = Bundle.main.url(forResource: filename, withExtension: nil) else {
throw MLError.modelNotFound
}
let predictor = try MLHealthPredictor(modelURL: modelURL)
predictors[name] = predictor
}
func predict(_ type: PredictionType, using data: HealthData) async throws -> PredictionResult {
guard let predictor = predictors[type.rawValue] else {
throw MLError.predictorNotFound
}
return try await predictor.predictHealthRisk(from: data)
}
}
Real-time ML Processing¶
class RealTimeMLProcessor {
private let queue = DispatchQueue(label: "ml.processing", qos: .userInitiated)
private let mlEngine: MLEngine
private var processingTask: Task<Void, Never>?
init(mlEngine: MLEngine) {
self.mlEngine = mlEngine
}
func startProcessing(healthDataStream: AsyncStream<HealthData>) {
processingTask = Task {
for await data in healthDataStream {
await processData(data)
}
}
}
private func processData(_ data: HealthData) async {
do {
let prediction = try await mlEngine.predict(.anomalyDetection, using: data)
if prediction.isAnomaly {
await notifyAnomaly(prediction)
}
} catch {
await handleError(error)
}
}
private func notifyAnomaly(_ prediction: PredictionResult) async {
// Send notification or trigger alert
NotificationCenter.default.post(
name: .healthAnomalyDetected,
object: prediction
)
}
}
Research Framework Integration¶
Building Research Modules¶
struct ResearchStudy {
let id: String
let title: String
let description: String
let protocol: StudyProtocol
let participants: [Participant]
let dataPoints: [DataPoint]
}
struct StudyProtocol {
let duration: TimeInterval
let frequency: DataCollectionFrequency
let consentRequired: Bool
let irbApproval: String?
}
class ResearchManager {
private var activeStudies: [String: ResearchStudy] = [:]
private let dataCollector: DataCollector
private let consentManager: ConsentManager
static func initialize() async throws -> ResearchManager {
let manager = ResearchManager()
try await manager.loadActiveStudies()
return manager
}
func createStudy(_ study: ResearchStudy) async throws {
// Validate study protocol
try validateProtocol(study.protocol)
// Set up data collection
try await dataCollector.setupCollection(for: study)
// Store study
activeStudies[study.id] = study
}
func enrollParticipant(_ participant: Participant, in studyId: String) async throws {
guard let study = activeStudies[studyId] else {
throw ResearchError.studyNotFound
}
// Obtain consent if required
if study.protocol.consentRequired {
try await consentManager.obtainConsent(from: participant, for: study)
}
// Set up participant data collection
try await dataCollector.enrollParticipant(participant, in: study)
}
func collectData(for studyId: String) async throws -> StudyData {
guard let study = activeStudies[studyId] else {
throw ResearchError.studyNotFound
}
return try await dataCollector.collectData(for: study)
}
}
Data Collection and Management¶
class DataCollector {
private var collectionTasks: [String: Task<Void, Never>] = [:]
func setupCollection(for study: ResearchStudy) async throws {
let task = Task {
await startDataCollection(for: study)
}
collectionTasks[study.id] = task
}
private func startDataCollection(for study: ResearchStudy) async {
let timer = Timer.publish(every: study.protocol.frequency.interval, on: .main, in: .common)
for await _ in timer {
await collectDataPoint(for: study)
}
}
private func collectDataPoint(for study: ResearchStudy) async {
for dataPoint in study.dataPoints {
do {
let data = try await collectData(for: dataPoint)
await storeData(data, for: study.id)
} catch {
await handleCollectionError(error, for: dataPoint)
}
}
}
private func collectData(for dataPoint: DataPoint) async throws -> HealthData {
switch dataPoint.type {
case .heartRate:
return try await HealthKitManager.shared.readHeartRate()
case .stepCount:
return try await HealthKitManager.shared.readStepCount()
case .sleepAnalysis:
return try await HealthKitManager.shared.readSleepAnalysis()
case .custom:
return try await collectCustomData(dataPoint)
}
}
}
Security and Compliance¶
Building Secure Modules¶
enum SecurityLevel {
case basic
case enhanced
case enterprise
}
class SecurityManager {
private let level: SecurityLevel
private let encryptionManager: EncryptionManager
private let auditLogger: AuditLogger
private let accessController: AccessController
init(level: SecurityLevel) {
self.level = level
self.encryptionManager = EncryptionManager(level: level)
self.auditLogger = AuditLogger()
self.accessController = AccessController()
}
func encryptData(_ data: Data) async throws -> EncryptedData {
let encrypted = try await encryptionManager.encrypt(data)
await auditLogger.log(.dataEncrypted, metadata: ["size": data.count])
return encrypted
}
func decryptData(_ encryptedData: EncryptedData) async throws -> Data {
let decrypted = try await encryptionManager.decrypt(encryptedData)
await auditLogger.log(.dataDecrypted, metadata: ["size": decrypted.count])
return decrypted
}
func checkAccess(_ user: User, for resource: Resource) async throws -> Bool {
let hasAccess = await accessController.checkAccess(user, for: resource)
await auditLogger.log(.accessChecked, metadata: [
"user": user.id,
"resource": resource.id,
"granted": hasAccess
])
return hasAccess
}
}
class EncryptionManager {
private let level: SecurityLevel
private let keychain: KeychainManager
init(level: SecurityLevel) {
self.level = level
self.keychain = KeychainManager()
}
func encrypt(_ data: Data) async throws -> EncryptedData {
let key = try await keychain.getOrCreateKey(for: level)
switch level {
case .basic:
return try encryptBasic(data, with: key)
case .enhanced:
return try encryptEnhanced(data, with: key)
case .enterprise:
return try encryptEnterprise(data, with: key)
}
}
private func encryptEnterprise(_ data: Data, with key: SecKey) throws -> EncryptedData {
// Implement enterprise-grade encryption (AES-256, hardware-backed keys)
let algorithm = SecKeyAlgorithm.rsaEncryptionOAEPSHA256
let encryptedData = try SecKeyCreateEncryptedData(key, algorithm, data as CFData, nil)
return EncryptedData(
data: encryptedData as Data,
algorithm: algorithm,
keyId: key.keyId
)
}
}
Performance Optimization¶
Optimizing Advanced Modules¶
class PerformanceOptimizer {
private let cache = NSCache<NSString, AnyObject>()
private let backgroundQueue = DispatchQueue(label: "background.processing", qos: .utility)
func optimizeMLProcessing() {
// Use background processing for ML tasks
backgroundQueue.async {
self.processMLTasks()
}
}
func cacheResults<T: AnyObject>(_ results: T, for key: String) {
cache.setObject(results, forKey: key as NSString)
}
func getCachedResults<T: AnyObject>(for key: String) -> T? {
return cache.object(forKey: key as NSString) as? T
}
private func processMLTasks() {
// Process ML tasks in background
// This prevents blocking the main thread
}
}
// Usage in advanced module
class OptimizedAdvancedModule: AdvancedModule {
private let optimizer = PerformanceOptimizer()
func processHealthData(_ data: HealthData) async throws -> HealthInsights {
// Check cache first
if let cached: HealthInsights = optimizer.getCachedResults(for: data.cacheKey) {
return cached
}
// Process in background if needed
let insights = try await backgroundProcess(data)
// Cache results
optimizer.cacheResults(insights, for: data.cacheKey)
return insights
}
}
Testing Advanced Modules¶
Comprehensive Testing Strategy¶
import XCTest
class AdvancedModuleTests: XCTestCase {
var module: MyAdvancedModule!
var mockMLEngine: MockMLEngine!
var mockResearchManager: MockResearchManager!
override func setUp() async throws {
mockMLEngine = MockMLEngine()
mockResearchManager = MockResearchManager()
let config = AdvancedModuleConfiguration(
enableML: true,
enableResearch: true,
securityLevel: .enhanced,
dataRetention: 3600
)
module = MyAdvancedModule(configuration: config)
module.mlEngine = mockMLEngine
module.researchManager = mockResearchManager
try await module.configure()
}
func testMLPrediction() async throws {
// Given
let healthData = HealthData.mock()
let expectedPrediction = HealthRiskPrediction.mock()
mockMLEngine.predictionResult = expectedPrediction
// When
let result = try await module.predictHealthRisk(from: healthData)
// Then
XCTAssertEqual(result.riskLevel, expectedPrediction.riskLevel)
XCTAssertEqual(result.confidence, expectedPrediction.confidence)
}
func testResearchDataCollection() async throws {
// Given
let study = ResearchStudy.mock()
let participant = Participant.mock()
// When
try await module.enrollParticipant(participant, in: study.id)
let data = try await module.collectStudyData(study.id)
// Then
XCTAssertNotNil(data)
XCTAssertEqual(data.participants.count, 1)
}
func testSecurityEncryption() async throws {
// Given
let sensitiveData = "sensitive health data".data(using: .utf8)!
// When
let encrypted = try await module.encryptData(sensitiveData)
let decrypted = try await module.decryptData(encrypted)
// Then
XCTAssertNotEqual(sensitiveData, encrypted.data)
XCTAssertEqual(sensitiveData, decrypted)
}
}
Best Practices¶
1. Modular Design¶
- Keep modules focused on specific functionality
- Use dependency injection for flexibility
- Implement clear interfaces between components
2. Error Handling¶
- Provide meaningful error messages
- Implement graceful degradation
- Log errors for debugging
3. Performance¶
- Use background processing for heavy tasks
- Implement caching strategies
- Optimize data structures and algorithms
4. Security¶
- Follow security best practices
- Implement proper encryption
- Maintain audit trails
5. Testing¶
- Write comprehensive unit tests
- Test edge cases and error conditions
- Use mocking for external dependencies
Next Steps¶
- Learn about Testing Modules
- Explore Publishing Modules
- Check out Module Overview
- Review Core Concepts