Saat menggunakan AI untuk melakukan koding, biasanya kita melakukan planning terlebih dahulu. Namun, pada planning yang sudah dibuat oleh AI, output planning yang dihasilkan terkadang sulit untuk kita mengerti dan juga terkesan terlalu banyak jargon teknis yang sulit dipahami. Beberapa minggu yang lalu, aku melihat Dillon Mulroy membagikan bagaimana dia menggunakan callstack untuk membuat techical spec
Dan aku juga melihat Rin (r17x) menggunakan cara yang sama untuk planning.
Melihat penggunaan callstack yang mereka gunakan untuk planning membuatku merasa mudah untuk mereview apa yang sedang di plan oleh AI dan juga kita bisa melihat mock functionality dari callstack tersebut dan error apa yang diproduce. Tdak lama setelah itu, Rin membuat sebuah design thinking yang mengadopsi mental model effect typescript.
Effect adalah standard library untuk typeScript yang menyediakan runtime khusus agar kode asynchronous, error handling, dan dependency injection menjadi 100% type-safe dan terprediksi.
The Design Sin-Think
Jika kamu membuka design thinking kamu akan melihat workflow seperti ini:
X → Graph → Effect<A, E, R>
│ │ │ │ │
│ │ │ │ └─ what each node needs
│ │ │ └──── where the graph breaks
│ │ └─────── what flows through nodes
│ │
│ └─ nodes = functions, edges = data flow
│
└─ the problem: what you’re trying to build
Pemisahan Tiga Channel (A,E,R)
Di effect typescript, sebuah function yang memiliki potensi return error selalu diberikan return Effect<A,E,R> atau Effect<A,E> (jika tidak memiliki dependency). Nah ketiga channel tersebut memiliki sebuah definisi:
- A(Happy Path): Memaksa AI/human memetakan domain logic dari awal tanpa terkontaminasi error handling dan memberikan sebuah return value
- E (Failure Modes): Pengkategorian error menjadi Retry (transient), Escape (recoverable/expected), dan Die (bug/panic) adalah mental model yang universal di bahasa mana pun.
- R (Requirements): Sebuah dependency pada function tersebut untuk fleksibilitas testing.
Menggunakan Call graph untuk Planning
Terkadang saat AI melakukan planning, AI sering kali memberikan output teks yang panjang lebar dan disertai jargon sehingga sulit untuk kita pahami. Dengan memberi aturan untuk AI agar menyusun call graph berbasis A, E, R sebelum menulis kode, kita memaksa AI berpikir secara linier dan terstruktur.
Alur berpikir call graph pada dasarnya adalah sebuah hirarki kode yang akan ditulis.
Production:
HTTP Handler → UserService.getUser → UserRepo.findById → PostgresDB
Tests:
HTTP Handler → UserService.getUser → UserRepoMock
Saat AI menyusun call graph, ada beberapa hal menarik yang terjadi:
- Pemetaan Alur Data (A): Menentukan relasi antar function, data yang dilewatkan, dan struktur output akhir.
- Identifikasi Error Handling (E): Menentukan titik mana yang dapat menghasilkan error serta penanganannya (retry, fallback, atau die) sebelum function dibuat.
- Dependency (R): Setiap function mendeklarasikan dependency-nya secara terbuka, sehingga tidak ada hidden dependency di dalam kode.
Dengan call graph, proses code review terhadap planning AI menjadi lebih cepat. Jika call graph-nya salah atau terlalu rumit, kita bisa langsung memberi feedback di tahap planning sebelum baris kode pertama ditulis.
Mengadopsi Call graph Design Thinking
Mental model A, E, R bersifat agnostik dan dapat diterapkan di luar ekosistem TypeScript. Konsep ini dapat diadaptasi saat menulis kode di bahasa seperti Go, Swift, Kotlin, Dart, dll. Meskipun bahasa pemrograman tersebut tidak memiliki runtime bawaan seperti Effect, prinsip dasarnya tetap dapat diimplementasikan:
- Go: A direpresentasikan sebagai return value, E sebagai custom error untuk memisahkan retryable error dan domain error, dan R dipassing secara eksplisit melalui struct atau interface injection.
-
Kotlin: A dan E bisa menggunakan
Either<E, A>jika pakai library Arrow-kt atau sealed class/interface sebagai typed error, sedangkan R dipassing menggunakan constructor injection atau function parameter. -
Swift: A dan E bisa menggunakan
Result<T, E>atau async throws ber-tipe, sedangkan R menggunakan protocol-based dependency injection. -
Dart / Flutter: A dan E bisa menggunakan
Either<E, A>jika pakai library fpdart, dan R dipassing menggunakan constructor injection atau function parameter.
Untuk mengadopsi design thinking ini ke dalam workflow AI (seperti Cursor, Claude, atau LLM lainnya), kamu bisa menggunakan contoh prompt ini
In this session we are going to build a "[YOUR IDEA]" and this app has features:
[Breakdown The MVP]
The tech stack is:
- Flutter
Use best practice coding in Flutter and adopt this design thinking:
"[ATTACH GIST DESIGN THINKING URL/CONTENT]"
Actually this design thinking is based on the Effect TypeScript mental model, but we can adapt its core concepts (A, E, R channels, call graph planning, typed errors, clean dependency separation) into Flutter functional programming.
Please port the design thinking into effect-flutter skills before planning the architecture.
Prompt diatas hanyalah sebuah contoh saja dan aku sudah coba menerapkan ini pada projek swift. Ini adalah output yang dihasilkan claude saat melakukan planning
Penutup
Dengan mengadopsi cara ini, AI akan memetakan bagian happy path, error yang bisa direcovery atau tidak, kebutuhan dependency dari sebuah function/class, dan kita bisa memverifikasinya dengan mudah karena rancangan sistemnya lebih jelas.





Top comments (1)
your post is interesting
I would like to get to know you better and discuss about your post. Would you please contact me? t_g_@kanelim1997