Week 7-8: Pattern 3 Implementation (Agent 1)
Timeline: 2025-10-26 Agent: Agent 1 (AAP - Platform Abstractions) Status: ✅ COMPLETE
Overview
Pattern 3 (Context Abstraction) designed, implemented, and validated over Week 6-8.
Week 6: Design
Deliverable: CONTEXT_ABSTRACTION_PATTERN.md (1,108 lines)
3 Core Abstractions Designed:
- PreferenceStorage - SharedPreferences → KMP
- ResourceProvider - String resources → KMP
- FileSystemProvider - File I/O → KMP
7-Step Migration Workflow:
- Identify Context dependencies
- Choose/create abstraction
- Use Android implementation
- Update service constructor
- Update manual DI
- Migrate to shared:domain
- Test with fakes
Week 7 Phase 1: Core Abstractions
PR #152 (MERGED)
PreferenceStorage
Purpose: Abstract SharedPreferences for KMP
Android Implementation:
- Uses
SharedPreferences.apply()(non-blocking) - Proper threading (
Dispatchers.IO) - Application Context (no leaks)
API:
interface PreferenceStorage {
suspend fun getString(key: String, defaultValue: String = ""): String
suspend fun putString(key: String, value: String)
suspend fun getInt(key: String, defaultValue: Int = 0): Int
// ... Boolean, Long, Float, remove, clear, contains
}iOS Future: NSUserDefaults
Tests: 21 test cases
ResourceProvider
Purpose: Abstract string resources for KMP
Android Implementation:
- Reflection-based resource ID lookup
- LRU cache (maxSize=50) for performance
- Fallback to android.R.string.* for system resources
API:
interface ResourceProvider {
fun getString(key: String): String
fun getString(key: String, vararg args: Any): String
fun getStringArray(key: String): List<String>
}iOS Future: NSBundle.localizedStringForKey()
Tests: 11 test cases
FileSystemProvider
Purpose: Abstract file I/O for KMP
Android Implementation:
- Uses context.filesDir, context.cacheDir, external storage
- Proper threading (Dispatchers.IO)
- Automatic parent directory creation
API:
interface FileSystemProvider {
suspend fun getDirectoryPath(directory: Directory): String
suspend fun writeText(filename: String, content: String, directory: Directory)
suspend fun readText(filename: String, directory: Directory): String?
suspend fun exists(filename: String, directory: Directory): Boolean
// ... binary I/O, directory management, list, delete, clear
}iOS Future: NSDocumentDirectory, NSCachesDirectory
Tests: 21 test cases
Week 7 Phase 2: ExportUtils Migration
PR #154 (Created)
Service: ExportUtils (CSV export utility)
Migration:
- From: app module (Android-specific)
- To: shared:domain (KMP-compatible)
Changes:
- ❌ Removed Context dependency
- ✅ Added FileSystemProvider injection
- ❌ Removed java.io.File (Android-only)
- ✅ Uses String paths (KMP-compatible)
- ✅ Added suspend functions
Before:
object ExportUtils {
fun exportCsv(context: Context, filename: String, rows: List<List<String>>): File {
val f = File(context.cacheDir, filename)
// Write CSV using java.io.File
}
}After:
class ExportUtils(private val fileSystemProvider: FileSystemProvider) {
suspend fun exportCsv(filename: String, rows: List<List<String>>): String {
val csvContent = buildString { /* CSV generation */ }
fileSystemProvider.writeText(filename, csvContent, Directory.CACHE)
return fileSystemProvider.getDirectoryPath(Directory.CACHE) + "/" + filename
}
}Tests: 11 test cases with FakeFileSystemProvider
Pattern 3 Validation
Workflow Proven:
- ✅ Design abstraction (Week 6)
- ✅ Implement Android version (Week 7 Phase 1)
- ✅ Create test fake (Week 7 Phase 1)
- ✅ Migrate service (Week 7 Phase 2)
- ✅ Test with fake (Week 7 Phase 2)
Results:
- Zero Android dependencies in shared:domain
- 100% test pass rate (68 new tests)
- Zero regressions
- Pattern ready for Week 8 reuse
Week 8 Preview
Next: Migrate 3-5 More Services
Candidates:
- OfflineScoreQueueManager (file storage)
- PlatformProvider extensions (Context deps)
- Settings utilities (SharedPreferences)
Estimated Effort: 5-7 hours
Pattern: Reuse existing abstractions (no new design needed)
Architecture Impact
Before Pattern 3:
- ~15% of services blocked by Context dependencies
- Services stuck in app module (Android-specific)
After Pattern 3:
- Context-dependent services can migrate to shared:domain
- Services testable with fakes (no Robolectric needed)
- iOS implementation path clear (expect/actual)
Next Patterns:
- Pattern 4: Additional platform abstractions (TBD)
- Week 9: FirebaseDataSource abstraction (Pattern 2 implementation)
Status: ✅ COMPLETE Impact: 15% of services now migratable to KMP Next: Week 8 service migration sprint