Package 

Interface BorgDrone


  • 
    public interface BorgDrone<T extends Object, C extends Object>
    
                        

    Contract for components that need ordered, dependency-aware initialization.

    Why an interface?

    • Keeps initialization logic separate from component business logic

    • Makes dependencies explicit through the type system

    • Allows mocking in tests

    • Generic context parameter allows flexibility in initialization

    Example implementations:

    // 1. Simple configuration drone
    class ConfigDrone : BorgDrone<AppConfig, Context> {
        override suspend fun assimilate(context: Context, borg: Borg<Context>): AppConfig {
            return AppConfig.load(context.assets.open("config.json"))
        }
    }
    
    // 2. Database initialization with config dependency
    class DatabaseDrone(private val configDrone: ConfigDrone) : BorgDrone<Database, Context> {
        override fun requiredDrones() = listOf(configDrone::class.java)
    
        override suspend fun assimilate(context: Context, borg: Borg<Context>): Database {
            val config = borg.requireAssimilated(configDrone::class.java)
            return Room.databaseBuilder(context, Database::class.java, config.dbName)
                .build()
        }
    }
    
    // 3. Repository with multiple dependencies
    class RepositoryDrone(
        private val databaseDrone: DatabaseDrone,
        private val apiDrone: ApiDrone
    ) : BorgDrone<Repository, Context> {
        override fun requiredDrones() = listOf(
            databaseDrone::class.java,
            apiDrone::class.java
        )
    
        override suspend fun assimilate(context: Context, borg: Borg<Context>): Repository {
            val db = borg.requireAssimilated(databaseDrone::class.java)
            val api = borg.requireAssimilated(apiDrone::class.java)
            return Repository(db, api)
        }
    }
    
    // 4. Analytics with fallback handling
    class AnalyticsDrone : BorgDrone<Analytics, Context> {
        override suspend fun assimilate(context: Context, borg: Borg<Context>): Analytics {
            return try {
                FirebaseAnalytics.getInstance(context)
            } catch (e: Exception) {
                NoOpAnalytics() // Fallback implementation
            }
        }
    }

    Best practices:

    • Keep drones focused and single-purpose

    • Make dependencies explicit in constructor

    • Handle errors gracefully with fallbacks

    • Use meaningful names that reflect purpose

    • Document any special initialization requirements

    • Consider thread safety in returned objects

    • Cache expensive operations appropriately

    • Write unit tests for initialization logic

    • Method Summary

      Modifier and Type Method Description
      List<Class<out BorgDrone<?, C>>> requiredDrones() Declares initialization prerequisites.
      abstract T assimilate(C context, Borg<C> borg) Creates and configures a component instance.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Method Detail

      • requiredDrones

         List<Class<out BorgDrone<?, C>>> requiredDrones()

        Declares initialization prerequisites.

        Why a list?

        • Natural representation of multiple dependencies

        • Order doesn't matter (Borg handles sequencing)

        • Empty by default for leaf components

        Best practices:

        • List ALL required dependencies

        • Use constructor injection for dependencies

        • Keep dependency count low (ideally ≤ 3)

        • Document why each dependency is needed

        • Consider breaking up drones with many dependencies

        Example:

        override fun requiredDrones() = listOf(
            configDrone::class.java,  // For API configuration
            authDrone::class.java,    // For authentication tokens
            logDrone::class.java      // For request logging
        )
      • assimilate

         abstract T assimilate(C context, Borg<C> borg)

        Creates and configures a component instance.

        Contract:

        • Must be idempotent (same result for multiple calls)

        • Should complete initialization fully or fail fast

        • May access results of required drones via borg

        • Should return immutable or thread-safe result

        Best practices:

        • Validate inputs and dependencies early

        • Handle errors gracefully with fallbacks

        • Log important initialization steps

        • Clean up resources on failure

        • Keep initialization logic simple

        • Document any assumptions or requirements

        Example error handling:

        override suspend fun assimilate(context: C, borg: Borg<C>): T {
            try {
                // 1. Get dependencies
                val config = borg.requireAssimilated(configDrone::class.java)
        
                // 2. Validate configuration
                require(config.isValid) { "Invalid configuration" }
        
                // 3. Initialize component
                return MyComponent(config)
                    .also { it.initialize() }
        
            } catch (e: Exception) {
                // 4. Clean up on failure
                cleanup()
                throw BorgException.AssimilationException(
                    drone = this::class.java,
                    cause = e
                )
            }
        }
        Parameters:
        context - The context object needed for initialization
        borg - The Borg instance, providing access to assimilated drone values