Claude Skills Guide

Claude Code for Kotlin Delegation Pattern Workflow

Kotlin’s delegation pattern is a powerful feature that allows you to delegate method calls to another object, promoting composition over inheritance and improving code reusability. When combined with Claude Code, you can efficiently implement, refactor, and maintain delegation patterns in your Kotlin projects. This guide provides practical workflows, code examples, and actionable strategies for using Claude Code in your Kotlin delegation pattern development.

Understanding Kotlin Delegation Basics

Kotlin provides first-class support for delegation through the by keyword. The language offers both built-in delegations like lazy, observable, and vetoable, as well as the ability to implement custom delegators. Understanding these fundamentals is essential before applying Claude Code to assist with your workflow.

Built-in Delegation Properties

Kotlin’s standard library includes several useful delegation patterns:

// Lazy delegation - value computed only on first access
val heavyObject by lazy {
    println("Initializing heavy object...")
    HeavyObject()
}

// Observable delegation - notifies on changes
var observedValue by observable("initial") { property, oldValue, newValue ->
    println("Value changed from $oldValue to $newValue")
}

// Vetoable delegation - allows conditional changes
var positiveValue by vetoable(0) { _, _, newValue ->
    newValue >= 0
}

When working with these patterns, Claude Code can help you generate appropriate implementations, explain behavior, and suggest optimal usage scenarios based on your specific requirements.

Setting Up Claude Code for Kotlin Development

Before diving into delegation patterns, ensure Claude Code is properly configured for your Kotlin project. Create a CLAUDE.md file in your project root to establish context-aware assistance:

# Project Context

- Language: Kotlin 1.9.x
- Build System: Gradle with Kotlin DSL
- Framework: Android/Server-side Kotlin
- Key Dependencies: Kotlin Coroutines, Spring Boot

# Code Conventions

- Use meaningful variable names
- Prefer immutable val over var when possible
- Follow official Kotlin style guide
- Document delegation usage in KDoc comments

This configuration helps Claude Code provide more accurate suggestions for delegation pattern implementations specific to your project structure and coding standards.

Implementing Custom Delegation Patterns

Custom delegation allows you to create reusable behavior that can be applied across different classes. Here’s a practical workflow for implementing custom delegators with Claude Code assistance.

Step 1: Define the Delegator Interface

Start by asking Claude Code to generate a clean interface for your delegator:

“Create a Kotlin interface for a property delegator that provides caching behavior with expiration”

Claude Code will generate:

interface CachedDelegate<V> {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): V
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: V)
}

class CachedValue<V>(
    private val loader: () -> V,
    private val expirationMs: Long = 60000
) : CachedDelegate<V> {
    private var cached: V? = null
    private var loadTime: Long = 0

    override fun getValue(thisRef: Any?, property: KProperty<*>): V {
        val now = System.currentTimeMillis()
        if (cached == null || now - loadTime > expirationMs) {
            cached = loader()
            loadTime = now
        }
        return cached!!
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
        cached = value
        loadTime = System.currentTimeMillis()
    }
}

Step 2: Implement the Delegator Class

Ask Claude Code to extend the implementation with thread-safety:

“Add thread-safe implementation with double-checked locking to the CachedValue delegator”

Claude Code will enhance the implementation:

class CachedValue<V>(
    private val loader: () -> V,
    private val expirationMs: Long = 60000
) : ReadWriteProperty<Any?, V> {
    @Volatile private var cached: V? = null
    @Volatile private var loadTime: Long = 0
    private val lock = ReentrantReadWriteLock()

    override fun getValue(thisRef: Any?, property: KProperty<*>): V {
        return lock.read {
            val now = System.currentTimeMillis()
            val current = cached
            if (current == null || now - loadTime > expirationMs) {
                lock.read.unlock()
                lock.write {
                    // Double-check after acquiring write lock
                    if (cached == null || System.currentTimeMillis() - loadTime > expirationMs) {
                        cached = loader()
                        loadTime = System.currentTimeMillis()
                    }
                }
                lock.read.lock()
            }
            cached!!
        }
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
        lock.write {
            cached = value
            loadTime = System.currentTimeMillis()
        }
    }
}

Practical Delegation Patterns for Android Development

In Android development, delegation patterns are particularly useful for managing lifecycle-aware components, view binding, and dependency injection.

Lifecycle-Aware Delegation

Create a delegation pattern that automatically handles lifecycle events:

