Split kotlin function for immediate and suspend parts

## Summary
A Kotlin suspend function mixing foreground and background work caused unexpected blocking behavior when called. The function contained an immediate task (set `a=2`) and a delayed background task (set `a=3`). When called synchronously (`bar()`'s `foo()` call), it blocked until **both tasks completed**, preventing immediate access to intermediate results (`a=2`). 

## Root Cause
- **`coroutineScope` blocks until all child coroutines complete**. Using `coroutineScope` in `foo()` forced the caller to wait for `launch { ... }` (1-second delay), even though that work was intended to run asynchronously.
- **Poor separation of concerns**. Combining synchronous and fire-and-forget logic in a single suspend function created implicit dependency on background job completion.

## Why This Happens in Real Systems
- Engineers treat suspend functions as containing **fully asynchronous logic** by default
- **Concurrency lifecycle blindness**: Misjudging which tasks require wait semantics vs autonomous execution
- Overusing suspending contexts for mixed workflows without explicit control boundaries
- Tight coupling of logic phases due to shared state (`var a`)

## Real-World Impact
- **Blocked callers wasted resources** awaiting non-critical background work
- **Delayed processing** of intermediate results (e.g., UI updates with placeholder `a=2`)
- **Incorrect state visibility** causing race conditions when background work overrides state
- **Degraded throughput**: Synchronization hotspots where connectors shouldn't exist

## Example or Code
```kotlin
// Original problematic structure
suspend fun foo() = coroutineScope { 
    delay(100)
    a = 2  // Should be synchronous
    launch { // Should be asynchronous
        delay(1000)
        a = 3
    }
}
// Fixed approach for bar()
suspend fun bar() = coroutineScope {
    fooImmediate()   // Synchronous part
    launch { 
        fooAsync()   // Background work
    }
    println(a)  // Now correctly prints 2
}

// Refactored functions
suspend fun fooImmediate() {
    delay(100)
    a = 2
}

suspend fun fooAsync() {
    delay(1000)
    a = 3
}

How Senior Engineers Fix It

  1. Decouple logical phases: Split suspend fun foo() into:

    • A synchronous suspending function (fooImmediate())
    • An asynchronous fire-and-forget function (fooAsync())
  2. Encapsulate state transitions:

    suspend fun executeWorkflow() {
        doImmediateWork()
        startBackgroundWork() // Returns immediately
    }
  3. Design API boundaries:

    • Prefix with start... for fire-and-forget methods
    • Use run.../do... for synchronous tasks
    • Document background job ownership in method contracts
  4. Enable caller control: Let calling code manage the coroutine scope:

    // Caller chooses when to wait vs launch
    suspend fun fooImmediate() = { ... }
    fun CoroutineScope.fooAsync() = launch { ... }

Why Juniors Miss It

  • CoroutineScope misunderstanding: Assuming launch inside suspend functions doesn’t block callers
  • Magic-box thinking: Treating suspend functions as black boxes without considering internal concurrency mechanics
  • Premature encapsulation:
    • Forcing unrelated logic into single functions to “avoid duplication”
    • Over-prioritizing code reuse over execution semantics
  • Visibilityškills gap: Not pesar-leveling structured concurrency rules (coroutineScope waits for children)