class LifecycleAwareDelegate<T>(
    private val context: Context,
    private val initializer: (Context) -> T
) : ReadWriteProperty<Any?, T> {
    private var value: T? = null

    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: initializer(context).also { value = it }
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

fun <T> lifecycleAware(initializer: (Context) -> T): LifecycleAwareDelegate<T> {
    return LifecycleAwareDelegate(requireContext(), initializer)
}

Use this pattern in your Android components:

class MyFragment : Fragment() {
    // Automatically managed with fragment lifecycle
    val database by lifecycleAware { Database.getInstance(it) }
    val sharedPrefs by lifecycleAware { 
        it.getSharedPreferences("prefs", Context.MODE_PRIVATE) 
    }
}

Ask Claude Code for variations: “Create a lifecycle-aware delegate that automatically closes resources when the fragment is destroyed”

Refactoring to Delegation Patterns

Claude Code excels at helping you refactor existing code to use delegation patterns. This is particularly valuable when dealing with inheritance hierarchies that should be composition-based.

Common Refactoring Scenario

When you have:

open class BaseRepository {
    open fun fetchUser(id: Int): User { /* implementation */ }
    open fun saveUser(user: User) { /* implementation */ }
}

class UserRepository : BaseRepository() {
    // Adds user-specific logic
}

Ask Claude Code to refactor:

“Refactor this inheritance hierarchy to use delegation instead, keeping the BaseRepository functionality while allowing composition”

Claude Code will generate:

interface Repository {
    fun fetchUser(id: Int): User
    fun saveUser(user: User)
}

class BaseRepositoryImpl : Repository {
    override fun fetchUser(id: Int): User { /* implementation */ }
    override fun saveUser(user: User) { /* implementation */ }
}

class UserRepository(
    private val baseRepository: Repository = BaseRepositoryImpl()
) : Repository by baseRepository {
    
    fun fetchUserWithCache(id: Int): User {
        // Add caching logic while delegating base functionality
        return baseRepository.fetchUser(id)
    }
    
    override fun saveUser(user: User) {
        // Add validation before saving
        require(user.isValid()) { "Invalid user data" }
        baseRepository.saveUser(user)
    }
}

Best Practices for Delegation Pattern Workflow

Following these practices ensures maintainable and effective delegation implementations:

1. Define Clear Interfaces

Always define interfaces for your delegators. This enables testing and provides clear contracts:

interface Logger {
    fun log(message: String)
    fun error(message: String, throwable: Throwable? = null)
}

class ConsoleLogger : Logger {
    override fun log(message: String) = println(message)
    override fun error(message: String, throwable: Throwable?) 
        = println("ERROR: $message, $throwable")
}

2. use Type-Safe Delegates

Use generic type parameters for reusability while maintaining type safety:

class NotNullDelegate<T : Any> : ReadWriteProperty<Any?, T> {
    private var value: T? = null
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value ?: throw IllegalStateException(
            "Property ${property.name} has not been initialized"
        )
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        this.value = value
    }
}

fun <T : Any> notNull(): NotNullDelegate<T> = NotNullDelegate()

3. Document Delegation Behavior

Use KDoc comments to explain delegation behavior, especially for custom delegates:

/**
 * A delegator that provides lazy initialization with thread safety.
 *
 * @param T The type of value being delegated
 * @param loader Lambda that produces the value on first access
 * @param lock The lock to use for thread synchronization
 *
 * @see lazy
 * @see kotlin.properties.ReadWriteProperty
 */
class SynchronizedLazyDelegate<T>(
    private val loader: () -> T,
    private val lock: Lock = ReentrantLock()
) : ReadWriteProperty<Any?, T> { /* implementation */ }

Troubleshooting Common Delegation Issues

When working with delegation patterns, you may encounter issues that Claude Code can help diagnose and resolve.

Property Delegate Type Mismatch

If you see type mismatch errors with delegates, ensure your delegate matches the property type:

// Wrong - type mismatch
val stringProperty: String by lazy { 42 } // Error: Int cannot be assigned to String

// Correct - matching types
val stringProperty: String by lazy { "42" }
val intProperty: Int by lazy { 42 }

Ask Claude Code: “Fix this type mismatch in the delegation” and provide the code for immediate correction.

Delegate Not Found Errors

When using custom delegates, ensure proper import statements and interface implementations:

import kotlin.properties.ReadWriteProperty

// Verify your delegate implements the correct interface
class MyDelegate<V> : ReadWriteProperty<Any?, V> { /* ... */ }

Conclusion

Kotlin’s delegation patterns, combined with Claude Code’s assistance, provide a powerful workflow for building maintainable, reusable code. By using Claude Code’s ability to generate, explain, and refactor delegation implementations, you can accelerate development while ensuring best practices. Remember to define clear interfaces, document behavior, and use built-in delegates where appropriate. With these patterns in your toolkit, you’ll write more elegant and composable Kotlin code.

Built by theluckystrike — More at zovo.one