<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[-1]]></title><description><![CDATA[-1 looks at education, technology, and programming through one simple question: what changes when one piece is missing? Issues vary: sometimes I preview research, sometimes I write practical how-tos, and sometimes I share a loose idea or code snippet.]]></description><link>https://www.0-1.my.id</link><image><url>https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png</url><title>-1</title><link>https://www.0-1.my.id</link></image><generator>Substack</generator><lastBuildDate>Tue, 01 Sep 2026 05:17:51 GMT</lastBuildDate><atom:link href="https://www.0-1.my.id/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[oon arfiandwi]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[oon@oo.or.id]]></webMaster><itunes:owner><itunes:email><![CDATA[oon@oo.or.id]]></itunes:email><itunes:name><![CDATA[oon arfiandwi]]></itunes:name></itunes:owner><itunes:author><![CDATA[oon arfiandwi]]></itunes:author><googleplay:owner><![CDATA[oon@oo.or.id]]></googleplay:owner><googleplay:email><![CDATA[oon@oo.or.id]]></googleplay:email><googleplay:author><![CDATA[oon arfiandwi]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Apa itu Agentic Software Engineering?]]></title><description><![CDATA[Dampak AI pada Software Engineering]]></description><link>https://www.0-1.my.id/p/apa-itu-agentic-software-engineering</link><guid isPermaLink="false">https://www.0-1.my.id/p/apa-itu-agentic-software-engineering</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Wed, 26 Aug 2026 11:03:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!M00h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!M00h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!M00h!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg 424w, https://substackcdn.com/image/fetch/$s_!M00h!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg 848w, https://substackcdn.com/image/fetch/$s_!M00h!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!M00h!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!M00h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2606346,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.0-1.my.id/i/213495211?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!M00h!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg 424w, https://substackcdn.com/image/fetch/$s_!M00h!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg 848w, https://substackcdn.com/image/fetch/$s_!M00h!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!M00h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b2c9d5e-f024-4437-b16f-817740bd7b91_2816x1536.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Sore tadi berdiskusi dengan pak dosen Agung mengenai topik kekinian, dampak AI pada Software Engineering, kemudian tersebutlah penggunaan <em>terms</em> Agentic Software Engineering.</p><p>Sekarang kita eksplor pembahasan Agentic Software Engineering ini di berbagai sumber di Internet dan AI :D</p><p>Pencarian sering mengarah ke tulisan dari Ahmed E. Hassan di antaranya:</p><ul><li><p>Agentic Software Engineering: Foundational Pillars and a Research Roadmap &#8212; https://arxiv.org/abs/2509.06216</p></li><li><p>Agentic Software Engineering: The rise of AI Teammates &#8212; https://link.springer.com/collections/aaaihgcafc</p></li><li><p>Agentic Software Engineering book &#8212; https://agenticse-book.github.io/</p></li></ul><p>Pendekatannya sebagai Software Engineering versi ke-3 (SE 3.0), dimana urutannya:</p><ol><li><p>Software Engineering versi awal (SE 1.0) adalah versi klasik dimana manusia seluruhnya yang coding.</p></li><li><p>Software Engineering versi berikutnya lagi (SE 2.0) dimana AI menjadi asisten.</p></li><li><p>Dan jadi lebih menarik ketika Software Engineering SE 3.0, ketika sejajar antara AI Agent dengan manusia, jadi AI menjadi anggota tim dalam development software.</p></li></ol><p>Beralih lagi sudut pandang lain, kalo Deloitte, menuliskan dampak <a href="https://www.deloitte.com/us/en/services/consulting/articles/agentic-ai-impact-on-software-engineering.html">Agentic AI ke Software Engineering</a> (ada juga pdf yang bisa dibaca di halaman tersebut), melihat dari sudut pandang software development life cycle (SDLC) ke agent orchestrated development life cycle (AO-DLC).</p><p>Satu lagi yang menarik adalah penyebutan Agentic Engineering, yang <a href="https://simonwillison.net/guides/agentic-engineering-patterns/">didokumentasikan sebagai Agentic Engineering Pattern oleh Simon Willison</a>, mungkin ada yang mengenalnya sebagai salah satu co-creator framework Django (Python Web), atau mengenalnya dari pengujian LLM menggambar <em>pelican riding a bicycle</em>.</p><p>Ngomong-ngomong tentang Agentic Engineering, <a href="https://addyosmani.com/blog/agentic-engineering/">Addy Osmani membuat tulisan Agentic Engineering yang menarik</a> juga, dikenal sebagai tech leader di Google, juga punya <a href="https://addyosmani.com/books/">banyak buku</a> yang menarik. Di artikel itu disebutkan bahwa terms Agentic Engineering mengacu ke <a href="https://x.com/karpathy/status/2019137879310836075">tulisan Andrej Karpathy di X</a>, terkait nama yang ingin dibedakan dari vibe coding (dimana post dibuat setahun sebelumnya), kemudian mengarah pada Agentic Engineering:</p><ul><li><p>Agentic: karena default saat ini kita nggak coding sendiri seperti masa klasik Software Engineering, hampir 99% waktu kita mengorkestrasi agents yang mengerjakan dan kita yang mengawasi.</p></li><li><p>Engineering: untuk menekankan sebenarnya ada keilmuan, seni, dan keahlian dibalik ini. Kemampuan yang tentunya bisa dipelajari dan dikuasai, serta memiliki kedalaman (mastery) ilmunya tersendiri dan berbeda dari coding yang klasik.</p></li></ul><p>Masih seputar terms dari Andrej Karpathy, ada <a href="https://www.ibm.com/think/topics/agentic-engineering">artikel dari IBM yang bahas Agentic Engineering</a> dilengkapi juga dengan <a href="https://www.youtube.com/watch?v=FgaBdwSvOGM">video YouTube membandingkan Agentic Engineering dengan Software Engineering</a>.</p><p>Dan masih terus mencari tentang Agentic Software Engineering ini.. </p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[pr: ptrace-based root ]]></title><description><![CDATA[&#8203;Weekend project: diving back into Linux chroot because I really wanted a native Linux environment on my phone!]]></description><link>https://www.0-1.my.id/p/pr-ptrace-based-root</link><guid isPermaLink="false">https://www.0-1.my.id/p/pr-ptrace-based-root</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Sun, 19 Apr 2026 14:46:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!hBkd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hBkd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hBkd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg 424w, https://substackcdn.com/image/fetch/$s_!hBkd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg 848w, https://substackcdn.com/image/fetch/$s_!hBkd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!hBkd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hBkd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2768359,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.0-1.my.id/i/194699203?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hBkd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg 424w, https://substackcdn.com/image/fetch/$s_!hBkd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg 848w, https://substackcdn.com/image/fetch/$s_!hBkd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!hBkd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34a47560-5655-47a3-a70d-fd8c35c387a0_2816x1536.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>&#8203;Weekend project: diving back into Linux chroot because I really wanted a native Linux environment on my phone! &#128170;&#128241;</p><p>&#8203;Everyone&#8217;s first thought is probably: "Just use Termux!"</p><p>Well, not quite. This journey actually started with me digging into virtualization, specifically the Android Virtualization Framework (AVF). Unfortunately, my current work phone (a Samsung powered by Snapdragon, huge thanks to Dicoding for the device &#128525;) doesn&#8217;t support AVF the way modern Google Pixels do. Waiting for it to arrive on this architecture feels like a long shot.</p><p>&#8203;So, I shifted gears and got inspired by proot. It&#8217;s incredibly clever how it utilizes ptrace to intercept system calls and translate them on the fly, effectively creating a virtual root filesystem without needing actual root access. This is the exact magic Termux adapted to run various Linux distros on Android.</p><p>&#8203;Bonus level unlocked &#128275;: Navigating around Android's W^X (Write XOR Execute) restrictions. This security mitigation is notoriously known for keeping similar apps stuck at Target SDK 28. Finding a way to bypass this and bump it up to SDK 35 is an interesting challenge, especially if I ever decide to publish this on the Play Store.</p><p>&#8203;For this weekend, the goal was to understand and implement proot without relying on the Termux environment&#8212;just wiring it up to a simple Android UI. Just for fun, I&#8217;m also porting a bunch of the initialization scripts into Rust &#129408; so I don&#8217;t have to rely too much on bash/mksh.</p><p>&#8203;You can check out the mess/progress here: <a href="https://github.com/oonid/pr">https://github.com/oonid/pr</a></p><p>&#8203;Oh, and this whole deep dive suddenly made me fully grasp a brilliant article written by Yohanes Nugroho a year ago about using seccomp for syscall interception in Linux and Android. Everything just clicks now! &#128513;</p><p>Read it here: <a href="https://blog.compactbyte.com/2025/04/27/seccomp-untuk-intersepsi-syscall-di-linux-dan-android/">https://blog.compactbyte.com/2025/04/27/seccomp-untuk-intersepsi-syscall-di-linux-dan-android/</a></p><p>&#8203;If pak Riza Satria (my lecturer) is still teaching Systems Programming, this could be a pretty fun use case for the class! &#129488;</p><p>&#8203;#AndroidDev #Linux #RustLang #SystemsProgramming #Termux #WeekendProject</p><p></p><p>(Cross-posted from LinkedIn)</p>]]></content:encoded></item><item><title><![CDATA[“It Works” Is Not the Same as “I Understand It”]]></title><description><![CDATA[In the previous article, I wrote about something I started to notice while developing several applications with AI coding agents.]]></description><link>https://www.0-1.my.id/p/it-works-is-not-the-same-as-i-understand</link><guid isPermaLink="false">https://www.0-1.my.id/p/it-works-is-not-the-same-as-i-understand</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Sun, 22 Mar 2026 02:57:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous article, I wrote about something I started to notice while developing several applications with AI coding agents. They let me move much faster, and I find them very effective. I can take an idea, discuss the architecture, start implementing it, test different approaches, and continue developing the project without spending the same amount of time writing every piece by hand.</p><p>After doing this across several repositories in <a href="http://github.com/oonid">github.com/oonid</a>, another feeling started to appear. It was not about whether the applications worked. Most of the time I knew what I had asked the agent to do, I had followed the implementation, and I could read the code afterward.</p><p>The uncomfortable part came when I tried to hold the whole project in my head.</p><p>I could recognize a module and remember the purpose of a feature, but sometimes the connections between them were less clear than I expected. Some decisions had happened several coding sessions earlier. Other parts had changed as the agent worked through a problem and found a better implementation. I had seen those changes when they happened, but seeing something is different from keeping it as part of my understanding.</p><p>This was a strange experience because these were my own projects. I was not joining an unfamiliar codebase written by another team. I had started the projects, made the main decisions, worked with the coding agent, and reviewed what it produced. Still, the software could move far enough that I needed to study my own project again.</p><p>The application could work while my understanding of it was already becoming incomplete.</p><p>That distinction has become important to how I think about AI-assisted software development.</p><p>A working application gives us many useful signals. It compiles. Tests pass. An API responds correctly. A feature behaves as expected. We may also have linting, static analysis, benchmarks, code review, and other forms of verification. All of these tell us something about the software.</p><p>They do not tell us how well the person responsible for the software understands it.</p><p>This problem existed long before coding agents. I have worked with enough software to know that nobody keeps every detail of a large system in their head. We depend on abstraction for that reason. We think about a database as a database instead of remembering every page written to disk. We think about a service through its responsibilities and interfaces instead of remembering every function.</p><p>AI changes the rate at which new abstractions, dependencies, files, and decisions can enter a project.</p><p>Before using coding agents heavily, implementing a new subsystem also forced me to spend time inside that subsystem. I wrote the code, made many small choices, encountered errors, fixed them, and slowly became familiar with the result. Some of that work was mechanical, but the time spent doing it also had an educational side effect: I was learning the system while creating it.</p><p>With an AI coding agent, part of that process is compressed. I can remain involved in the decisions while delegating much more of the implementation. This is one of the reasons the tool is productive. But it also means that an old relationship between production time and learning time starts to change.</p><p>I began to see this as an education problem as much as a software engineering problem.</p><p><strong>Producing an answer and learning something</strong></p><p>Education has dealt with a similar distinction for a long time.</p><p>A student can produce the correct answer without having a strong understanding of the subject. A learner may remember a procedure for solving a mathematics problem and become very good at applying it to exercises that have the same shape. The result is correct, so from the outside the learning process seems successful.</p><p>Change the problem slightly and the limitation becomes visible.</p><p>The student may know which formula to use but not why it works. Another student may be able to follow a worked example but struggle to solve a similar problem later without looking at the example again. In both cases, something has been learned, but the knowledge is not yet flexible enough to use in a different situation.</p><p>This is close to what I experience when reading AI-generated code and explanations.</p><p>While the code is in front of me, I can follow it. When an agent explains why a module is structured in a certain way, the explanation can be clear and useful. At that moment I may feel that I understand the design.</p><p>Later I discover whether that understanding stayed with me.</p><p>Can I explain the same part of the system when the original explanation is no longer open? Can I predict which other component will be affected when I change it? Can I connect a design decision from two weeks ago with a problem I am seeing today?</p><p>There is a familiar distinction in learning between recognition and recall. Recognizing something when we see it is easier than rebuilding it from memory. The same problem appears when we read source code. A function can look familiar without giving us a useful mental model of the larger system around it.</p><p>AI can make recognition very easy. It can continuously provide the missing explanation, locate the relevant code, summarize a module, and answer another question. These are useful capabilities, and I use them. But there is a risk that the tool becomes part of the memory loop. I understand the system while the assistant is present because the assistant can keep reconstructing the missing context for me.</p><p>For some tasks that may be perfectly fine. We already use documentation, search engines, IDEs, and reference books as external memory.</p><p>Software engineering, however, also requires judgment. When we design an architecture, review a risky change, investigate a production problem, or decide which trade-off is acceptable, we need enough of the system in our own mental model to reason across several pieces at once.</p><p>The amount we need to remember is not everything. The important part is knowing enough of the structure and its relationships to reason about the consequences of a decision.</p><p><strong>Code review is also a learning activity</strong></p><p>This way of thinking changed how I look at code review.</p><p>I used to think about review mainly in terms of software quality. I would look for incorrect behavior, design problems, missing tests, security issues, confusing names, or code that would be difficult to maintain. I still care about all of those things.</p><p>With AI-assisted development, I now see another purpose in the review process. Review is one of the places where I can update my own understanding of what the system has become.</p><p>This matters because the size of a diff does not tell us how much our mental model needs to change. A large mechanical refactoring may preserve the architecture almost completely. A very small modification may introduce a new assumption that changes how two parts of the system interact.</p><p>Git is good at showing textual change. It does not automatically tell me how much of my understanding needs to change with it.</p><p>This is also where the education perspective becomes useful. When a learner already understands a topic, we normally do not teach the entire subject again every time one new concept is introduced. We connect the new information to what the learner already knows.</p><p>Software could be approached in a similar way.</p><p>Suppose I understood a project yesterday. Today an agent changes twelve files. I probably do not need a new explanation of the entire repository. I need to know which concepts were added, which relationships changed, whether an old assumption no longer holds, and which parts of my previous understanding can remain as they were.</p><p>That is a much smaller learning problem, but it requires more than a diff.</p><p>It requires some representation of what the system meant before the change and what it means afterward.</p><p><strong>More information does not automatically help</strong></p><p>My first instinct was that better documentation might solve much of this. Documentation certainly helps, and I still consider it necessary, but I started to see a limitation there too.</p><p>An AI coding agent can generate documentation very quickly. It can create module descriptions, architecture summaries, diagrams, comments, and explanations of almost any part of a repository. The amount of available information is no longer the main limitation.</p><p>I can easily imagine reaching a point where the project contains more documentation than I have time to read.</p><p>Education has a useful lesson here as well. Giving a learner more material does not guarantee more learning. A textbook can contain everything required to understand a subject while a student remains confused. The order of ideas matters. Prior knowledge matters. Examples matter. Practice matters. Sometimes the learner needs a diagram, sometimes a concrete case, and sometimes they need to try explaining the idea themselves.</p><p>There is also cognitive load. Our working memory has limits, so presenting every available detail at once can make understanding harder. Good teaching manages that load by deciding what needs attention now and what can remain in the background.</p><p>Software tools rarely think this way. A repository browser gives us files. Git gives us commits and diffs. Static analysis gives us findings. A graph may give us hundreds or thousands of relationships. An AI assistant can summarize all of them.</p><p>Every one of those outputs may be correct, yet the human still has to decide what matters.</p><p>That is where my thinking about makna started to change.</p><p>The early idea was strongly connected to observing development activity. If an AI agent changes software, it seemed useful to capture what the agent did and connect that activity to the state of the repository. The history between a request and the resulting code contains information that Git alone does not preserve.</p><p>But collecting more evidence does not solve the comprehension problem by itself.</p><p>A complete recording of an agent session could include prompts, tool calls, file modifications, compiler output, test results, retries, and many intermediate actions. It could be an accurate history and still be exhausting for a human to read.</p><p>So I started separating three different problems in my head.</p><p>First, we need to know what happened. That requires evidence from the coding agent, repository, Git, compiler, tests, and other sources.</p><p>Then we need to understand what those observations mean for the software. A changed file is an observation, but the engineering meaning may be that a component gained a new responsibility, an interface changed, or a dependency moved across a boundary.</p><p>Finally, the human needs a useful way to learn from that knowledge.</p><p>These ideas eventually became the Observation, Knowledge, and Comprehension planes in makna. I did not start with those names. They appeared after trying to separate problems that initially looked like one problem.</p><p>The third plane is the one I find especially important now.</p><p>A system can collect correct evidence and build an accurate model of software while still failing to help the engineer understand it. Comprehension has its own requirements because people learn in a different way from databases storing facts.</p><p><strong>Keeping my mental model up to date</strong></p><p>Thinking about learning also led me to a more specific idea.</p><p>I do not need makna to teach me my entire project every morning. Most of what I understood yesterday is probably still useful today.</p><p>What I need is a way to notice when that understanding should change.</p><p>If an agent adds a helper function, my architectural understanding may stay exactly the same. If the agent moves persistence responsibility from one component to another, I need to update part of my mental model even if the code change itself is small.</p><p>If a new service appears, I need to learn what role it has and how it connects to the rest of the system. If an old abstraction disappears, I should stop carrying that abstraction in my head. And if the implementation changes while the architectural meaning remains stable, I may only need a brief note.</p><p>This eventually led us to the concept of ComprehensionDelta in makna: the difference between what a person needed to understand about the previous state and what they need to understand about the new state.</p><p>I like this idea because it connects the history of software with the process of learning it.</p><p>The repository has a history.</p><p>The engineering model has a history.</p><p>Our understanding has a history too.</p><p>AI coding agents make the first history move faster. makna is an attempt to help the third one keep up.</p><p>I still want AI to help me write more software. My experience with it has been productive enough that going back to the old way of doing everything manually would make little sense to me. The problem I want to work on is what happens after that productivity gain.</p><p>When I return to one of my own projects, I want to remain close enough to it that I can explain the important parts, follow how they changed, and make the next engineering decision with a mental model I can trust.</p><p>The application working is one result.</p><p>Understanding what I have built is another.</p>]]></content:encoded></item><item><title><![CDATA[AI Can Write More Code Than I Can Understand]]></title><description><![CDATA[Lately, I have been developing many applications in github.com/oonid, and AI coding agents have become a normal part of how I work.]]></description><link>https://www.0-1.my.id/p/ai-can-write-more-code-than-i-can</link><guid isPermaLink="false">https://www.0-1.my.id/p/ai-can-write-more-code-than-i-can</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Sat, 21 Mar 2026 01:01:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Lately, I have been developing many applications in <a href="http://github.com/oonid">github.com/oonid</a>, and AI coding agents have become a normal part of how I work. They are effective. I can explore an idea, build something, revise it, test it, and continue much faster than I could when I had to write every part myself.</p><p>For a software developer, this is exciting. I can spend more time thinking about architecture and problems instead of typing every line of code. Projects that might have taken much longer can now move forward very quickly.</p><p>After doing this for a while, however, I noticed something uncomfortable.</p><p>My repositories were growing faster than my understanding of them.</p><p>I could open a project and recognize the code. I knew what I had asked the coding agent to build, and I had reviewed many of the changes when they were created. The application worked and the tests could pass, yet sometimes I needed time to rebuild the larger picture in my head. I had to remember how the components were connected, why a certain design was chosen, what had changed during several AI-assisted sessions, and which decisions still mattered.</p><p>That moment stayed with me because I was not looking at someone else&#8217;s project. These were my projects. I had been involved from the beginning.</p><p>AI had helped me produce more software, but my ability to produce software had increased faster than my ability to keep all of that software in my head.</p><p>This is different from saying that AI writes bad code. In many cases, I am impressed by how useful coding agents have become. The problem can appear even when the generated code is good.</p><p><strong>Software engineering has always required us to manage complexity</strong>, but AI changes the rate at which that complexity can arrive. A developer can now create, modify, and extend a system much faster, while human learning still takes time. We need to <strong>read, connect ideas, remember decisions, and gradually build a mental model</strong> of the system.</p><p>That difference between the speed of software production and the speed of human understanding became one of the reasons I started thinking about makna.</p><p>I want to explore whether we can keep the productivity of AI-assisted development without becoming disconnected from the software we are creating.</p><p>If AI helps us write more code, I think we also need better ways to keep understanding what that code becomes.</p>]]></content:encoded></item><item><title><![CDATA[mini-redis client & server]]></title><description><![CDATA[Belajar tokio dengan contoh kasus mini-redis.]]></description><link>https://www.0-1.my.id/p/mini-redis-client-and-server</link><guid isPermaLink="false">https://www.0-1.my.id/p/mini-redis-client-and-server</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Tue, 28 Oct 2025 16:58:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Belajar tokio dengan contoh kasus mini-redis.</p><p></p><p><a href="https://tokio.rs/tokio/tutorial/setup">https://tokio.rs/tokio/tutorial/setup</a></p><p></p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Membedah Dynamo: Resep Rahasia Amazon untuk Sistem yang "Tidak Bisa Mati"]]></title><description><![CDATA[Pernahkah Anda terbangun tengah malam karena notifikasi PagerDuty yang memekakkan telinga?]]></description><link>https://www.0-1.my.id/p/membedah-dynamo-resep-rahasia-amazon</link><guid isPermaLink="false">https://www.0-1.my.id/p/membedah-dynamo-resep-rahasia-amazon</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Mon, 27 Oct 2025 16:55:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Pernahkah Anda terbangun tengah malam karena notifikasi PagerDuty yang memekakkan telinga? Server down, database tidak merespons, dan entah bagaimana, semua jari menunjuk ke arah Anda. Membangun sistem yang tangguh itu sulit. Membangun sistem yang harus selalu online 100%,nbahkan saat separuh dunia digital sedang terbakar, rasanya hampir mustahil.</p>]]></content:encoded></item><item><title><![CDATA[Eksplorasi Dynomite dari Netflix]]></title><description><![CDATA[Proyek open-source Dynomite dari Netflix https://github.com/Netflix/dynomite punya unique selling point karena seperti fitur yang hanya dimiliki oleh redis yang berbayar.]]></description><link>https://www.0-1.my.id/p/eksplorasi-dynomite-dari-netflix</link><guid isPermaLink="false">https://www.0-1.my.id/p/eksplorasi-dynomite-dari-netflix</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Sun, 26 Oct 2025 16:59:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Proyek open-source Dynomite dari Netflix <a href="https://github.com/Netflix/dynomite">https://github.com/Netflix/dynomite</a> punya unique selling point karena seperti fitur yang hanya dimiliki oleh redis yang berbayar.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Data Mesh,  Momen Ketika DDD Bertemu Dunia Data]]></title><description><![CDATA[Selama bertahun-tahun, sistem perangkat lunak dan sistem data berkembang dalam dua dunia yang hampir terpisah.]]></description><link>https://www.0-1.my.id/p/data-mesh-momen-ketika-ddd-bertemu</link><guid isPermaLink="false">https://www.0-1.my.id/p/data-mesh-momen-ketika-ddd-bertemu</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Sat, 25 Oct 2025 16:57:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Selama bertahun-tahun, sistem perangkat lunak dan sistem data berkembang dalam dua dunia yang hampir terpisah.</p><p>Aplikasi bisnis dibangun dengan prinsip domain dan bounded context, sementara sistem data &#8212; terutama data lake dan data warehouse &#8212; dikelola secara terpusat oleh tim analitik.</p><p></p><p>to be continued.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Event-Driven Architecture, Menyatukan Domain melalui Peristiwa ]]></title><description><![CDATA[Dalam sistem modern, banyak hal tidak lagi berjalan secara berurutan.]]></description><link>https://www.0-1.my.id/p/event-driven-architecture-menyatukan</link><guid isPermaLink="false">https://www.0-1.my.id/p/event-driven-architecture-menyatukan</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Fri, 24 Oct 2025 15:59:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Dalam sistem modern, banyak hal tidak lagi berjalan secara berurutan.</p><p>Perangkat lunak perlu bereaksi terhadap berbagai kejadian yang muncul di waktu berbeda, dari berbagai sumber, dan kadang tanpa koordinasi langsung.</p><p>Inilah konteks di mana Event-Driven Architecture (EDA) menjadi relevan.</p><p></p><p>Sementara Domain-Driven Design (DDD) fokus pada memahami dan memodelkan domain bisnis,</p><p>Event-Driven Architecture fokus pada mengalirkan informasi tentang perubahan domain ke seluruh sistem.</p><p></p><p>to be continued.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Microservices, Antara Ukuran Kecil dan Kompleksitas Besar]]></title><description><![CDATA[Beberapa tahun terakhir, kata microservices seolah menjadi mantra sakti di dunia teknologi.]]></description><link>https://www.0-1.my.id/p/microservices-antara-ukuran-kecil</link><guid isPermaLink="false">https://www.0-1.my.id/p/microservices-antara-ukuran-kecil</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Thu, 23 Oct 2025 16:59:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Beberapa tahun terakhir, kata <em>microservices</em> seolah menjadi mantra sakti di dunia teknologi. Banyak perusahaan beralih dari monolit ke microservices dengan harapan semua masalah skala, performa, dan kolaborasi akan terselesaikan.</p><p>Namun, kenyataannya sering jauh dari harapan: setelah dipecah menjadi banyak service, tim justru kebingungan mengelola dependensi, data tersebar, dan komunikasi antar sistem menjadi mimpi buruk.</p><p>Vlad Khononov menyebut fenomena ini dengan sangat tepat:</p><blockquote><p>&#8220;Microservices are not the destination &#8212; they are the outcome of understanding your domain.&#8221; &#8212; <em>Vlad Khononov, Learning Domain-Driven Design</em> (2022)</p></blockquote><p>Dengan kata lain, <strong>microservices bukan tujuan, melainkan konsekuensi logis dari penerapan DDD yang baik.</strong></p><h2>Microservices dan Janji Kemerdekaan</h2><p>Secara konsep, <em>microservice architecture</em> adalah tentang memecah sistem besar menjadi unit-unit kecil yang <strong>dapat dikembangkan, dirilis, dan diskalakan secara independen.</strong></p><p>Setiap microservice:</p><ul><li><p>Menangani satu fungsi bisnis tertentu,</p></li><li><p>Memiliki data sendiri,</p></li><li><p>Dan bisa dikelola oleh satu tim otonom.</p></li></ul><p>Tujuannya terdengar sederhana: <em>independence and scalability.</em> Namun dalam praktiknya, banyak organisasi gagal karena <strong>tidak memahami batas domain sebelum membagi service.</strong></p><blockquote><p>&#8220;Without understanding domain boundaries, splitting a monolith creates distributed chaos, not distributed systems.&#8221; &#8212; <em>Khononov, 2022</em></p></blockquote><p>Dan di situlah peran DDD menjadi sangat penting.</p><h2>Hubungan DDD dan Microservices</h2><p>DDD memberi fondasi berpikir yang kuat untuk menentukan <strong>batas alami</strong> dari setiap microservice, yaitu melalui konsep <strong>bounded context</strong>.</p><ul><li><p>DDD Concept: Bounded Context</p><ul><li><p>Padanan Microservices: Microservice Boundary </p></li><li><p>Tujuan: Memisahkan logikadan model bisnis secara mandiri </p></li></ul></li><li><p>DDD Concept: <em>Ubiquitous Language</em> </p><ul><li><p>Padanan Microservices: Service API Contract</p></li><li><p>Tujuan: Bahasa dan istilah konsisten dalam satu tim</p></li></ul></li><li><p>DDD Concept: <em>Context Map</em></p><ul><li><p>Padanan Microservices: Service Interaction Diagram</p></li><li><p>Tujuan: Hubungan antar service dan pola komunikasinya</p></li></ul></li><li><p>DDD Concept: <em>Communication Pattern</em> </p><ul><li><p>Padanan Microservices: API/Event Integration</p></li><li><p>Tujuan: Cara service berkoordinasi tanpa coupling</p></li></ul></li></ul><p>Jadi, <em>bounded context</em> dalam DDD bukan sekadar konsep abstrak, ia adalah <strong>peta alami yang membantu kita menentukan microservice yang sehat.</strong></p><h2>Bounded Context Sebagai Panduan Desain Microservice</h2><p>Banyak kegagalan microservice berasal dari salah memotong sistem: dibagi berdasarkan <strong>lapisan teknis</strong> (UI, backend, database), bukan <strong>area bisnis.</strong></p><p>Hasilnya: service terlalu kecil, saling bergantung, dan kehilangan makna bisnis.</p><p>DDD membantu memotong sistem secara <strong>semantik</strong>, bukan <strong>struktural.</strong></p><p><strong>Contoh:</strong> Daripada membagi berdasarkan teknologi:</p><pre><code>/user-api
/payment-service
/database-service</code></pre><p>DDD akan mendorong pembagian berdasarkan domain:</p><pre><code>/billing-context
/inventory-context
/customer-context</code></pre><p>Setiap context punya logika, data, dan bahasa sendiri, itulah microservice yang benar-benar &#8220;domain-driven&#8221;.</p><h2>Integrasi Antar Microservice: Komunikasi Antara Context</h2><p>Ketika kita punya banyak bounded context (atau microservice), komunikasi di antaranya harus dikelola dengan hati-hati.</p><p>DDD memperkenalkan <em>communication patterns</em> yang juga relevan di dunia microservices, seperti:</p><ul><li><p><strong>Customer&#8211;Supplier</strong></p></li><li><p><strong>Conformist</strong></p></li><li><p><strong>Partnership</strong></p></li><li><p><strong>Separate Ways</strong></p></li></ul><p>Dalam konteks arsitektur terdistribusi, pola-pola ini bisa diterjemahkan sebagai:</p><ul><li><p>Customer&#8211;Supplier &#8594; satu service tergantung API dari service lain,</p></li><li><p>Conformist &#8594; mengikuti format upstream tanpa perubahan,</p></li><li><p>Partnership &#8594; dua tim berkolaborasi erat,</p></li><li><p>Separate Ways &#8594; berjalan mandiri tanpa integrasi real-time.</p></li></ul><p>Misalnya:</p><pre><code>// Contoh komunikasi event-driven antar microservice
#[derive(serde::Serialize, serde::Deserialize)]
struct OrderPlaced {
    order_id: u64,
    total: f64,
}

fn publish_order_placed(order: OrderPlaced) {
    // publish ke message broker (Kafka, NATS, dll)
    println!("Publishing event: {:?}", order);
}</code></pre><p>Pendekatan event-driven ini menjaga agar microservice tetap otonom, karena setiap service bereaksi terhadap event, bukan memanggil service lain secara langsung.</p><h2>Tantangan Microservice di Dunia Nyata</h2><p>Meski konsepnya indah, arsitektur microservices membawa <strong>kompleksitas baru.</strong></p><p>Khononov mengingatkan, bahwa:</p><blockquote><p>&#8220;Microservices move complexity from code to communication.&#8221; &#8212; <em>Vlad Khononov, 2022</em></p></blockquote><p>Mari lihat beberapa jebakan umum yang sering terjadi:</p><h3>1. <strong>Over-segmentation (Service Terlalu Kecil)</strong></h3><p>Engineer terlalu semangat memecah sistem hingga setiap fungsi menjadi satu service. Akibatnya, integrasi menjadi rumit dan deployment berantakan.</p><p><em>Solusi:</em> Pastikan setiap service punya makna domain utuh (bounded context lengkap), bukan sekadar endpoint CRUD.</p><h3>2. <strong>Shared Database</strong></h3><p>Beberapa service masih berbagi database yang sama, ini menghapus batas konteks.</p><p><em>Solusi:</em> Setiap service memiliki <strong>database sendiri</strong>, bahkan jika data yang disimpan mirip. Gunakan event untuk sinkronisasi, bukan query silang.</p><h3>3. <strong>Communication Hell</strong></h3><p>Service saling memanggil API secara berantai (A &#8594; B &#8594; C &#8594; D). Jika satu mati, semuanya ikut gagal.</p><p><em>Solusi:</em> Gunakan <strong>asynchronous messaging (event-driven)</strong> untuk mengurangi coupling antar service.</p><h3>4. <strong>Terlalu Banyak Infrastruktur</strong></h3><p>Microservice memerlukan CI/CD pipeline, monitoring, logging, service mesh, dan sebagainya. Untuk tim kecil, overhead ini bisa lebih mahal daripada manfaatnya.</p><p><em>Solusi:</em> Mulai dari <em>modular monolith</em>, struktur monolit yang sudah terpisah per context. Jika sudah stabil, baru evolusikan ke microservice sejati.</p><h2>Modular Monolith Sebagai Titik Awal</h2><p>Khononov menyarankan pendekatan yang realistis:</p><blockquote><p>&#8220;Start with a modular monolith. Split it when you must, not when you can.&#8221; &#8212; <em>Khononov, 2022</em></p></blockquote><p>Artinya, kamu bisa mulai dengan sistem monolit tunggal, tapi struktur internalnya sudah mengikuti prinsip <em>bounded context.</em></p><p>Contoh struktur folder dalam Rust:</p><pre><code>src/
 &#9500;&#9472;&#9472; billing/
 &#9474;    &#9500;&#9472;&#9472; domain.rs
 &#9474;    &#9500;&#9472;&#9472; service.rs
 &#9474;    &#9492;&#9472;&#9472; repository.rs
 &#9500;&#9472;&#9472; inventory/
 &#9474;    &#9500;&#9472;&#9472; domain.rs
 &#9474;    &#9492;&#9472;&#9472; service.rs
 &#9492;&#9472;&#9472; main.rs</code></pre><p>Ketika skala sistem tumbuh, tiap folder domain ini bisa dengan mudah dipecah menjadi microservice independen, karena sejak awal, batas context-nya sudah jelas.</p><h2>DDD sebagai Landasan Microservice Sehat</h2><p>Inti dari pesan Khononov sangat sederhana tapi krusial:</p><blockquote><p>&#8220;Without DDD, microservices are just distributed monoliths.&#8221; &#8212; <em>Vlad Khononov (2022)</em></p></blockquote><p>DDD membantu kita:</p><ol><li><p>Menentukan batas yang sehat (<em>bounded contexts</em>),</p></li><li><p>Menjaga otonomi antar tim,</p></li><li><p>Mencegah duplikasi logika bisnis,</p></li><li><p>Menghindari coupling antar service.</p></li></ol><p>Dengan kata lain, <strong>DDD adalah kompas yang menunjukkan di mana memotong sistem.</strong> Microservices hanyalah hasil fisik dari pemotongan itu.</p><h2>Ringkasnya, Microservices yang Bermakna</h2><p>Microservices bukan soal ukuran kecil, tapi soal <strong>batas makna yang jelas.</strong> Sebuah microservice seharusnya mencerminkan satu domain bisnis yang utuh, bukan sekadar satu tabel di database atau satu endpoint di API gateway.</p><p>DDD membantu kita menemukan batas itu, bukan lewat intuisi arsitek, tapi lewat percakapan lintas tim, pemahaman domain, dan bahasa umum yang disepakati.</p><blockquote><p>&#8220;Good microservices emerge from good domain models.&#8221; &#8212; <em>Vlad Khononov, Learning Domain-Driven Design</em> (2022)</p></blockquote><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[DDD di Dunia Nyata, Antara Ideal dan Kenyataan]]></title><description><![CDATA[Setelah memahami konsep DDD dari sisi teori, strategi, dan taktik, sering kali muncul satu kesimpulan sederhana dari engineer yang sudah mencoba menerapkannya: &#8220;DDD di buku itu indah.]]></description><link>https://www.0-1.my.id/p/ddd-di-dunia-nyata-antara-ideal-dan</link><guid isPermaLink="false">https://www.0-1.my.id/p/ddd-di-dunia-nyata-antara-ideal-dan</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Wed, 22 Oct 2025 16:11:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Setelah memahami konsep DDD dari sisi teori, strategi, dan taktik, sering kali muncul satu kesimpulan sederhana dari engineer yang sudah mencoba menerapkannya: &#8220;DDD di buku itu indah. Tapi di dunia nyata&#8230; ya, tidak sesempurna itu.&#8221;</p><p>Dan memang benar. Vlad Khononov sendiri menekankan sejak awal bahwa <em>Domain-Driven Design</em> bukanlah metode magis yang menjamin keberhasilan proyek, melainkan <strong>sekumpulan pola pikir dan alat bantu untuk memahami serta mengelola kompleksitas.</strong></p><p>Dalam bab ini, kita akan melihat <strong>bagaimana DDD diterapkan secara pragmatis di dunia nyata</strong>, termasuk kesalahpahaman umum, jebakan organisasi, dan strategi agar tetap waras dalam menghadapi kenyataan.</p><h2>Kenyataan #1: Tidak Semua Sistem Butuh DDD</h2><p>Salah satu kesalahan paling sering ditemui di dunia profesional adalah <strong>menerapkan DDD di semua tempat.</strong></p><p>Padahal, tidak semua sistem punya kompleksitas yang layak untuk itu.</p><p>DDD diciptakan untuk domain yang:</p><ul><li><p>Kompleks secara <em>bisnis</em>, bukan hanya teknis.</p></li><li><p>Penuh ambiguitas dan aturan yang berubah cepat.</p></li><li><p>Memerlukan komunikasi intens antara developer dan domain expert.</p></li></ul><p>Kalau sistem kamu hanya mencatat data CRUD (Create, Read, Update, Delete), maka memakai DDD lengkap akan terasa seperti <strong>menggunakan bazooka untuk memecahkan telur.</strong></p><blockquote><p>&#8220;DDD is not for every project &#8212; it&#8217;s for the ones where business complexity rules.&#8221; &#8212; Vlad Khononov, <em>Learning Domain-Driven Design</em> (2022)</p></blockquote><p>Jadi, <em>if it&#8217;s simple, keep it simple.</em> Gunakan pendekatan ringan seperti <em>Transaction Script</em> atau <em>Active Record</em> untuk modul sederhana, dan hanya terapkan DDD penuh pada bagian yang benar-benar strategis.</p><h2>Kenyataan #2: Organisasi Lebih Sulit dari Kode</h2><p>DDD sering kali gagal bukan karena engineer tidak paham model, tapi karena <strong>organisasi tidak siap untuk cara berpikir kolaboratif.</strong></p><p>Di dunia nyata:</p><ul><li><p>Tim terpisah oleh silo,</p></li><li><p>Komunikasi antar departemen buruk,</p></li><li><p>&#8220;Ahli domain&#8221; tidak selalu punya waktu untuk berdiskusi,</p></li><li><p>Dan setiap tim punya KPI sendiri-sendiri.</p></li></ul><p>Hasilnya? Setiap orang punya versi modelnya sendiri, dan <em>ubiquitous language</em> yang ideal di buku berubah jadi <em>babel language</em> di kantor.</p><blockquote><p>&#8220;The real challenge of DDD is not modeling the software &#8212; it&#8217;s modeling the organization.&#8221; &#8212; <em>Khononov, 2022</em></p></blockquote><p><strong>Strategi realistis:</strong> Mulai dari lingkar kecil, satu tim yang mau berkolaborasi penuh. Bangun <em>bounded context</em> pertama di situ, dan buktikan hasilnya. Setelah berhasil, baru tularkan ke tim lain.</p><h2>Kenyataan #3: Bounded Context Itu Tidak Harus Rapi</h2><p>Di teori, <em>bounded context</em> terlihat jelas: setiap domain punya batas logis, bahasa sendiri, dan modelnya tidak tumpang-tindih.</p><p>Tapi di dunia nyata, batas itu sering kabur:</p><ul><li><p>Ada konteks yang saling tumpang tindih,</p></li><li><p>Ada istilah yang &#8220;nyasar&#8221; karena kebutuhan API,</p></li><li><p>Kadang satu tim harus mengurusi dua domain karena alasan praktis.</p></li></ul><p>Dan itu <strong>tidak apa-apa.</strong></p><p>DDD bukan tentang kesempurnaan arsitektur, tapi tentang <em>kesadaran terhadap batasan.</em> Selama tim sadar di mana batas tanggung jawabnya, DDD tetap hidup.</p><blockquote><p>&#8220;It&#8217;s okay if your boundaries are blurry &#8212; as long as you know they&#8217;re blurry.&#8221; &#8212; <em>Khononov, 2022</em></p></blockquote><p>Contohnya, dua tim mungkin sama-sama menggunakan istilah <em>Order</em>. Tapi yang penting adalah:</p><ul><li><p>Mereka tahu makna &#8220;Order&#8221; di masing-masing context,</p></li><li><p>Dan mereka tidak saling memaksakan model satu sama lain.</p></li></ul><h2>Kenyataan #4: Model Akan Selalu Berubah</h2><p>Sering kali, tim DDD pemula ingin membuat <em>domain model final</em> sebelum mulai coding. Padahal, seperti dibahas di Bab 11, <strong>model domain itu hasil belajar, bukan hasil perencanaan.</strong></p><p>Model yang baik bukan yang paling stabil, tapi yang paling mudah beradaptasi.</p><p><strong>Praktik nyata:</strong> Gunakan pendekatan <em>event-driven</em> untuk memantau perubahan domain. Setiap kali muncul <em>event</em> baru yang tidak masuk akal, itu tanda modelmu butuh revisi.</p><p>Misalnya:</p><pre><code>// Model awal
enum OrderStatus {
    Pending,
    Paid,
}

// Setelah bisnis menambah fitur refund
enum OrderStatus {
    Pending,
    Paid,
    Refunded,
}</code></pre><p>Model berkembang bukan karena salah di awal, tapi karena <strong>bisnis berubah dan pengetahuan bertambah.</strong></p><h2>Kenyataan #5: Kompromi Itu Wajar</h2><p>Setiap proyek di dunia nyata berhadapan dengan tiga tekanan utama:</p><ol><li><p><strong>Waktu</strong>: deadline yang ketat,</p></li><li><p><strong>Sumber daya</strong>: tim kecil, beban besar,</p></li><li><p><strong>Teknologi warisan (legacy)</strong>: keputusan lama yang sulit diubah.</p></li></ol><p>Dan di tengah tekanan itu, idealisme DDD kadang harus dikompromikan.</p><blockquote><p>&#8220;A pragmatic architect knows when to bend the rules.&#8221; &#8212; <em>Khononov, 2022</em></p></blockquote><p>Kompromi tidak berarti menyerah. Yang penting adalah tahu <strong>kapan dan kenapa</strong> melanggar prinsip.</p><p> <strong>Contoh kompromi sehat:</strong></p><ul><li><p>Sementara gunakan model anemik (tanpa logika bisnis di entitas), lalu perlahan refactor ketika domain makin jelas.</p></li><li><p>Tulis <em>event</em> secara manual dulu tanpa bus, lalu evolusikan jadi <em>event-driven architecture</em> saat skalanya cukup besar.</p></li><li><p>Gunakan <em>shared database</em> sementara untuk sinkronisasi antar context, tapi tandai sebagai <em>temporary coupling.</em></p></li></ul><p>Kunci keberhasilan DDD di dunia nyata adalah <strong>transparansi dalam kompromi.</strong></p><h2>Kenyataan #6: DDD Adalah Perjalanan, Bukan Tujuan</h2><p>Banyak tim berpikir bahwa &#8220;menerapkan DDD&#8221; adalah milestone yang bisa dicapai. Padahal, DDD itu bukan proyek &#8212; ia <em>cara berpikir yang berkelanjutan.</em></p><p>DDD yang sehat terlihat bukan dari diagram yang indah, tapi dari <strong>komunikasi yang lancar antar tim, pemahaman yang jelas tentang domain, dan model yang tumbuh bersama bisnis.</strong></p><blockquote><p>&#8220;The success of DDD is not measured in aggregates, but in shared understanding.&#8221; &#8212; Vlad Khononov (2022)</p></blockquote><p>Ketika orang bisnis, developer, dan QA bisa berbicara tanpa translator, itulah saat DDD benar-benar hidup, bahkan tanpa disebut DDD.</p><h2>Kenyataan #7: Legacy Systems Bisa Diperbaiki Bertahap</h2><p>Banyak perusahaan tidak memulai dari nol. Mereka punya sistem lama, penuh logika bercampur, dan database yang menua.</p><p>Kabar baiknya: <strong>DDD bisa diterapkan secara bertahap.</strong></p><p>Mulailah dari memetakan domain dan event dengan <em>EventStorming</em> (Bab 12). Temukan <em>bounded context</em> tersembunyi di dalam monolit, dan pisahkan secara evolusioner.</p><p>Contohnya, dari monolit besar, ekstrak satu domain kecil seperti <em>Invoice Management</em> menjadi microservice mandiri dengan domain model sendiri.</p><p>Dengan cara itu, DDD menjadi strategi <em>perbaikan berkelanjutan</em>, bukan proyek overhaul besar.</p><h2>Heuristik untuk Bertahan di Dunia Nyata</h2><p>Khononov menutup buku ini dengan beberapa heuristik penting bagi praktisi DDD:</p><ul><li><p>Heuristik: <strong>Mulai dari percakapan, bukan kode.</strong> </p><ul><li><p>Penjelasan: DDD lahir dari dialog dengan domain expert. </p></li></ul></li><li><p>Heuristik: <strong>Desain secukupnya.</strong> </p><ul><li><p>Penjelasan: Tidak semua bagian butuh arsitektur kompleks. </p></li></ul></li><li><p><strong>Refactor berdasarkan pembelajaran.</strong> </p><ul><li><p>Penjelasan: Evolusi model harus mengikuti realitas bisnis. </p></li></ul></li><li><p><strong>Gunakan bahasa bisnis di kode.</strong> </p><ul><li><p>Penjelasan: Nama-nama class, function, dan event harus masuk akal bagi non-engineer. </p></li></ul></li><li><p><strong>Toleransi terhadap kekacauan.</strong> </p><ul><li><p>Penjelasan: Di awal, model pasti berantakan &#8212; dan itu normal. </p></li></ul></li><li><p><strong>Rayakan perbaikan kecil.</strong> </p><ul><li><p>Penjelasan: Setiap domain yang jadi lebih mudah dipahami adalah kemenangan.</p></li></ul></li></ul><h2>Ringkasnya, DDD yang Sejati Adalah DDD yang Hidup</h2><p>Pada akhirnya, DDD bukan tentang pola, agregat, atau bounded context yang sempurna. DDD adalah tentang <strong>membawa makna bisnis ke dalam perangkat lunak</strong> dengan cara yang bisa berkembang bersama waktu.</p><p>Di dunia nyata, DDD yang berhasil bukan yang 100% sesuai buku, tapi yang 100% <em>dipahami</em> oleh orang-orang yang membangunnya.</p><blockquote><p>&#8220;Perfect DDD doesn&#8217;t exist &#8212; but meaningful DDD does.&#8221; &#8212; Vlad Khononov, <em>Learning Domain-Driven Design</em> (2022)</p></blockquote><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[EventStorming dimana Menemukan Pemahaman Bersama Melalui Peristiwa]]></title><description><![CDATA[Salah satu tantangan terbesar dalam DDD bukanlah menulis kode,]]></description><link>https://www.0-1.my.id/p/eventstorming-dimana-menemukan-pemahaman</link><guid isPermaLink="false">https://www.0-1.my.id/p/eventstorming-dimana-menemukan-pemahaman</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Tue, 21 Oct 2025 16:17:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Salah satu tantangan terbesar dalam DDD bukanlah menulis kode,</p><p>melainkan menyatukan pemahaman antara orang-orang yang berbicara bahasa berbeda:</p><p>engineer, product manager, domain expert, dan stakeholder bisnis.</p><p>Setiap orang membawa perspektifnya sendiri:</p><ul><li><p>Engineer berpikir dalam entitas dan API,</p></li><li><p>Product manager berpikir dalam fitur,</p></li><li><p>Domain expert berpikir dalam proses dan peraturan bisnis.</p></li></ul><p>Dan sering kali, perbedaan bahasa ini membuat diskusi berputar tanpa hasil.</p><p>Nah, <em>EventStorming</em> hadir untuk menjembatani semua itu.<br>Ini bukan teknik coding, tapi teknik <strong>berpikir dan berkolaborasi visual</strong> agar tim memahami domain dengan cara yang sama.</p><blockquote><p>&#8220;EventStorming is a workshop-based method to explore complex domains by focusing on domain events.&#8221; &#8212; Vlad Khononov, <em>Learning Domain-Driven Design</em> (2022)</p></blockquote><h2>Apa Itu EventStorming?</h2><p>Secara sederhana, <em>EventStorming</em> adalah <strong>cara memetakan alur bisnis dengan menulis peristiwa-peristiwa (event) yang terjadi di domain</strong>, biasanya di atas dinding atau papan besar dengan sticky notes berwarna.</p><p>Kata &#8220;Storming&#8221; di sini menggambarkan proses eksplorasi yang intens dan cepat, bukan diskusi formal yang kaku.<br>Tujuannya bukan langsung &#8220;mendesain arsitektur,&#8221; tapi <strong>mendapatkan pemahaman utuh tentang bagaimana domain bekerja</strong> dari perspektif semua pihak.</p><p><strong>Kata kuncinya:</strong><br>Semua orang bisa berkontribusi, semua ide valid, dan peristiwa (event) adalah bahasa pemersatu.</p><h2>Kenapa EventStorming Penting dalam DDD</h2><p>DDD berfokus pada pemahaman domain.<br>Tapi sering kali, pengetahuan domain tidak tertulis dengan rapi,<br>ia tersebar di kepala orang-orang, dokumen lama, atau asumsi tim.</p><p>EventStorming membantu:</p><ol><li><p><strong>Menyatukan semua stakeholder</strong> di satu ruangan (atau papan digital).</p></li><li><p><strong>Menyingkap logika bisnis tersembunyi</strong> lewat diskusi natural.</p></li><li><p><strong>Membentuk bahasa umum (ubiquitous language)</strong> dari kejadian nyata di domain.</p></li><li><p><strong>Menemukan batas-batas alami (bounded contexts)</strong> berdasarkan pola peristiwa.</p></li></ol><p>Dengan kata lain, EventStorming adalah <strong>cara tercepat untuk &#8220;menemukan domain model&#8221; sebelum menulis satu baris kode pun.</strong></p><h2>Prinsip Utama: Berpikir dalam &#8220;Event&#8221;</h2><p>Daripada bertanya &#8220;entitas apa yang kita butuhkan?&#8221;, facilitator EventStorming akan memulai dengan pertanyaan sederhana: &#8220;Apa saja yang terjadi di domain ini?&#8221;</p><p>Setiap jawaban ditulis dalam format <em>Domain Event</em>, sesuatu yang <em>terjadi</em> di masa lalu dan <em>relevan</em> bagi bisnis.</p><p>Contohnya:</p><ul><li><p><code>OrderPlaced</code></p></li><li><p><code>PaymentReceived</code></p></li><li><p><code>ShipmentSent</code></p></li><li><p><code>CustomerRegistered</code></p></li></ul><p>Setiap event ditempel di dinding dari kiri ke kanan, menggambarkan urutan waktu.</p><p>Dari situ, perlahan terbentuk narasi: bagaimana proses bisnis berjalan, siapa yang terlibat, dan di mana kompleksitas muncul.</p><h2>Warna dan Artefak Utama</h2><p>EventStorming biasanya menggunakan <strong>sticky note dengan warna berbeda</strong>, yang masing-masing mewakili artefak penting dalam domain.</p><ul><li><p>Oranye: Artefak Domain Event</p><ul><li><p>Artinya: Sesuatu yang terjadi di masa lalu</p></li></ul></li><li><p>Biru: Artefak Command</p><ul><li><p>Artinya: Tindakan yang menyebabkan Event</p></li></ul></li><li><p>Kuning: Artefak External System / Policy </p><ul><li><p>Artinya: Sistem atau aturan luar yang memicu tindakan </p></li></ul></li><li><p>Merah muda: Artefak Actor / User</p><ul><li><p>Artinya: Siapa yang menjalankan command</p></li></ul></li><li><p>Hijau: Artefak View / Read Model</p><ul><li><p>Artinya: Informasi yang dilihat pengguna </p></li></ul></li><li><p>Ungu: Artefak Aggregate / Entity</p><ul><li><p>Artinya: Unit logika bisnis yang menangani command</p></li></ul></li></ul><p>Tidak semua workshop butuh semua warna. Fokusnya bukan estetika, tapi pemahaman bersama tentang hubungan sebab-akibat di domain.</p><h2>Fase-Fase EventStorming</h2><p>Menurut Khononov (2022), proses EventStorming umumnya terdiri dari beberapa tahap yang semakin mendalam.</p><h3>1. <strong>Big Picture EventStorming</strong></h3><p>Tujuannya: menemukan <strong>alur bisnis secara keseluruhan</strong>.</p><p>Peserta dari berbagai fungsi (bisnis, teknis, operasional) diminta menuliskan semua <em>event penting</em> dalam proses.<br>Hasilnya sering kali berantakan &#8212; dan itu bagus! Karena di sanalah percakapan penting muncul.</p><p>Contoh:<br>Ketika seseorang menulis <em>PaymentFailed</em>, peserta lain mungkin bertanya,<br>&#8220;Lho, itu terjadi sebelum atau sesudah <em>OrderCancelled</em>?&#8221;<br>Diskusi seperti itu mengungkap <em>aturan bisnis implisit</em> yang selama ini tidak pernah terdokumentasi.</p><h3>2. <strong>Process-Level EventStorming</strong></h3><p>Setelah gambaran besar terbentuk, tim bisa memperdalam satu proses spesifik, misalnya <em>Order Fulfillment</em>.<br>Di tahap ini, kita mulai melihat <em>command</em>, <em>actor</em>, dan <em>aggregate</em> yang terlibat.</p><p>Misalnya:</p><ul><li><p>Command: <code>PlaceOrder</code></p></li><li><p>Aggregate: <code>Order</code></p></li><li><p>Event: <code>OrderPlaced</code></p></li><li><p>Actor: <code>Customer</code></p></li></ul><p>Dan mungkin muncul insight seperti: &#8220;Kalau stok tidak cukup, event <code>OrderRejected</code> bisa muncul.&#8221;</p><p>Dari sini, kita mulai melihat pola <em>bounded context</em> dan logika bisnis yang nyata.</p><h3>3. <strong>Design-Level EventStorming</strong></h3><p>Tahap ini paling teknis, dilakukan biasanya oleh engineer dan arsitek sistem.<br>Di sini, event dan command diterjemahkan ke dalam komponen desain seperti:</p><ul><li><p><strong>Aggregate</strong> (logika domain utama)</p></li><li><p><strong>Saga / Process Manager</strong> (mengatur alur lintas aggregate)</p></li><li><p><strong>Read Model / Projection</strong> (untuk query data)</p></li><li><p><strong>External System Integration</strong> (pihak ketiga)</p></li></ul><p>Contoh dalam Rust (sketsa sederhana):</p><pre><code><code>struct Order {
    id: u64,
    status: OrderStatus,
}

impl Order {
    fn place(&amp;mut self) -&gt; OrderPlaced {
        self.status = OrderStatus::Placed;
        OrderPlaced { order_id: self.id }
    }
}

struct OrderPlaced {
    order_id: u64,
}</code></code></pre><p>Dari event yang awalnya hanya sticky note oranye, kini kita bisa melihat <em>kode yang berbicara dengan bahasa bisnis yang sama.</em></p><h2>Temuan yang Sering Muncul dari EventStorming</h2><p>EventStorming bukan hanya latihan pemetaan, ini adalah <em>alat diagnosis organisasi.</em></p><p>Beberapa temuan umum:</p><ul><li><p><strong>Ambiguitas istilah:</strong> orang berbeda menyebut hal yang sama dengan istilah berbeda.</p></li><li><p><strong>Kekosongan tanggung jawab:</strong> ada event tanpa command yang jelas.</p></li><li><p><strong>Masalah komunikasi antar tim:</strong> event muncul di satu context tapi dikonsumsi di context lain tanpa koordinasi.</p></li><li><p><strong>Aturan bisnis tersembunyi:</strong> &#8220;oh ternyata itu otomatis dibatalkan kalau lewat 24 jam!&#8221;</p></li></ul><p>Setiap temuan seperti ini adalah <em>pengetahuan domain baru</em>, dan itulah nilai utama EventStorming.</p><h2>Nilai Praktis bagi Engineer</h2><p>Bagi engineer, EventStorming terasa seperti cheat code untuk memahami domain baru.</p><p>Alih-alih membaca dokumen setebal 50 halaman atau menebak-nebak lewat backlog Jira, kita bisa melihat <strong>alur bisnis hidup</strong> di depan mata.</p><p>Kita tahu:</p><ul><li><p>Event apa yang penting,</p></li><li><p>Siapa yang memicunya,</p></li><li><p>Kondisi apa yang menyebabkannya gagal,</p></li><li><p>Dan bagaimana satu bounded context memengaruhi yang lain.</p></li></ul><p>Setelah workshop, kode yang kita tulis jadi jauh lebih dekat dengan cara bisnis berpikir.</p><h2>EventStorming dan Bounded Context</h2><p>Salah satu hasil alami dari EventStorming adalah munculnya <strong>pola pemisahan alami</strong> antar bagian domain.</p><p>Ketika papan mulai &#8220;penuh&#8221;, kita bisa mulai melihat klaster event yang saling erat, itulah kandidat <strong>bounded context.</strong></p><blockquote><p>&#8220;Bounded contexts don&#8217;t come from architects &#8212; they emerge from understanding.&#8221; &#8212; <em>Vlad Khononov, 2022</em></p></blockquote><p>Bounded context yang ditemukan dengan cara ini jauh lebih realistis, karena tumbuh dari percakapan lintas tim, bukan dari diagram PowerPoint.</p><h2>Kapan Menggunakan EventStorming</h2><p>Gunakan EventStorming ketika:</p><ul><li><p>Tim baru akan memulai proyek besar,</p></li><li><p>Domain masih kabur atau penuh asumsi,</p></li><li><p>Ada ketegangan antar tim atau model yang tidak selaras,</p></li><li><p>Atau ketika organisasi ingin membangun <em>ubiquitous language.</em></p></li></ul><p>Sebaliknya, untuk sistem kecil atau domain yang sudah stabil, EventStorming mungkin berlebihan, cukup gunakan diagram alur sederhana.</p><div><hr></div><h2>Tips Memfasilitasi EventStorming</h2><ol><li><p><strong>Mulai dari event, bukan dari entitas.</strong><br>Jangan tanya &#8220;objek apa yang kita punya?&#8221;, tapi &#8220;apa yang terjadi?&#8221;</p></li><li><p><strong>Dorong partisipasi semua pihak.</strong><br>Tidak ada jawaban salah. Justru ketidaksepakatan itu bahan diskusi.</p></li><li><p><strong>Gunakan papan besar dan sticky notes.</strong><br>Visualisasi itu penting, otak manusia lebih cepat memahami pola.</p></li><li><p><strong>Beri ruang untuk chaos.</strong><br>Di awal pasti berantakan, tapi dari kekacauan itu muncul struktur.</p></li><li><p><strong>Akhiri dengan insight, bukan diagram sempurna.</strong><br>Tujuan utama: pemahaman bersama, bukan artefak yang rapi.</p></li></ol><h2>Ringkasnya, ini adalah Percakapan yang Mengubah Cara Berpikir</h2><p>EventStorming bukan alat teknis, ia alat manusiawi.<br>Ia mengubah cara tim memahami domain dari <em>debat tentang solusi</em> menjadi <em>percakapan tentang kejadian nyata.</em></p><p>Setelah workshop, semua orang, baik engineer, PM, maupun ahli bisnis, akan mulai berbicara dengan bahasa yang sama. Dan itu, dalam semangat DDD, adalah kemenangan terbesar.</p><blockquote><p>&#8220;Software design is a communication game. EventStorming makes the rules visible.&#8221; &#8212; Vlad Khononov, <em>Learning Domain-Driven Design</em> (2022)</p></blockquote><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Evolving Design Decisions, Menuju Desain yang Tumbuh Bersama Pengetahuan]]></title><description><![CDATA[Di artikel-artikel sebelumnya, kita belajar bahwa domain model itu hidup.]]></description><link>https://www.0-1.my.id/p/evolving-design-decisions-menuju</link><guid isPermaLink="false">https://www.0-1.my.id/p/evolving-design-decisions-menuju</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Mon, 20 Oct 2025 16:43:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><p>Di artikel-artikel sebelumnya, kita belajar bahwa domain model itu hidup. Ia berkembang seiring perubahan bisnis dan pemahaman tim.</p><p>Tapi bukan hanya <strong>model domain</strong> yang perlu berevolusi. Keputusan desain dan arsitektur pun harus mengikuti &#8212; karena yang kita tahu hari ini <em>belum tentu benar besok.</em></p><blockquote><p>&#8220;Good design decisions are not permanent. They are just good for now.&#8221; &#8212; Vlad Khononov, <em>Learning Domain-Driven Design</em> (2022)</p></blockquote><p>Inilah inti dari bab ini: <strong>desain yang baik adalah desain yang bisa tumbuh bersama waktu dan pengetahuan.</strong></p><h2>Mengapa Desain Harus Berevolusi</h2><p>Kita sering berpikir desain itu seperti kontrak: sekali diputuskan, harus dijaga mati-matian. Padahal, dunia bisnis bergerak cepat. Aturan baru muncul, model berubah, skala sistem bertambah, bahkan teknologi pun bergeser.</p><p>Keputusan yang dulu tepat bisa jadi tidak relevan hari ini. Maka, desain yang sehat bukan yang &#8220;tidak berubah&#8221;, tapi yang <strong>mudah berubah tanpa menyakitkan.</strong></p><h3>Contoh sederhana:</h3><p>Awalnya sistem pembayaran hanya mendukung <em>cash</em> dan <em>transfer bank</em>, jadi cukup enum sederhana:</p><pre><code>enum PaymentMethod {
    Cash,
    BankTransfer,
}</code></pre><p>Tiga bulan kemudian, muncul kebutuhan baru: <em>QRIS, kartu kredit, e-wallet,</em> bahkan <em>voucher internal.</em></p><p>Kalau arsitektur kita kaku, perubahan kecil seperti ini bisa menyentuh banyak tempat sekaligus &#8212; error di mana-mana. Tapi kalau modelnya fleksibel, kita cukup menambah varian baru tanpa mengubah bagian lain:</p><pre><code>enum PaymentMethod {
    Cash,
    BankTransfer,
    CreditCard(String),
    EWallet(String),
    Voucher(String),
}</code></pre><p>Desain yang bisa berevolusi seperti ini menunjukkan bahwa arsitektur kita <strong>adaptif terhadap perubahan pengetahuan.</strong></p><h2>Desain Itu Proses Pembelajaran</h2><p>Khononov menjelaskan bahwa desain bukan hasil akhir dari perencanaan panjang, melainkan <strong>hasil iterasi dari proses belajar.</strong></p><p>Setiap diskusi dengan domain expert, setiap bug, dan setiap perilaku pengguna membawa <em>insight baru</em> tentang domain. Dengan setiap wawasan baru itu, kita perlu memperbarui model, dan kadang mengubah keputusan desain sebelumnya.</p><blockquote><p>&#8220;Design is learning, and learning means change.&#8221; &#8212; <em>Vlad Khononov, 2022</em></p></blockquote><p>Desain DDD bukan soal menemukan struktur paling indah, tapi soal menemukan struktur <strong>yang paling menggambarkan kenyataan saat ini.</strong></p><h2>Perbedaan Antara Desain yang Kaku dan Desain yang Berevolusi</h2><p>Aspek Desain Kaku</p><ul><li><p>Fokus: Kepastian</p></li><li><p>Tujuan: Menghindari perubahan </p></li><li><p>Strategi: Rencana besar di awal</p></li><li><p>Efek samping: Cepat usang</p></li><li><p>Pola pikir: &#8220;Sudah benar dari awal&#8221;</p></li></ul><p>Aspek Desain Berevolusi </p><ul><li><p>Fokus: Adaptasi</p></li><li><p>Tujuan: Menyambut perubahan</p></li><li><p>Strategi: Iterasi kecil dan terus-menerus</p></li><li><p>Efek samping: Selalu relevan</p></li><li><p>Pola pikir: &#8220;Kita belajar setiap hari&#8221;</p></li></ul><p>Desain kaku lahir dari ketakutan akan salah. Desain yang berevolusi lahir dari <strong>rasa ingin tahu dan keberanian untuk mengoreksi diri.</strong></p><h2>Teknik: Menunda Keputusan Secara Sengaja</h2><p>Salah satu prinsip desain penting yang diperkenalkan dalam buku ini adalah <strong>delaying decisions</strong> &#8212; <em>menunda keputusan desain sampai kita punya cukup informasi.</em></p><p>Istilah ini sering disebut <em>Last Responsible Moment</em>:</p><blockquote><p>&#8220;Ambil keputusan selambat mungkin, tapi tidak sampai terlambat.&#8221;</p></blockquote><p>Artinya, jangan buat keputusan desain besar saat masih banyak ketidakpastian. Ambil keputusan yang paling ringan dulu, yang bisa dengan mudah diubah nanti.</p><p><strong>Contoh:</strong> Daripada langsung memilih pattern besar seperti <em>CQRS + Event Sourcing</em>, mulailah dengan <em>Layered Architecture</em>. Begitu sistem makin kompleks dan kebutuhan audit muncul, kamu bisa evolusikan jadi <em>CQRS.</em></p><p>Atau, daripada menentukan teknologi database di awal, abstraksikan akses datanya lewat <em>Repository Interface</em>. Kalau nanti migrasi dari SQLite ke PostgreSQL, domain model tetap aman.</p><pre><code>trait OrderRepository {
    fn save(&amp;self, order: &amp;Order);
    fn find_by_id(&amp;self, id: u64) -&gt; Option&lt;Order&gt;;
}</code></pre><p>Keputusan kecil ini menjaga fleksibilitas tanpa mengorbankan arah.</p><h2>Prinsip: Keputusan Harus Proporsional dengan Pengetahuan</h2><p>Khononov menyebut bahwa setiap keputusan desain adalah <strong>pertukaran antara pengetahuan dan risiko.</strong></p><ul><li><p>Semakin sedikit pengetahuan yang kita punya, semakin besar risiko salah mengambil keputusan.</p></li><li><p>Maka, keputusan harus <strong>sepadan dengan tingkat pemahaman kita saat itu.</strong></p></li></ul><p>Jangan terlalu dini membuat keputusan besar atas asumsi mentah. Sebaliknya, jangan juga terlalu lama menunda hingga tim kehilangan arah.</p><p>Prinsip ini mendorong pola pikir <em>evolutionary architecture</em>, arsitektur yang tidak selesai di atas kertas, melainkan terus dibentuk dari pengalaman nyata.</p><h2>Tanda-tanda Kamu Butuh Mengubah Desain</h2><ol><li><p><strong>Banyak &#8220;if&#8221; di mana-mana.</strong> Itu tanda model sudah tidak mencerminkan domain lagi.</p></li><li><p><strong>Aturan bisnis sulit dijelaskan lewat kode.</strong> Mungkin modelmu sudah terlalu teknis.</p></li><li><p><strong>Istilah di kode dan di meeting mulai berbeda.</strong> Bahasa umum (ubiquitous language) sudah melenceng.</p></li><li><p><strong>Perubahan kecil memengaruhi banyak bagian.</strong> Tanda struktur sistem sudah terlalu rapuh.</p></li><li><p><strong>Tim mulai takut refactor.</strong> Ini gejala klasik desain yang membatu.</p></li></ol><p>Kalau ini mulai terasa, jangan panik. Itu bukan kegagalan, itu sinyal bahwa kamu sudah belajar sesuatu yang baru, dan saatnya model ikut berubah.</p><h2>Pendekatan: Continuous Refinement</h2><p>Evolusi desain tidak butuh revolusi besar setiap enam bulan. Cukup lakukan <strong>refinement kecil</strong> secara terus-menerus.</p><p>Langkah sederhananya:</p><ol><li><p><strong>Identifikasi pain point.</strong> Misalnya entitas tertentu jadi terlalu besar.</p></li><li><p><strong>Diskusikan dengan domain expert.</strong> Apakah ada istilah atau proses baru?</p></li><li><p><strong>Perbaiki model.</strong> Pecah aggregate, ubah value object, atau tambahkan event.</p></li><li><p><strong>Uji asumsi.</strong> Pastikan perubahan benar-benar memudahkan pemahaman bisnis.</p></li><li><p><strong>Rilis kecil.</strong> Jangan tunda sampai &#8220;semua siap&#8221;.</p></li></ol><p>Refinement yang berkelanjutan jauh lebih sehat daripada <em>refactor masif</em> yang menakutkan.</p><h2>Mengelola Tekanan dan Trade-off</h2><p>Kadang manajemen ingin keputusan cepat: &#8220;Pilih framework sekarang!&#8221; Atau: &#8220;Kita harus finalkan model minggu ini!&#8221;</p><p>Dalam konteks DDD, tugas engineer bukan hanya membuat kode, tapi juga <strong>melindungi proses belajar.</strong> Artinya, jangan biarkan tekanan waktu membunuh kesempatan untuk memahami domain dengan benar.</p><p>Kita boleh mengambil keputusan pragmatis sementara &#8212; asal sadar bahwa itu keputusan <em>sementara</em>, dan siap diperbaiki nanti.</p><blockquote><p>&#8220;Every temporary decision is a debt &#8212; pay it back when knowledge grows.&#8221; &#8212; <em>Vlad Khononov, 2022</em></p></blockquote><h2>Kode Sebagai Dokumentasi Evolusi</h2><p>Model domain yang baik seharusnya menjadi dokumentasi hidup tentang cara bisnis bekerja <em>saat ini</em>. Jangan takut kalau modelmu berbeda dari enam bulan lalu &#8212; itu tanda kamu belajar.</p><p>Gunakan git commit, test case, dan domain event sebagai <em>jejak sejarah evolusi</em> keputusan desain.</p><p>Contoh:</p><pre><code>// Sebelum
enum DeliveryStatus {
    Pending,
    Delivered,
}

// Setelah memahami proses retur
enum DeliveryStatus {
    Pending,
    Delivered,
    Returned(String), // alasan pengembalian
}</code></pre><p>Setiap perubahan semacam ini adalah bukti bahwa sistemmu menyesuaikan diri dengan realitas bisnis, bukan sebaliknya.</p><h2>Ringkasan mengenai Desain yang Tumbuh Bersama Pengetahuan</h2><p>DDD bukan hanya tentang membuat model domain, tapi tentang <strong>membangun sistem yang terus belajar</strong>.</p><p>Desain yang baik tidak kaku. Ia tumbuh bersama tim, bersama bisnis, dan bersama waktu.</p><p>Prinsip utamanya sederhana:</p><ul><li><p>Jangan kunci keputusan sebelum waktunya.</p></li><li><p>Jangan takut mengubah arah saat pengetahuan bertambah.</p></li><li><p>Dan yang paling penting: pastikan perubahan desain selalu mengikuti <strong>makna bisnis</strong>, bukan sekadar selera teknis.</p></li></ul><blockquote><p>&#8220;The best design is the one that fits the current understanding of the domain &#8212; and is ready to change when that understanding grows.&#8221; &#8212; Vlad Khononov, <em>Learning Domain-Driven Design</em> (2022)</p></blockquote><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Design Heuristics Dimana Saat Harus Realistis dengan Domain-Driven Design]]></title><description><![CDATA[Jika di pembahasan sebelumnya kita belajar tentang semua elemen keren di DDD &#8212; dari bounded context, aggregate, sampai communication patterns, mungkin kini muncul pertanyaan praktis:]]></description><link>https://www.0-1.my.id/p/design-heuristics-dimana-saat-harus</link><guid isPermaLink="false">https://www.0-1.my.id/p/design-heuristics-dimana-saat-harus</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Sun, 19 Oct 2025 15:57:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><p>Jika di pembahasan sebelumnya kita belajar tentang semua elemen keren di DDD &#8212; dari <em>bounded context</em>, <em>aggregate</em>, sampai <em>communication patterns</em>, mungkin kini muncul pertanyaan praktis:</p><blockquote><p>&#8220;Kapan sih kita <em>benar-benar perlu</em> pakai DDD? Apakah semua bagian sistem harus pakai domain model penuh?&#8221;</p></blockquote><p>Jawabannya singkat tapi penting: <strong>tidak selalu.</strong> Dan di sinilah kita mulai masuk ke inti bab ini: <em>design heuristics</em> &#8212; kumpulan prinsip berpikir agar kita tahu <strong>seberapa dalam menerapkan DDD</strong>, dan kapan harus <em>berhenti sebelum berlebihan.</em></p><h2>Heuristik: Bukan Aturan, Tapi Kompas</h2><p>Kata <em>heuristic</em> berarti &#8220;petunjuk praktis untuk membuat keputusan yang baik dalam kondisi tidak pasti.&#8221; Dalam konteks DDD, heuristik membantu kita memilih pendekatan desain yang <strong>seimbang antara nilai bisnis dan biaya implementasi.</strong></p><p>DDD bukan dogma. Ia bukan tentang &#8220;semua harus punya domain model lengkap.&#8221; Ia adalah <em>cara berpikir</em> agar sistem kita mencerminkan realitas bisnis <strong>secukupnya</strong> &#8212; tidak kurang, tapi juga tidak berlebihan.</p><blockquote><p>&#8220;Heuristics are not rules &#8212; they are good advice for most situations.&#8221; &#8212; Vlad Khononov, <em>Learning Domain-Driven Design</em> (2022)</p></blockquote><h2>Prinsip Dasar 1: Gunakan Kompleksitas dengan Bijak</h2><p>DDD diciptakan untuk <strong>domain yang kompleks secara bisnis</strong>, bukan sekadar teknis. Kalau sistem kamu hanya memindahkan data antar tabel tanpa aturan khusus, maka DDD penuh justru akan memperlambat tim.</p><p>Bayangkan sistem sederhana seperti <em>user management</em>, <em>login</em>, atau <em>report generator</em>. Fungsi-fungsi itu bisa selesai dengan cepat pakai pola <em>Transaction Script</em> atau <em>Active Record</em>.</p><p>Tapi ketika mulai muncul hal-hal seperti:</p><ul><li><p>&#8220;kalau pengguna premium, logika perhitungan komisinya berbeda,&#8221;</p></li><li><p>&#8220;status langganan berubah otomatis tergantung perilaku,&#8221;</p></li><li><p>&#8220;ada peraturan bisnis yang saling bertabrakan,&#8221;</p></li></ul><p>maka itu tanda domain mulai <strong>kompleks</strong>. Dan di situlah <em>Domain Model</em> menjadi alat yang tepat.</p><blockquote><p>Heuristik #1: <strong>Semakin kompleks logika bisnis, semakin layak DDD digunakan.</strong></p></blockquote><h2>Prinsip Dasar 2: Model Harus Menghasilkan Nilai Bisnis</h2><p>Kadang engineer terjebak membangun model yang indah tapi tidak berdampak. DDD tidak mengejar keindahan teknis, tapi <strong>kejelasan makna bisnis.</strong></p><p>Sebelum membuat entitas, aggregate, atau event, selalu tanyakan:</p><blockquote><p>&#8220;Apakah model ini membantu tim memahami atau memecahkan masalah bisnis?&#8221;</p></blockquote><p>Kalau jawabannya tidak, mungkin kamu sedang membuat <em>arsitektur demi arsitektur.</em></p><p><strong>Contoh sederhana:</strong></p><p>Katakan kita sedang membangun sistem pembelian tiket.</p><p>Model yang bermanfaat:</p><pre><code>struct Ticket {
    id: u64,
    status: TicketStatus,
}

enum TicketStatus {
    Reserved,
    Paid,
    Cancelled,
}
</code></pre><p>Model yang &#8220;terlalu DDD tapi tidak berguna&#8221;:</p><pre><code>struct TicketAggregate {
    id: u64,
    ticket_entity: TicketEntity,
    ticket_state: TicketState,
    ticket_repository: Arc&lt;dyn Repository&gt;,
}</code></pre><p>Yang satu berbicara tentang <em>tiket dan statusnya</em>, yang lain berbicara tentang <em>framework dan istilah arsitektur</em>. Model yang baik selalu dekat dengan <em>bahasa domain</em>, bukan dengan jargon teknis.</p><blockquote><p>Heuristik #2: <strong>Model yang baik berbicara dalam bahasa bisnis, bukan bahasa framework.</strong></p></blockquote><h2>Prinsip Dasar 3: Pisahkan Domain yang Penting dari yang Biasa</h2><p>Tidak semua bagian sistem punya nilai strategis yang sama. Beberapa bagian adalah <strong>core domain</strong> &#8212; di sanalah keunggulan kompetitif bisnis berada. Yang lain hanyalah <strong>supporting</strong> atau bahkan <strong>generic subdomain</strong>.</p><p>Gunakan tenaga DDD di tempat yang paling berdampak.</p><p>Jenis Domain Fokus Pendekatan <strong>Core Domain</strong> Inovasi, keunggulan kompetitif Domain Model penuh (DDD taktis lengkap) <strong>Supporting Domain</strong> Mendukung operasi Pola sederhana seperti Active Record <strong>Generic Domain</strong> Umum untuk semua bisnis Gunakan library atau SaaS</p><p>Contoh nyata:</p><ul><li><p>Core Domain: algoritme rekomendasi di e-commerce.</p></li><li><p>Supporting Domain: sistem pembayaran internal.</p></li><li><p>Generic Domain: login, autentikasi, logging.</p></li></ul><blockquote><p>Heuristik #3: <strong>Investasikan DDD di tempat yang memberi nilai strategis terbesar.</strong></p></blockquote><h2>Prinsip Dasar 4: Jangan Jadikan DDD Sebagai Target, Tapi Sebagai Alat</h2><p>Engineer yang baru mengenal DDD sering terlalu semangat: semua hal dibuat Aggregate, semua entitas punya Repository, semua event dicatat.</p><p>Padahal DDD bukan checklist, melainkan <em>toolbox.</em> Gunakan hanya alat yang relevan untuk masalah di depan mata.</p><blockquote><p>Heuristik #4: <strong>DDD bukan tujuan akhir, melainkan sarana untuk memahami dan menyelesaikan kompleksitas.</strong></p></blockquote><p>Ciri bahwa kamu terlalu jauh: model makin abstrak, tapi semua orang di tim justru makin bingung. Ciri bahwa kamu tepat: model membantu tim berdebat tentang <em>bisnis</em>, bukan tentang kode.</p><h2>Prinsip Dasar 5: Evolve, Don&#8217;t Freeze</h2><p>Model domain bukan kontrak permanen. Ia seharusnya <strong>tumbuh bersama pemahaman bisnis.</strong></p><p>Ketika aturan bisnis berubah, biarkan model ikut berevolusi. Jangan terjebak pada rasa takut &#8220;merusak arsitektur yang sudah rapi.&#8221;</p><blockquote><p>Heuristik #5: <strong>Model yang hidup lebih berguna daripada model yang sempurna.</strong></p></blockquote><p>Misalnya, awalnya kamu hanya punya dua status pembayaran: <code>Pending</code> dan <code>Paid</code>. Lalu muncul kebutuhan &#8220;Refunded&#8221;. Tambahkan saja, meskipun awalnya belum semua proses mendukung.</p><pre><code>enum PaymentStatus {
    Pending,
    Paid,
    Refunded,
}</code></pre><p>Model berkembang, pengetahuan bertambah &#8212; persis seperti bisnisnya.</p><h2>Prinsip Dasar 6: Biarkan Bounded Context Mengatur Diri Sendiri</h2><p>Ketika sistem tumbuh besar, mudah tergoda membuat &#8220;model universal&#8221; yang bisa dipakai semua tim. Padahal itu berbahaya.</p><p>Model yang terlalu umum akan kehilangan makna di setiap konteks. Lebih baik setiap bounded context punya modelnya sendiri &#8212; walau istilahnya sama tapi maknanya berbeda.</p><p>Contoh nyata:</p><ul><li><p>Di <em>Sales Context</em>, &#8220;Customer&#8221; berarti orang yang membeli produk.</p></li><li><p>Di <em>Support Context</em>, &#8220;Customer&#8221; berarti orang yang sedang punya tiket bantuan aktif.</p></li></ul><p>Keduanya sah. Yang penting, mereka <strong>tidak saling memaksakan makna.</strong></p><blockquote><p>Heuristik #6: <strong>Hargai otonomi bounded context &#8212; lebih baik model ganda yang jelas daripada model tunggal yang membingungkan.</strong></p></blockquote><h2>Prinsip Dasar 7: Arsitektur Ada untuk Melayani Domain</h2><p>Jangan biarkan framework atau pola arsitektur membatasi desain domain. Ingat bahwa <em>model domain adalah pusat dari sistem,</em> bukan lapisan di bawah framework.</p><p>Kalau framework ORM memaksa semua entitas harus punya <code>id</code> integer, padahal di domain kamu lebih masuk akal pakai <code>code</code> sebagai identitas, maka ubahlah framework, bukan domainnya.</p><pre><code>struct Product {
    code: String, // Bukan ID auto-increment
    name: String,
}</code></pre><blockquote><p>Heuristik #7: <strong>Framework boleh diganti, domain tidak.</strong></p></blockquote><h2>Prinsip Dasar 8: Ubiquitous Language Adalah Tes Terbaik</h2><p>Kalau kamu ingin tahu seberapa sehat model domainmu, lihat bagaimana tim berbicara tentang bisnisnya.</p><p>Kalau engineer, PM, dan ahli domain bisa bicara tentang &#8220;Order&#8221;, &#8220;Refund&#8221;, dan &#8220;Shipment&#8221; tanpa kebingungan &#8212; artinya modelmu sudah bekerja. Kalau tiap meeting diwarnai &#8220;maksud kamu order yang di database atau order yang di API?&#8221;, artinya modelmu butuh perbaikan.</p><blockquote><p>Heuristik #8: <strong>Jika bahasa di kode dan di percakapan bisnis sama, kamu sedang menerapkan DDD dengan benar.</strong></p></blockquote><h2>Ringkasnya, Pragmatism is the Real DDD</h2><p>DDD bukan sekadar teori elegan untuk sistem besar. Ia adalah <em>cara berpikir</em> untuk memastikan bahwa software yang kita bangun <strong>selalu berbicara tentang bisnis, bukan sekadar data.</strong></p><p>Namun, setiap engineer yang matang tahu:</p><ul><li><p>Tidak semua sistem butuh domain model penuh,</p></li><li><p>Tidak semua konteks perlu aggregate,</p></li><li><p>Dan tidak semua tim siap hidup dengan kompleksitas DDD sejak hari pertama.</p></li></ul><p>Gunakan <em>heuristics</em> sebagai kompas, bukan peta mutlak. Tugas kita bukan membuat DDD sempurna, tapi membuat sistem yang <strong>bermakna, terpelihara, dan berumur panjang.</strong></p><blockquote><p>&#8220;The goal of DDD is not to apply all its patterns, but to use the right ones, in the right context, for the right reasons.&#8221; &#8212; Vlad Khononov, <em>Learning Domain-Driven Design</em> (2022)</p></blockquote><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Communication Patterns untuk Menyatukan Bahasa di Dunia yang Berbeda]]></title><description><![CDATA[Setelah kita membangun domain model yang kuat dan melindunginya dengan arsitektur yang rapi, kini muncul pertanyaan baru:]]></description><link>https://www.0-1.my.id/p/communication-patterns-untuk-menyatukan</link><guid isPermaLink="false">https://www.0-1.my.id/p/communication-patterns-untuk-menyatukan</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Sat, 18 Oct 2025 16:54:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Setelah kita membangun domain model yang kuat dan melindunginya dengan arsitektur yang rapi, kini muncul pertanyaan baru:</p><blockquote><p>&#8220;Bagaimana kalau model kita harus berkomunikasi dengan model dari tim lain?&#8221;</p></blockquote><p>Dalam organisasi besar, setiap tim biasanya bekerja di <strong>bounded context</strong> yang berbeda, masing-masing dengan bahasa, istilah, dan prioritasnya sendiri. Tantangannya adalah bagaimana <em>bounded context</em> ini bisa saling berbicara tanpa saling merusak model satu sama lain.</p><p>Di sinilah <strong>communication patterns</strong> dalam DDD berperan. Ia membantu kita <strong>menjembatani dunia yang berbeda</strong>, agar integrasi antar sistem tidak membuat domain model kita rusak atau kehilangan makna.</p><h2>Mengapa Komunikasi Itu Rumit</h2><p>Komunikasi antara bounded context bukan sekadar &#8220;kirim data lewat API&#8221;. Masalah sebenarnya bukan di teknologinya, tapi di <strong>perbedaan makna</strong>.</p><p>Bayangkan dua tim:</p><ul><li><p><strong>Tim Sales</strong> menggunakan istilah &#8220;Customer&#8221; untuk siapa pun yang pernah melakukan transaksi.</p></li><li><p><strong>Tim Support</strong> menyebut &#8220;Customer&#8221; hanya untuk pengguna aktif yang punya kontrak dukungan.</p></li></ul><p>Ketika kedua sistem bertukar data tentang <em>Customer</em>, data itu mungkin valid secara teknis, tapi salah makna secara bisnis. Itulah mengapa DDD menekankan bahwa komunikasi antar bounded context harus punya <strong>kontrak yang jelas</strong>, baik secara teknis maupun semantik.</p><h2>Hubungan Upstream dan Downstream</h2><p>Dalam DDD, hubungan antar bounded context digambarkan seperti aliran sungai:</p><ul><li><p><strong>Upstream</strong> &#8594; konteks yang <em>mengirim data atau keputusan</em>,</p></li><li><p><strong>Downstream</strong> &#8594; konteks yang <em>menerima dan menyesuaikan diri</em> dengan upstream.</p></li></ul><p>Hubungan ini penting karena menentukan <strong>arah pengaruh</strong>, siapa yang memengaruhi siapa.</p><h3>Contoh sederhana</h3><p>Misalnya ada dua tim:</p><ul><li><p><strong>Team Orders</strong> mengelola pemesanan pelanggan.</p></li><li><p><strong>Team Shipping</strong> mengurus pengiriman barang.</p></li></ul><p>Ketika pesanan dikonfirmasi, <strong>Orders</strong> mengirim event ke <strong>Shipping</strong> untuk memulai proses pengiriman.</p><pre><code>Orders (upstream) ---&gt; Shipping (downstream)</code></pre><p>Jika tim Orders mengubah format event tanpa koordinasi, tim Shipping akan terkena dampaknya. Jadi, downstream selalu <strong>lebih sensitif terhadap perubahan</strong> upstream. Inilah mengapa kita perlu <em>communication pattern</em> yang tepat, untuk mengatur dinamika semacam ini.</p><h2>Pola-Pola Komunikasi antar Context</h2><p>DDD memperkenalkan beberapa pola utama untuk menggambarkan cara bounded context saling berinteraksi. Masing-masing mencerminkan tingkat kolaborasi dan kekuasaan yang berbeda.</p><h3>1. Partnership</h3><p>Dalam <strong>Partnership</strong>, dua tim bekerja sangat erat, mereka berbagi tujuan dan menegosiasikan setiap perubahan bersama.</p><p>Mereka bisa dianggap &#8220;sekutu&#8221; yang membangun solusi bersama, dengan jadwal rilis dan kontrak yang disepakati dua arah.</p><blockquote><p>&#8220;Changes are negotiated together.&#8221; &#8212; Vlad Khononov (2022)</p></blockquote><p>Pola ini cocok bila dua sistem bergantung kuat satu sama lain dan punya siklus hidup yang sinkron. Misalnya antara tim &#8220;Billing&#8221; dan &#8220;Subscription&#8221; di platform SaaS.</p><p>Tantangannya: koordinasi butuh komunikasi intensif, jadi lebih cocok untuk organisasi kecil atau modul yang sangat terintegrasi.</p><h3>2. Customer&#8211;Supplier</h3><p>Dalam pola ini, <strong>supplier</strong> menyediakan data atau layanan yang digunakan oleh <strong>customer</strong>. Supplier biasanya memiliki kekuasaan lebih besar karena menentukan struktur data dan kontrak API.</p><blockquote><p>&#8220;When the supplier has the power.&#8221; &#8212; <em>Khononov (2022)</em></p></blockquote><p>Jika tim supplier berubah, tim customer harus menyesuaikan diri.</p><p>Untuk melindungi domain model-nya sendiri, tim customer bisa membuat <strong>Anticorruption Layer (ACL)</strong>, lapisan penerjemah antara model supplier dan model internalnya.</p><p><strong>Contoh:</strong></p><pre><code>// Model dari supplier (mungkin dari API eksternal)
struct ExternalOrder {
    order_id: String,
    value: f64,
}

// Model internal di domain kita
struct InternalOrder {
    id: u64,
    total: f64,
}

// Anticorruption Layer (penerjemah)
impl From&lt;ExternalOrder&gt; for InternalOrder {
    fn from(eo: ExternalOrder) -&gt; Self {
        InternalOrder { id: eo.order_id.parse().unwrap(), total: eo.value }
    }
}</code></pre><p>ACL memastikan model domain kita <strong>tidak terkontaminasi</strong> oleh model pihak lain. Domain kita tetap bersih, meskipun harus berinteraksi dengan dunia luar.</p><h3>3. Conformist</h3><p>Kadang, tim downstream <strong>tidak punya pilihan</strong> selain menyesuaikan diri sepenuhnya dengan upstream, baik format data, struktur model, maupun jadwal rilisnya.</p><p>Inilah pola <strong>Conformist</strong>. Pola ini sering muncul saat:</p><ul><li><p>Sistem upstream adalah produk eksternal atau pihak ketiga.</p></li><li><p>Atau tim downstream terlalu kecil untuk memengaruhi perubahan di upstream.</p></li></ul><p>Misalnya, sistem kita membaca data dari layanan pemerintah atau vendor eksternal &#8212; mau tidak mau, kita harus &#8220;conform&#8221;.</p><p>Walau kurang ideal, <em>Conformist</em> tetap bisa dikelola dengan baik asalkan dokumentasi kontraknya jelas.</p><h3>4. Open Host Service dan Published Language</h3><p>Kadang, satu bounded context melayani banyak konsumen. Daripada menyesuaikan diri dengan masing-masing, lebih efisien kalau dia menyediakan satu <strong>antarmuka publik yang stabil</strong>.</p><p>Pola ini disebut <strong>Open Host Service</strong>, dan bahasa komunikasinya disebut <strong>Published Language</strong>.</p><ul><li><p><em>Open Host Service</em> &#8594; API publik yang terbuka untuk konsumsi banyak sistem.</p></li><li><p><em>Published Language</em> &#8594; format data dan istilah yang disepakati (misalnya JSON schema, gRPC proto, atau message contract).</p></li></ul><p>Contoh sederhana:</p><pre><code>// Published Language: kontrak publik API
#[derive(serde::Serialize)]
struct OrderDto {
    order_id: u64,
    total: f64,
    status: String,
}</code></pre><p>Dengan <em>Published Language</em>, upstream tidak perlu menyesuaikan setiap downstream. Semua berkomunikasi lewat kontrak publik yang stabil, mirip seperti &#8220;bahasa diplomatik&#8221; antar negara.</p><h3>5. Separate Ways</h3><p>Tidak semua bounded context harus saling bicara. Kadang, lebih baik mereka <strong>berjalan sendiri-sendiri</strong> dengan domain model masing-masing.</p><p>Pola <strong>Separate Ways</strong> digunakan saat:</p><ul><li><p>Integrasi terlalu rumit dibanding manfaatnya,</p></li><li><p>Atau dua sistem hanya berbagi data secara sinkronisasi batch, bukan real-time.</p></li></ul><blockquote><p>&#8220;Sometimes the cost of integration outweighs the benefits.&#8221; &#8212; <em>Khononov (2022)</em></p></blockquote><p>Dalam praktiknya, ini justru bisa lebih efisien: tim jadi bebas bereksperimen dan merilis fitur tanpa bergantung satu sama lain.</p><h2>Menggunakan Context Map</h2><p>Untuk memvisualisasikan hubungan antar bounded context dan pola komunikasinya, DDD menggunakan <strong>Context Map</strong> &#8212; semacam peta hubungan antar tim atau sistem.</p><p>Contohnya:</p><pre><code>[Sales Context] ---&gt; [Shipping Context] ---&gt; [Support Context]
       |                   |                       |
    (Customer&#8211;Supplier)  (Partnership)         (Separate Ways)</code></pre><p>Context Map membantu kita menjawab:</p><ul><li><p>Siapa upstream, siapa downstream?</p></li><li><p>Pola komunikasi apa yang digunakan?</p></li><li><p>Siapa yang perlu berkoordinasi untuk perubahan?</p></li></ul><p>Dengan peta ini, arsitektur organisasi menjadi lebih transparan, dan konflik semantik bisa diantisipasi sejak awal.</p><h2>Ketika Komunikasi Gagal</h2><p>Kesalahan paling umum dalam integrasi antar context adalah menganggap komunikasi sekadar urusan teknis. Padahal, <em>communication patterns</em> adalah tentang <strong>hubungan antar manusia dan tim</strong>, bukan hanya antar sistem.</p><p>Masalah seperti:</p><ul><li><p>&#8220;API-nya berubah sepihak,&#8221;</p></li><li><p>&#8220;Istilah &#8216;customer&#8217; di mereka artinya beda,&#8221;</p></li><li><p>atau &#8220;Kita tidak tahu kapan upstream akan rilis versi baru,&#8221; semuanya berakar pada komunikasi lintas domain yang buruk.</p></li></ul><p>DDD mengajarkan bahwa solusi teknis harus lahir dari <strong>kesepahaman semantik dan kolaborasi antar tim.</strong></p><h2>Ringkasnya, Komunikasi yang Berarti</h2><p>Setiap bounded context adalah dunia kecil dengan bahasanya sendiri. Tapi dunia ini tidak bisa hidup sendirian, ia harus berbicara dengan dunia lain.</p><p>Communication patterns membantu kita menjaga agar percakapan itu <strong>bermakna dan sehat</strong>, bukan sekadar pertukaran data.</p><p>Arsitektur yang bagus melindungi model dari gangguan teknis, tapi komunikasi yang bagus melindungi model dari <strong>kesalahpahaman makna</strong>.</p><p>Dan pada akhirnya, seperti yang sering diingatkan Khononov: &#8220;Domain-Driven Design bukan hanya tentang model dan kode, tapi tentang orang-orang yang berbicara dengan bahasa yang sama.&#8221;</p><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Architecture Patterns untuk Menjaga Model Tetap Bersih]]></title><description><![CDATA[Sampai di artikel ini, kita sudah membangun model domain yang mencerminkan cara bisnis bekerja.]]></description><link>https://www.0-1.my.id/p/architecture-patterns-untuk-menjaga</link><guid isPermaLink="false">https://www.0-1.my.id/p/architecture-patterns-untuk-menjaga</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Fri, 17 Oct 2025 15:06:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sampai di artikel ini, kita sudah membangun model domain yang mencerminkan cara bisnis bekerja. Tapi muncul tantangan baru: bagaimana cara <strong>menjaga model itu tetap bersih</strong> ketika sistem kita tumbuh, framework berubah, dan kebutuhan makin kompleks?</p><p>Inilah peran <em>architecture patterns</em>, arsitektur perangkat lunak yang membantu memisahkan logika bisnis dari hal-hal teknis, agar domain model tidak tenggelam di tengah &#8220;kebisingan&#8221; infrastruktur.</p><h2>Arsitektur Itu Bukan Soal Layer Saja</h2><p>Kebanyakan engineer mendengar kata &#8220;arsitektur&#8221; lalu langsung berpikir tentang <em>layered architecture</em>, lapisan presentasi, logika bisnis, dan data. Padahal, arsitektur dalam konteks DDD bukan cuma soal membagi layer, tapi <strong>menentukan bagaimana model domain berinteraksi dengan bagian lain dari sistem.</strong></p><p>Arsitektur adalah <strong>cara menjaga agar domain model tetap berdaulat</strong>, tidak dikendalikan oleh framework, database, atau API eksternal.</p><blockquote><p>Dalam DDD, domain model adalah &#8220;raja&#8221;, dan arsitektur adalah istana yang melindunginya.</p></blockquote><h2>Mengapa Butuh Pola Arsitektur?</h2><p>Tanpa pola arsitektur yang jelas, kode domain akan cepat &#8220;tercemar&#8221; oleh hal-hal teknis. Awalnya mungkin cuma satu query SQL di dalam entitas, lalu satu logika HTTP handler di service. Lama-lama model domain kehilangan fokus, menjadi campuran antara logika bisnis, UI, dan infrastruktur.</p><p>Inilah yang menyebabkan <em>Big Ball of Mud</em>, sistem yang sulit dipahami karena semua bagian saling menempel tanpa batas yang jelas.</p><p>Pola arsitektur membantu kita menetapkan <strong>batas tanggung jawab (separation of concerns)</strong> antara:</p><ul><li><p>Domain logic (apa yang bisnis lakukan),</p></li><li><p>Application logic (kapan bisnis dijalankan),</p></li><li><p>dan Infrastructure logic (bagaimana bisnis dijalankan di dunia nyata).</p></li></ul><h2>Beberapa Pola Arsitektur Umum</h2><p>Buku Khononov (2022) membahas beberapa pola arsitektur yang sering digunakan dalam implementasi DDD: <strong>Layered Architecture</strong>, <strong>Ports and Adapters (Hexagonal Architecture)</strong>, dan <strong>CQRS</strong>. Mari kita bahas satu per satu dengan contoh sederhana.</p><h3>1. Layered Architecture, Struktur Paling Umum</h3><p>Arsitektur berlapis ini mungkin paling dikenal. Biasanya terdiri dari tiga atau empat lapisan:</p><pre><code>+------------------------+
|   Presentation Layer   |
+------------------------+
|   Application Layer    |
+------------------------+
|   Domain Layer         |
+------------------------+
|   Infrastructure Layer |
+------------------------+</code></pre><ul><li><p><strong>Presentation Layer</strong> Menangani interaksi dengan pengguna atau sistem lain (API, UI, CLI).</p></li><li><p><strong>Application Layer</strong> Mengatur <em>flow</em> atau urutan operasi &#8212; kapan bisnis dieksekusi.</p></li><li><p><strong>Domain Layer</strong> Tempat Entity, Value Object, dan Domain Service berada.</p></li><li><p><strong>Infrastructure Layer</strong> Berisi detail teknis seperti database, file system, atau network.</p></li></ul><p><strong>Contoh sederhana (Rust):</strong></p><pre><code>// Domain Layer
struct Order {
    id: u64,
    total: f64,
}

impl Order {
    fn confirm(&amp;mut self) {
        println!("Order {} dikonfirmasi", self.id);
    }
}

// Application Layer
fn confirm_order(order_repo: &amp;mut impl OrderRepository, id: u64) {
    if let Some(mut order) = order_repo.find_by_id(id) {
        order.confirm();
        order_repo.save(order);
    }
}

// Infrastructure Layer
trait OrderRepository {
    fn find_by_id(&amp;self, id: u64) -&gt; Option&lt;Order&gt;;
    fn save(&amp;mut self, order: Order);
}</code></pre><p>Layered architecture mudah dipahami, cocok untuk banyak aplikasi. Namun, jika tidak dijaga dengan disiplin, lapisan bisa bocor, logika bisnis sering naik ke Application Layer atau turun ke Infrastructure Layer.</p><h3>2. Ports and Adapters (Hexagonal Architecture)</h3><p>Kadang disebut juga <strong>Hexagonal Architecture</strong>, pola ini dikembangkan oleh Alistair Cockburn. Tujuannya: <strong>memisahkan domain dari dunia luar</strong> lewat <em>port</em> (antarmuka) dan <em>adapter</em> (implementasi teknis).</p><p>Bayangkan domain sebagai inti heksagon, dan setiap sisi dihubungkan oleh &#8220;port&#8221; yang bisa dipasang atau dilepas sesuai kebutuhan: API, database, atau event queue.</p><pre><code>           +-----------------------+
           |    Presentation API   |
           +-----------+-----------+
                       |
         +-------------+-------------+
         |       Domain Core         |
         | (Entities, Services, etc) |
         +-------------+-------------+
                       |
           +-----------+-----------+
           | Infrastructure / DB   |
           +-----------------------+</code></pre><p><strong>Kuncinya:</strong> Domain tidak tahu siapa yang memanggilnya, dan tidak peduli siapa yang menyimpan datanya.</p><p><strong>Contoh sederhana (Rust):</strong></p><pre><code>// Port (interface)
trait PaymentGateway {
    fn pay(&amp;self, amount: f64) -&gt; bool;
}

// Domain core
struct PaymentService&lt;'a&gt; {
    gateway: &amp;'a dyn PaymentGateway,
}

impl&lt;'a&gt; PaymentService&lt;'a&gt; {
    fn process(&amp;self, amount: f64) {
        if self.gateway.pay(amount) {
            println!("Pembayaran berhasil!");
        } else {
            println!("Pembayaran gagal.");
        }
    }
}

// Adapter (implementasi)
struct FakeGateway;

impl PaymentGateway for FakeGateway {
    fn pay(&amp;self, _amount: f64) -&gt; bool {
        true
    }
}</code></pre><p>Dengan pola ini, kita bisa mengganti implementasi <em>PaymentGateway</em> tanpa menyentuh kode domain. Mau pakai Midtrans, Stripe, atau simulator lokal, tinggal ganti adapter-nya.</p><h3>3. CQRS (Command Query Responsibility Segregation)</h3><p>CQRS memisahkan dua jenis operasi utama sistem:</p><ul><li><p><strong>Command</strong> &#8594; mengubah data (buat, ubah, hapus).</p></li><li><p><strong>Query</strong> &#8594; membaca data.</p></li></ul><p>Tujuannya agar keduanya bisa berevolusi dengan kebutuhan berbeda, misalnya skala, performa, atau keamanan.</p><p>Dalam sistem sederhana, Command dan Query bisa digabung. Tapi dalam sistem kompleks, pemisahan ini membuat sistem lebih efisien dan mudah dioptimasi.</p><p><strong>Contoh sederhana (Rust):</strong></p><pre><code>// Command handler
fn confirm_order(order_repo: &amp;mut impl OrderRepository, id: u64) {
    if let Some(mut order) = order_repo.find_by_id(id) {
        order.confirm();
        order_repo.save(order);
    }
}

// Query handler
fn get_order_details(order_repo: &amp;impl OrderRepository, id: u64) -&gt; Option&lt;Order&gt; {
    order_repo.find_by_id(id)
}</code></pre><p>Kita bisa punya dua pipeline terpisah, satu untuk memproses perubahan, satu untuk membaca data (misalnya dari cache atau database yang dioptimalkan untuk query). CQRS sering dikombinasikan dengan <em>Event Sourcing</em> agar setiap perubahan bisa dilacak dengan mudah.</p><h2>Memilih Pola yang Tepat</h2><p>Tidak ada arsitektur yang &#8220;paling benar.&#8221; Pola yang ideal tergantung dari:</p><ul><li><p><strong>Kompleksitas domain</strong>,</p></li><li><p><strong>Skala sistem</strong>,</p></li><li><p><strong>Kebutuhan integrasi</strong>, dan</p></li><li><p><strong>Tim yang mengelola.</strong></p></li></ul><p>Sebagai panduan umum:</p><ul><li><p>Gunakan <strong>Layered Architecture</strong> untuk sistem yang masih tumbuh.</p></li><li><p>Gunakan <strong>Hexagonal Architecture</strong> jika ingin model domain benar-benar independen dari framework atau infrastruktur.</p></li><li><p>Gunakan <strong>CQRS</strong> bila ada kebutuhan pemisahan beban baca/tulis yang signifikan.</p></li></ul><h2>Menghindari Arsitektur yang Membelenggu</h2><p>Sering kali engineer terjebak pada arsitektur yang mereka anggap &#8220;suci&#8221;, sampai akhirnya domain model malah dikorbankan demi mematuhi struktur. DDD justru sebaliknya: <strong>arsitektur harus melayani domain, bukan sebaliknya.</strong></p><p>Kuncinya adalah menjaga <em>boundaries</em> tetap jelas, tapi tidak kaku. Ketika model domain berkembang, arsitektur boleh ikut menyesuaikan, selama tujuannya sama: <strong>melindungi logika bisnis dari gangguan teknis.</strong></p><h2>Ringkasnya, Arsitektur Sebagai Penjaga Makna</h2><p>Arsitektur bukan tentang folder, file, atau diagram. Ia tentang <strong>cara melindungi makna bisnis</strong> di dalam sistem kita.</p><p>Layer, port, dan adapter hanyalah alat untuk memastikan kode kita tetap bercerita tentang <em>domain</em>, bukan tentang framework. Karena pada akhirnya, sistem yang paling bertahan lama bukan yang paling modern arsitekturnya, tapi yang paling setia pada makna bisnis yang dilayaninya.</p><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Menyempurnakan dan Menumbuhkan Model Domain]]></title><description><![CDATA[Setelah kita membangun fondasi Domain Model, lengkap dengan Entity, Value Object, Aggregate, Repository, dan kawan-kawan, muncul pertanyaan besar berikutnya: &#8220;Bagaimana model domain kita tetap relevan ketika bisnis berubah?&#8221;]]></description><link>https://www.0-1.my.id/p/menyempurnakan-dan-menumbuhkan-model</link><guid isPermaLink="false">https://www.0-1.my.id/p/menyempurnakan-dan-menumbuhkan-model</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Thu, 16 Oct 2025 15:10:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><p>Setelah kita membangun fondasi Domain Model, lengkap dengan Entity, Value Object, Aggregate, Repository, dan kawan-kawan, muncul pertanyaan besar berikutnya: &#8220;Bagaimana model domain kita tetap relevan ketika bisnis berubah?&#8221;</p><p>Di dunia nyata, bisnis tidak pernah diam. Aturan baru muncul, prioritas berubah, bahkan istilah yang dulu dianggap jelas bisa bergeser maknanya. Maka, Domain Model pun harus <strong>tumbuh dan berevolusi</strong>. Bab ini membahas bagaimana kita bisa menyempurnakan model tanpa membuat sistem runtuh.</p><h2>Model Domain Bukan Arsitektur Sekali Jadi</h2><p>Kesalahan umum dalam menerapkan DDD adalah menganggap domain model sebagai desain permanen. Padahal, model itu seharusnya hidup dan berubah mengikuti <strong>pemahaman baru tentang domain.</strong></p><p>Khononov (2022) menekankan bahwa DDD bukan tentang mencari model yang sempurna di awal, melainkan <strong>mendekati pemahaman yang lebih baik seiring waktu.</strong> Setiap diskusi dengan ahli domain, setiap bug, dan setiap fitur baru bisa memperkaya model kita.</p><p>Bayangkan model domain seperti peta kota. Saat pertama kali dibuat, mungkin hanya berisi jalan utama. Tapi seiring waktu, kita tambahkan gang kecil, lampu merah, dan area baru &#8212; bukan karena peta awal salah, tapi karena pengetahuan kita bertambah.</p><h2>Proses Refinement: Dari Model Kasar ke Model Tajam</h2><h3>1. Mulai dari Model Kasar</h3><p>Pada awal proyek, buatlah model sederhana dulu &#8212; tidak masalah kalau belum lengkap. Fokus pada pemahaman dasar: <em>apa saja konsep utama</em> dan <em>bagaimana mereka berhubungan</em>.</p><p>Misalnya kita membangun sistem untuk pengiriman paket. Model awal bisa sesederhana ini:</p><pre><code>struct Package {
    id: u64,
    status: String,
}

impl Package {
    fn deliver(&amp;mut self) {
        self.status = "Delivered".to_string();
    }
}</code></pre><p>Masih sederhana, tapi cukup untuk memulai percakapan dengan ahli domain.</p><h3>2. Kembangkan Melalui Umpan Balik</h3><p>Setiap kali bisnis atau stakeholder memberi masukan (&#8220;Bagaimana kalau pelanggan bisa menjadwalkan ulang pengiriman?&#8221;), kita ubah model agar mencerminkan realitas baru itu.</p><pre><code>enum DeliveryStatus {
    Pending,
    InTransit,
    Delivered,
    Rescheduled(String), // alasan atau tanggal baru
}

struct Package {
    id: u64,
    status: DeliveryStatus,
}</code></pre><p>Model berkembang mengikuti kebutuhan bisnis, <strong>bukan sebaliknya.</strong> Perubahan ini adalah bentuk <em>refinement</em>, bukan &#8220;refactor tanpa arah&#8221;.</p><h3>3. Evaluasi Bahasa Umum (Ubiquitous Language)</h3><p>Setiap istilah di model harus sama artinya bagi semua pihak, engineer, product owner, dan ahli domain.</p><p>Kalau tim mulai bilang &#8220;Shipment&#8221; di tempat yang seharusnya &#8220;Package&#8221;, itu tanda bahasa umum mulai kabur. Periksa model, ubah nama kelas, fungsi, dan variabel agar kembali konsisten dengan istilah bisnis yang terbaru.</p><p>Inilah kenapa DDD mendorong kode yang &#8220;bercerita seperti domain&#8221;-nya.</p><h2>Pola Umum dalam Evolusi Model</h2><h3>1. Split dan Merge Aggregate</h3><p>Saat sistem bertumbuh, aggregate yang dulu terasa ideal bisa jadi terlalu besar. Kita mungkin perlu memisahkannya agar tidak menimbulkan <em>transaction contention</em> atau <em>performance bottleneck</em>.</p><p>Misalnya awalnya kita punya <code>Order</code> yang juga menyimpan <code>Payment</code> dan <code>Shipment</code> di dalamnya. Tapi seiring waktu, tim pembayaran dan pengiriman berkembang terpisah.</p><p>Maka kita pisahkan menjadi tiga aggregate dengan batas yang jelas.</p><pre><code>// Awalnya semua di Order
struct Order {
    id: u64,
    payment_status: String,
    shipment_status: String,
}

// Setelah displit
struct Order {
    id: u64,
}

struct Payment {
    order_id: u64,
    status: String,
}

struct Shipment {
    order_id: u64,
    tracking_code: String,
}</code></pre><p>Kini setiap tim bisa berinovasi di domain-nya tanpa saling menunggu.</p><h3>2. Mengubah Entity menjadi Value Object (atau sebaliknya)</h3><p>Kadang sebuah objek awalnya dianggap penting secara identitas, tapi belakangan ternyata tidak.</p><p>Contoh: pada tahap awal, kita buat <code>Address</code> sebagai <code>Entity</code> karena kita pikir pengguna bisa memperbaruinya dan kita perlu menyimpannya secara unik. Tapi kemudian kita sadar bahwa <code>Address</code> hanya bagian dari <code>Order</code> dan tidak pernah digunakan secara terpisah.</p><p>Maka kita ubah menjadi <code>Value Object</code>.</p><pre><code>#[derive(Clone, PartialEq, Eq)]
struct Address {
    street: String,
    city: String,
    postal_code: String,
}</code></pre><p>Sebaliknya, jika suatu saat kita butuh melacak alamat pelanggan secara historis, <code>Address</code> bisa dipromosikan lagi menjadi <code>Entity</code>.</p><h3>3. Menambah Domain Event untuk Dekoupling</h3><p>Ketika sistem makin besar, modul-modul akan saling tergantung. Untuk mencegah kekacauan, kita bisa menambahkan <strong>Domain Event</strong> agar komunikasi antarmodul tidak saling menempel.</p><pre><code>struct OrderCreated {
    order_id: u64,
}

struct SendEmailOnOrderCreated;

impl SendEmailOnOrderCreated {
    fn handle(event: &amp;OrderCreated) {
        println!("Email konfirmasi untuk order {} dikirim!", event.order_id);
    }
}</code></pre><p>Dengan event, <code>Order</code> tidak perlu tahu cara mengirim email, dan modul notifikasi bisa bereaksi secara independen. Ini membuat sistem lebih fleksibel dan siap tumbuh tanpa coupling berlebihan.</p><h2>Evolusi yang Terarah, Bukan Reaktif</h2><p>Menumbuhkan model domain bukan berarti &#8220;sering ganti struktur kode&#8221;. Tujuannya bukan perubahan semata, tapi <strong>perubahan yang memperdalam pemahaman kita terhadap domain</strong>.</p><p>Langkah idealnya seperti ini:</p><ol><li><p><strong>Temukan masalah di dunia nyata.</strong> Misalnya pengguna bingung dengan istilah &#8220;shipment&#8221; vs &#8220;delivery&#8221;.</p></li><li><p><strong>Diskusikan dengan ahli domain.</strong> Pahami maknanya dalam konteks bisnis.</p></li><li><p><strong>Perbarui bahasa umum.</strong> Ubah nama kelas atau entitas agar konsisten dengan istilah baru.</p></li><li><p><strong>Refactor model.</strong> Pisahkan, gabungkan, atau ubah struktur sesuai pemahaman baru.</p></li><li><p><strong>Uji dan validasi.</strong> Pastikan perubahan tidak merusak perilaku bisnis yang sudah benar.</p></li></ol><p>Jika perubahan dilakukan lewat percakapan yang intens antara engineer dan ahli domain, model domain akan terus &#8220;mendekati kenyataan&#8221; seiring waktu.</p><h2>Kesalahan Umum Saat Model Berevolusi</h2><ol><li><p><strong>Refactor teknis tanpa konteks bisnis.</strong> Mengubah struktur hanya karena &#8220;terlihat lebih bersih&#8221;, padahal maknanya makin kabur.</p></li><li><p><strong>Terlalu cepat memecah aggregate.</strong> Split boleh dilakukan, tapi pastikan memang ada kebutuhan bisnis atau beban transaksi nyata.</p></li><li><p><strong>Mengabaikan bahasa umum.</strong> Nama-nama di kode harus tetap sejalan dengan istilah di dunia nyata, bukan dengan preferensi pribadi.</p></li><li><p><strong>Tidak mencatat keputusan.</strong> Setiap perubahan besar di domain model sebaiknya punya alasan bisnis yang terdokumentasi.</p></li></ol><h2>Menumbuhkan Model Secara Aman</h2><p>Dalam praktik modern, kita bisa menggunakan pendekatan seperti:</p><ul><li><p><strong>Feature toggles</strong>, untuk mengaktifkan model baru tanpa mengganggu produksi.</p></li><li><p><strong>Event sourcing</strong>, agar perubahan model tidak kehilangan jejak historis.</p></li><li><p><strong>Migration scripts</strong>, untuk memindahkan data lama ke struktur baru dengan aman.</p></li></ul><p>DDD tidak menentang perubahan, ia justru <strong>mengajarkan cara mengelolanya dengan sadar</strong>.</p><h2>Akhirnya: Model yang Hidup</h2><p>Domain model yang baik bukan yang paling indah diagramnya, tapi yang <strong>tetap bernapas bersama bisnisnya.</strong></p><p>Ketika bisnis berubah, model pun ikut beradaptasi. Ketika istilah baru muncul, kode pun ikut menyesuaikan. Dan ketika engineer dan ahli domain berbicara, mereka bicara dalam <strong>bahasa yang sama</strong>, bukan lagi sekadar query, tapi makna.</p><p>Itulah esensi menghadapi kompleksitas: Bukan melawannya dengan abstraksi berlebihan, tetapi <strong>menjinakkannya dengan pemahaman yang terus bertumbuh.</strong></p><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Pola Logika Bisnis Kompleks dengan Model Domain]]></title><description><![CDATA[Kalau di artikel-artikel sebelumnya kita bicara tentang cara membatasi konteks (bounded context) dan mengintegrasikannya, sekarang kita masuk ke jantung dari Domain-Driven Design (DDD): Domain Model.]]></description><link>https://www.0-1.my.id/p/pola-logika-bisnis-kompleks-dengan</link><guid isPermaLink="false">https://www.0-1.my.id/p/pola-logika-bisnis-kompleks-dengan</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Wed, 15 Oct 2025 16:44:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rOdU!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30b13e4e-634e-4bdd-b95d-174c866b2405_256x256.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Kalau di artikel-artikel sebelumnya kita bicara tentang cara membatasi konteks (bounded context) dan mengintegrasikannya, sekarang kita masuk ke jantung dari Domain-Driven Design (DDD): <strong>Domain Model</strong>.<br>Bagian ini menjawab pertanyaan besar: &#8220;Bagaimana cara membuat kode yang benar-benar mencerminkan cara bisnis bekerja, bukan sekadar menyimpan data?&#8221;</p><h2>Dari Strategi ke Taktik</h2><p>Dalam DDD, ada dua lapisan pendekatan: <strong>Strategic DDD</strong> dan <strong>Tactical DDD</strong>.<br>Strategic DDD membantu kita memetakan <em>peta besar</em>, membagi sistem menjadi domain, subdomain, dan bounded context.<br>Sementara Tactical DDD berbicara tentang <em>bagaimana kita membangun isi di dalam satu bounded context itu.</em></p><p>Kalau Strategic DDD seperti membuat denah kota, maka Tactical DDD adalah merancang bangunan di dalam tiap distrik: siapa penghuni, bagaimana alurnya, dan aturan apa yang berlaku di dalamnya.</p><h2>Domain Model: Jantung dari DDD</h2><p>Sebuah <strong>domain model</strong> bukan sekadar diagram UML atau tabel database.<br>Ia adalah <strong>representasi konseptual dari cara bisnis bekerja</strong>, diterjemahkan ke dalam kode, menggunakan bahasa yang sama dengan yang digunakan oleh para ahli domain.</p><p>Model ini bukan hanya soal <em>data structure</em>, tapi juga soal <em>perilaku (behavior)</em> dan <em>aturan (rules)</em> yang melekat di dalamnya.</p><p>Contoh sederhana:<br>Bayangkan kita membuat sistem untuk toko online. Ada entitas <code>Order</code>, tapi <code>Order</code> bukan cuma tabel dengan kolom <code>id</code>, <code>total</code>, dan <code>status</code>.<br>Ia harus tahu bagaimana:</p><ul><li><p>menambahkan item,</p></li><li><p>menghitung total,</p></li><li><p>memastikan tidak ada duplikasi produk,</p></li><li><p>dan kapan pesanan bisa dikonfirmasi.</p></li></ul><p>Model yang baik berarti kode kita <em>bicara seperti bisnisnya</em>.</p><h2>Entity</h2><p>Salah satu elemen paling penting dari domain model adalah <strong>Entity</strong>, sebuah objek yang punya identitas unik dan bisa berubah seiring waktu.</p><p>Misalnya, <code>User</code> dengan ID <code>123</code> tetap sama orangnya meski alamat atau emailnya berubah.<br>Yang menentukan dirinya adalah identitas, bukan nilainya.</p><pre><code><code>struct User {
    id: u64,
    name: String,
    email: String,
}

impl User {
    fn change_email(&amp;mut self, new_email: String) {
        self.email = new_email;
    }
}</code></code></pre><p>Di sini <code>User</code> adalah Entity karena kita mengenalinya lewat <code>id</code>.<br>Ketika <code>change_email()</code> dipanggil, objek ini masih &#8220;orang yang sama&#8221;.</p><h2>Value Object</h2><p>Berbeda dengan Entity, <strong>Value Object</strong> tidak punya identitas.<br>Ia hanya penting karena nilainya. Dua objek yang nilainya sama dianggap sama.</p><p>Coba pikirkan <code>Money</code>, <code>Address</code>, atau <code>DateRange</code>.<br>Kalau kamu punya <code>Money { amount: 100, currency: &#8220;USD&#8221; }</code>, itu identik dengan objek lain yang punya nilai sama.</p><pre><code><code>#[derive(Debug, Clone, PartialEq, Eq)]
struct Money {
    amount: f64,
    currency: String,
}</code></code></pre><p>Value Object biasanya <strong>immutable</strong>, artinya nilainya tidak diubah, tapi dibuat baru saat ada perubahan.<br>Pendekatan ini membuat kode lebih aman dan mudah diprediksi.</p><h2>Aggregate</h2><p>Saat bisnis mulai kompleks, satu entitas tidak lagi cukup.<br>Kita butuh sekumpulan entitas dan value object yang bekerja bersama dalam satu batas konsistensi.<br>Inilah yang disebut <strong>Aggregate</strong>.</p><p>Aggregate adalah kumpulan objek yang <strong>dikelola sebagai satu kesatuan logis</strong>, dengan satu titik masuk utama yang disebut <strong>Aggregate Root</strong>.</p><pre><code><code>struct OrderItem {
    product_id: u64,
    quantity: u32,
}

struct Order {
    id: u64,
    items: Vec&lt;OrderItem&gt;,
}

impl Order {
    fn add_item(&amp;mut self, product_id: u64, quantity: u32) {
        self.items.push(OrderItem { product_id, quantity });
    }

    fn total_items(&amp;self) -&gt; usize {
        self.items.len()
    }
}</code></code></pre><p><code>Order</code> di atas adalah Aggregate Root &#8212; semua perubahan terhadap <code>OrderItem</code> harus melalui <code>Order</code>.<br>Aggregate membantu menjaga <strong>aturan bisnis tetap konsisten</strong> di dalam batasnya.</p><h2>Repository</h2><p>Domain Model tidak seharusnya tahu tentang database atau API.<br>Tapi tentu kita tetap perlu menyimpan data.<br>Untuk itu, DDD memperkenalkan <strong>Repository</strong>.</p><p>Repository berfungsi sebagai &#8220;pintu keluar masuk&#8221; Aggregate.<br>Dari sisi domain, Repository terlihat seperti <em>koleksi di memori</em>, meski di baliknya mungkin ada SQL, file, atau service eksternal.</p><pre><code><code>trait OrderRepository {
    fn save(&amp;self, order: &amp;Order);
    fn find_by_id(&amp;self, id: u64) -&gt; Option&lt;Order&gt;;
}</code></code></pre><p>Dengan pola ini, domain tetap bersih dari detail teknis.<br>Kita bisa mengganti penyimpanan dari SQLite ke PostgreSQL tanpa mengubah logika bisnis sedikit pun.</p><h2>Domain Service</h2><p>Kadang kita menemukan logika bisnis yang tidak cocok dimasukkan ke satu entitas mana pun.<br>Misalnya, proses transfer uang antar akun: melibatkan dua <code>Account</code>, tapi tidak ada satu pun yang benar-benar &#8220;memiliki&#8221; logika itu.</p><p>Inilah peran <strong>Domain Service</strong>, tempat untuk menaruh logika lintas entitas.</p><pre><code><code>struct Account {
    id: u64,
    balance: f64,
}

struct TransferService;

impl TransferService {
    fn transfer(from: &amp;mut Account, to: &amp;mut Account, amount: f64) {
        if from.balance &gt;= amount {
            from.balance -= amount;
            to.balance += amount;
        }
    }
}</code></code></pre><p>Domain Service tetap bagian dari domain layer, bukan service teknis seperti API handler atau queue worker.<br>Ia merepresentasikan <strong>aksi bisnis</strong>, bukan infrastruktur.</p><h2>Factory</h2><p>Membuat entitas kadang tidak sesederhana memanggil <code>new()</code>.<br>Ada validasi, aturan bisnis, atau dependensi lain.<br>Di sinilah <strong>Factory</strong> digunakan.</p><p>Factory bertugas <strong>membangun objek kompleks dengan aturan bisnis yang benar sejak awal.</strong></p><pre><code><code>struct OrderFactory;

impl OrderFactory {
    fn create_new(items: Vec&lt;OrderItem&gt;) -&gt; Order {
        assert!(!items.is_empty(), &#8220;Order harus punya minimal satu item&#8221;);
        Order { id: 0, items }
    }
}</code></code></pre><p>Factory mencegah kita membuat objek domain dalam keadaan &#8220;tidak valid&#8221;.<br>Ia seperti dapur yang memastikan masakan sudah matang sebelum dihidangkan.</p><h2>Domain Event</h2><p>Dalam kehidupan nyata, setiap sistem bisnis penuh dengan peristiwa: pesanan dibuat, pembayaran diterima, stok habis, dsb.<br>DDD merepresentasikan semua itu lewat <strong>Domain Event</strong>.</p><p>Event adalah sinyal bahwa <em>sesuatu yang penting sudah terjadi</em> di dalam domain.<br>Biasanya diberi nama dengan bentuk lampau: <code>OrderCreated</code>, <code>PaymentReceived</code>.</p><pre><code><code>struct OrderCreated {
    order_id: u64,
    timestamp: u64,
}
</code></code></pre><p>Event bisa dikirim ke bagian lain dari sistem (misalnya ke modul pengiriman atau notifikasi) tanpa membuat coupling langsung antar komponen.<br>Hasilnya: sistem lebih fleksibel dan modular.</p><h2>Menghadapi Kompleksitas</h2><p>Setiap sistem yang tumbuh pasti akan menjadi kompleks.<br>Tactical DDD memberi kita alat untuk <strong>mengelola</strong> kompleksitas itu, bukan menyingkirkannya.</p><ul><li><p>Entity dan Value Object membantu kita berpikir dalam istilah bisnis, bukan tabel.</p></li><li><p>Aggregate menjaga aturan tetap konsisten.</p></li><li><p>Repository dan Factory memisahkan logika domain dari teknis.</p></li><li><p>Domain Service dan Event membuat sistem bisa berkembang tanpa kekacauan.</p></li></ul><p>Inilah inti filosofi DDD: &#8220;Kode bukan cuma alat, tapi cerminan dari cara kita memahami bisnis.&#8221;</p><p>Ketika model domain dibuat dengan benar, engineer tidak hanya menulis kode, mereka <strong>mengkodekan pengetahuan bisnis</strong> yang bisa bertahan bertahun-tahun, bahkan ketika framework atau teknologi berubah.</p><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Pola Logika Bisnis Sederhana dengan Transaction Script & Active Record]]></title><description><![CDATA[Saat logika bisnis belum terlalu rumit, kita bisa pakai pola Transaction Script atau Active Record.]]></description><link>https://www.0-1.my.id/p/pola-logika-bisnis-sederhana-dengan</link><guid isPermaLink="false">https://www.0-1.my.id/p/pola-logika-bisnis-sederhana-dengan</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Tue, 14 Oct 2025 15:12:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!sy3A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Saat logika bisnis belum terlalu rumit, kita bisa pakai pola <strong>Transaction Script</strong> atau <strong>Active Record</strong>. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sy3A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sy3A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!sy3A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!sy3A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!sy3A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sy3A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sy3A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!sy3A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!sy3A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!sy3A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f644851-dad9-4137-a6d8-7f68c59e9b6c_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Pola Logika Bisnis Sederhana dengan Transaction Script &amp; Active Record.</figcaption></figure></div><h2>Business Logic</h2><p>Logika bisnis (<em>business logic</em>) adalah bagian dari sistem yang menentukan bagaimana data diproses sesuai aturan dan tujuan bisnis<strong>.</strong></p><p>Secara definisi:</p><blockquote><p>Business logic adalah sekumpulan keputusan, kalkulasi, kondisi, dan alur kerja yang menjelaskan <em>bagaimana bisnis seharusnya beroperasi dalam konteks sistem perangkat lunak.</em></p></blockquote><p>Contoh:</p><ul><li><p>Jika saldo rekening &lt; 0 &#8594; tolak transaksi.</p></li><li><p>Jika pelanggan sudah bayar &#8594; ubah status pesanan menjadi &#8220;confirmed.&#8221;</p></li><li><p>Jika total belanja &gt; 1 juta &#8594; berikan diskon 10%.</p></li></ul><p>Semua ini bukan &#8220;aturan pemrograman umum,&#8221; tapi cara bisnis tertentu berjalan.<br>Karena itu, <em>business logic</em> berbeda dari <em>technical logic</em> (seperti validasi input, autentikasi pengguna, caching, dll.).</p><p>Intinya: logika bisnis = perilaku sistem yang mencerminkan keputusan bisnis.</p><h3>Business Rules</h3><p>Istilah Business Rules dan Business Logic ini sering tertukar, padahal secara konsep ada perbedaan:</p><ul><li><p> Business Rules</p><ul><li><p>Ciri utama: Prinsip atau kebijakan yang didefinisikan oleh organisasi, misalnya menjelaskan apa yang boleh dan tidak boleh terjadi di dunia nyata.</p></li><li><p>Contoh: Setiap transaksi harus memiliki nomor faktur unik.</p></li></ul></li><li><p>Business Logic</p><ul><li><p>Ciri utama: Implementasi teknis dari aturan-aturan tersebut di dalam sistem.</p></li><li><p>Contoh: <code>fn generate_invoice_id()</code> memastikan nomor faktur tidak duplikat.</p></li></ul></li></ul><p>Singkatnya:</p><ul><li><p><em>Business rules</em> = <strong>&#8220;aturan permainan&#8221;</strong> (bersifat deklaratif).</p></li><li><p><em>Business logic</em> = <strong>&#8220;cara memainkan permainan itu di sistem&#8221;</strong> (bersifat prosedural).</p></li></ul><p>Dalam DDD, keduanya sama-sama penting:</p><ul><li><p><em>Aturan bisnis</em> berasal dari pengetahuan ahli domain (domain expert).</p></li><li><p><em>Logika bisnis</em> diimplementasikan di kode (biasanya di entitas atau service dalam domain model).</p></li></ul><h2>Transaction Script</h2><p>Secara definisi, Transaction Script adalah pola arsitektur di mana setiap operasi bisnis diimplementasikan sebagai satu prosedur atau fungsi tunggal.<br>Istilah aslinya berasal dari <em>Patterns of Enterprise Application Architecture</em> oleh Martin Fowler (2003).</p><blockquote><p>Definisi: &#8220;Transaction Script organizes business logic by procedures where each procedure handles a single request from the presentation.&#8221;<br>&#8212; <em>Martin Fowler, P of EAA, 2003.</em></p></blockquote><p>Dengan kata lain:</p><ul><li><p>Setiap <em>use case</em> bisnis (misal &#8220;proses pembayaran&#8221;, &#8220;buat laporan&#8221;, &#8220;import data&#8221;) ditulis sebagai satu skrip atau fungsi.</p></li><li><p>Logika bisnis disusun secara imperatif (langkah demi langkah).</p></li><li><p>Tidak ada objek domain yang rumit &#8212; biasanya hanya sekumpulan operasi database.</p></li></ul><p>Analogi: seperti membuat resep dapur dalam satu lembar kertas, semua langkahnya berurutan: ambil bahan, masak, sajikan. Simpel, tapi sulit dipakai ulang kalau resep makin kompleks.</p><p>Khononov (2022) menjelaskan bahwa <em>Transaction Script</em> mengorganisir logika bisnis ke dalam prosedur terpisah. Setiap prosedur (atau fungsi) menangani satu permintaan atau operasi bisnis. </p><p>Misalnya, fungsi <code>process_payment()</code> yang hanya fokus menyelesaikan satu transaksi pembayaran. Pendekatan ini gampang dipahami dan minim abstraksi. Contohnya, bayangkan kita punya daftar pekerjaan (job) yang perlu diproses satu per satu:</p><pre><code><code>fn process_jobs(db: &amp;Database) {
    db.start_transaction();
    if let Some(job) = db.load_next_job() {
        let data = std::fs::read_to_string(&amp;job.source).unwrap();
        let result = convert_to_xml(&amp;data);
        std::fs::write(&amp;job.destination, result).unwrap();
        db.mark_complete(job.id);
    }
    db.commit();
}
</code></code></pre><p>Kode di atas menunjukkan satu prosedur sederhana: mulai transaksi, baca job berikutnya, ubah data, simpan hasil, lalu <em>commit</em>. Jika ada kesalahan di tengah, sistem harus <em>rollback</em> agar data tetap konsisten. </p><p>Khononov menegaskan pentingnya perilaku transaksional di setiap skrip: operasi harus sukses seluruhnya atau gagal tanpa meninggalkan kondisi setengah jadi. Karena itu, pola Transaction Script cocok untuk subdomain pendukung atau tugas <strong>ETL (Extract-Transform-Load)</strong> sederhana. Sebagai contoh, sinkronisasi data dari satu sistem ke sistem lain bisa diimplementasikan dengan skrip seperti di atas.</p><p><strong>Kapan pakai Transaction Script?</strong> Beberapa poin penting:</p><ul><li><p>Cocok untuk <em>subdomain pendukung</em> atau <em>generik</em> di mana logika bisnisnya prosedural (misal batch job, laporan, sinkronisasi).</p></li><li><p>Sederhana dan cepat: minim abstraksi, performa tinggi karena langsung panggil database (atau penyimpanan).</p></li><li><p><strong>Hati-hati:</strong> Jika logika bisnis makin kompleks, skrip terpisah cenderung duplikasi kode dan kesulitan pemeliharaan. Khononov bahkan menyebut pattern ini sering dianggap <em>antipola (antipattern)</em> karena bisa jadi &#8220;big ball of mud&#8221; jika dipakai di domain inti yang rumit. Jadi, jangan pakai Transaction Script untuk <em>core subdomain</em> yang punya banyak aturan bisnis, karena pola ini tidak tahan dengan kompleksitas tinggi.</p></li></ul><h3>Antipattern Arsitektur Big Ball of Mud</h3><p>Ini adalah antipattern arsitektur yang menggambarkan sistem tanpa struktur yang jelas.</p><blockquote><p><strong>Definisi:</strong> &#8220;A Big Ball of Mud is a haphazardly structured system, tangled, and difficult to maintain.&#8221;<br>&#8212; <em>Foote &amp; Yoder, 1997.</em></p></blockquote><p>Sederhananya:</p><ul><li><p>Semua kode bercampur tanpa batas yang jelas.</p></li><li><p>Tidak ada pemisahan logika bisnis, data, dan presentasi.</p></li><li><p>Setiap perubahan kecil bisa merusak bagian lain.</p></li></ul><p>Dalam konteks pembahasan di atas:</p><p>Jika kita memaksa memakai <em>Transaction Script</em> atau <em>Active Record</em> untuk domain yang kompleks (seperti <em>core subdomain</em>), cepat atau lambat sistem akan jadi <em>Big Ball of Mud.</em></p><p>Kenapa? Karena fungsi-fungsi akan saling memanggil, logika duplikat di mana-mana, dan tidak ada satu model mental yang jelas tentang &#8220;bagaimana bisnis bekerja&#8221; di dalam kode.</p><h2>Active Record</h2><p>Active Record juga berasal dari buku Fowler yang sama, dan definisinya adalah:</p><blockquote><p>Definisi: &#8220;An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.&#8221;<br>&#8212; <em>Martin Fowler, P of EAA, 2003.</em></p></blockquote><p>Artinya:</p><ul><li><p>Setiap baris di tabel database direpresentasikan oleh sebuah objek.</p></li><li><p>Objek itu <em>&#8220;aktif&#8221;</em> karena bisa menyimpan (<code>save()</code>), memperbarui (<code>update()</code>), atau menghapus (<code>delete()</code>) dirinya sendiri.</p></li><li><p>Kadang juga memuat logika bisnis sederhana, seperti validasi atau penghitungan kecil.</p></li></ul><p>Analogi: seperti lembar Excel di mana tiap baris bisa langsung &#8220;menyimpan dirinya ke server&#8221; begitu kita ubah isinya.</p><p>Active Record biasanya lebih rapi dari Transaction Script karena sudah mulai ada objek dan data berelasi, tapi belum punya pemisahan yang jelas antara data dan aturan bisnis.</p><p>Pola ini diperkenalkan oleh Fowler dan disitir Khononov (2022) sebagai objek yang &#8220;membungkus satu baris di tabel database, mengenkapsulasi akses database, dan menambah logika bisnis di data tersebut&#8221;. Artinya, setiap entitas data (misalnya baris <code>User</code> di tabel) direpresentasikan oleh sebuah objek yang punya metode sendiri, termasuk operasi <em>save()</em> atau <em>update()</em> ke database. </p><p>Active Record cocok ketika logika bisnis masih sederhana, tapi struktur datanya relatif rumit (misal relasi banyak-ke-banyak). Contohnya, kalau kita punya struct Rust <code>User</code>:</p><pre><code><code>struct User {
    id: u32,
    name: String,
    email: String,
}

impl User {
    fn save(&amp;self, conn: &amp;DbConnection) {
        // Contoh sederhana: INSERT atau UPDATE ke DB
        conn.execute(&#8221;INSERT INTO users ...&#8221;, &amp;[&amp;self.name, &amp;self.email]);
    }
    fn increment_logins(&amp;mut self, conn: &amp;DbConnection) {
        self.logins += 1;
        self.save(conn);
    }
}
</code></code></pre><p>Di sini, <code>User</code> bertindak sebagai <em>active record</em>: ia menyimpan datanya (<code>id</code>, <code>name</code>, dll.) dan punya method <code>save()</code> untuk persist ke database. Jika kita perlu modifikasi data kompleks, kita manipulasi objek <code>User</code> dan panggil <code>user.save(conn)</code> untuk update. </p><p>Menurut Khononov, tujuan pola ini adalah <em>mengenkapsulasi kompleksitas pemetaan antara object ke skema database</em>. Dibanding Transaction Script, skema Active Record menyediakan objek-objek khusus yang memuat data dan operasi CRUD mereka sendiri.</p><p><strong>Kapan pakai Active Record?</strong> Beberapa poin:</p><ul><li><p>Logika masih sederhana (CRUD, validasi input ringan) tapi datanya lebih struktur.</p></li><li><p>Berguna di <em>subdomain pendukung/generik</em> yang butuh konversi data kompleks ke model aplikasi.</p></li><li><p>Intinya: Active Record adalah Transaction Script yang &#8220;hidup&#8221; &#8211; yaitu setiap operasi bisnis masih dilakukan di luar objek, tapi objek data punya <em>save()</em> sendiri. Ini punya kekurangan: logika bisnis tetap tersebar di layanan/prosedur, jadi sering disebut <em>anemic domain model</em>. Maka jangan gunakan di core subdomain yang seharusnya punya domain model penuh (<em>full domain model</em>).</p></li></ul><p>Ringkasnya, bagian ini memberikan pemahaman bahwa untuk kasus sederhana kita bisa pakai Transaction Script atau Active Record. Keduanya ringan dan cepat diimplementasi, tapi terbatas pada logika sederhana di subdomain pendukung. Untuk core subdomain dengan banyak aturan, kita akan membahas pada pola Domain Model berikutnya.</p><h3>Anemic Domain Model</h3><p>Istilah ini juga dari Martin Fowler, dan Khononov menyinggungnya saat membandingkan Active Record dengan Domain Model.</p><blockquote><p>Definisi: &#8220;Anemic Domain Model is a domain model where the business logic is absent and resides in services instead of the entities themselves.&#8221;<br>&#8212; <em>Martin Fowler, 2003.</em></p></blockquote><p>Artinya:</p><ul><li><p>Objek domain hanya menyimpan data (getter &amp; setter).</p></li><li><p>Logika bisnis tersebar di service/fungsi lain.</p></li><li><p>Secara teknis modelnya ada, tapi secara semantik &#8220;kosong&#8221;.</p></li></ul><p>Contoh dalam Rust:</p><pre><code><code>struct Order {
    id: u32,
    total: f64,
    status: String,
}

fn confirm(order: &amp;mut Order) {
    if order.total &gt; 0.0 {
        order.status = &#8220;Confirmed&#8221;.to_string();
    }
}
</code></code></pre><p>Objek <code>Order</code> di sini tidak tahu apa-apa tentang bisnisnya sendiri.<br>Segala logika berada di luar (<code>confirm()</code>). Akibatnya, aturan bisnis bisa dengan mudah tersebar dan bertentangan.</p><p>DDD menolak pola ini karena tujuan DDD adalah memusatkan logika bisnis di dalam domain model, agar kode benar-benar mencerminkan pemikiran bisnis.</p><h3>Full Domain Model</h3><p>Dalam DDD, domain model penuh, istilah aslinya adalah &#8220;Rich Domain Model&#8221; atau &#8220;Full-Fledged Domain Model&#8221;.</p><blockquote><p>Definisi: &#8220;A rich domain model is one where domain objects encapsulate both data and behavior, enforcing business rules internally.&#8221;<br>&#8212; <em>Evans, Domain-Driven Design, 2004.</em></p></blockquote><p>Bedanya dengan <em>anemic domain model berdasarkan karakteristik</em>:</p><ul><li><p>Rich (Full) Domain Model</p><ul><li><p>Data dan perilaku: Digabung di entitas.</p></li><li><p>Aturan Bisnis: Ditegakkan di dalam entitas.</p></li><li><p>Keterwakilan domain: Kuat, selaras dengan bahasa bisnis.</p></li><li><p>Cocok untuk: Core subdomain.</p></li></ul></li><li><p>Anemic Domain Model</p><ul><li><p>Data dan perilaku: Terpisah.</p></li><li><p>Aturan Bisnis: Tersebar di service luar.</p></li><li><p>Keterwakilan domain: Lemah, cenderung CRUD.</p></li><li><p>Cocok untuk: Supporting/generic subdomain.</p></li></ul></li></ul><p>Jadi ketika Khononov menulis bahwa &#8220;core subdomain seharusnya memiliki <em>domain model penuh</em>&#8221;, maksudnya adalah:</p><p>Subdomain yang menjadi keunggulan utama bisnis harus diimplementasikan dengan <em>rich domain model</em>, agar aturan bisnis dan konsep bisnis benar-benar hidup di dalam kode, bukan di spreadsheet, dokumen, atau service-service longgar.</p><h3>Domain Model Berdasarkan Pola yang Cocok</h3><p>Ada spektrum kompleksitas yang mempengaruhi pemilihan domain model yang cocok:</p><ul><li><p>Kondisi domain sangat sederhana (ETL, batch job, CRUD data referensi)</p><ul><li><p>Pola yang cocok: Transaction Script.</p></li><li><p>Karena tidak perlu model atau logika kompleks.</p></li></ul></li><li><p>Kondisi domain sederhana tapi punya struktur data berelasi</p><ul><li><p>Pola yang cocok: Active Record.</p></li><li><p>Karena sedikit OO, tapi mudah dan cepat.</p></li></ul></li><li><p>Kompleks dengan aturan bisnis yang dinamis</p><ul><li><p>Pola yang cocok: Rich Domain Model.</p></li><li><p>Karena logika terpusat di entitas &amp; aggregate.</p></li></ul></li><li><p>Butuh audit / histori</p><ul><li><p>Pola yang cocok: Event-Sourced Domain Model.</p></li><li><p>Karena Domain Model + Event Sourcing.</p></li></ul></li></ul><h2>Melihat Kembali Subdomain Pendukung (supporting subdomain)</h2><p>Di atas banyak dibahas bahwa keduanya terbatas pada logika sederhana di subdomain pendukung. Kita lihat kembali klasifikasi subdomain pada DDD (Khononov, 2022):</p><ul><li><p>Core Subdomain</p><ul><li><p>Karakteristik: Menjadi sumber keunggulan kompetitif bisnis. Kompleks, sering berubah, butuh inovasi tinggi.</p></li><li><p>Fokus solusi: Perlu desain DDD mendalam, domain model penuh, investasi besar.</p></li></ul></li><li><p>Supporting Subdomain</p><ul><li><p>Karakteristik: Mendukung operasional inti, tapi tidak membedakan bisnis dari kompetitor. Biasanya sederhana.</p></li><li><p>Fokus solusi: Gunakan solusi pragmatis (Transaction Script, Active Record, atau framework siap pakai)</p></li></ul></li><li><p>Generic Subdomain</p><ul><li><p>Karakteristik: Umum dipakai semua bisnis (contoh: autentikasi, log aktivitas).</p></li><li><p>Fokus solusi: Lebih baik dibeli atau pakai library standar.</p></li></ul></li></ul><p>Sederhananya:</p><ul><li><p><em>Supporting subdomain</em> masih penting untuk bisnis, tapi tidak menentukan keberhasilan utama.</p></li><li><p>Karena kompleksitasnya rendah dan nilai strategisnya kecil, maka kita tidak perlu investasi arsitektur rumit seperti Domain Model penuh.</p></li><li><p>Inilah kenapa <em>Transaction Script</em> dan <em>Active Record</em> cocok: cepat dibuat, mudah dipelihara, cukup stabil.</p></li></ul><p>Sebaliknya, <em>core subdomain</em> biasanya punya banyak aturan bisnis, ketergantungan lintas fungsi, dan terus berubah.</p><h3>Data &amp; Logika Bisnis</h3><p>Pernyataan &#8220;pemisahan antara data dan logika bisnis&#8220; ini sering muncul dalam konteks arsitektur software, misalnya <em>Separation of Concerns</em>.</p><p>Artinya: Data (apa yang disimpan) dan logika bisnis (apa yang dilakukan terhadap data itu) tidak seharusnya bercampur dalam satu tempat.</p><p>Contoh salah:</p><pre><code><code>fn save_order_to_db(order_id: u32, total: f64) {
    // ... query ke DB ...
    if total &gt; 1000000.0 {
        // logika bisnis diselipkan di sini
        println!(&#8221;Diskon 10%&#8221;);
    }
}
</code></code></pre><p>Contoh benar:</p><pre><code><code>struct Order {
    id: u32,
    total: f64,
}

impl Order {
    fn apply_discount(&amp;mut self) {
        if self.total &gt; 1000000.0 {
            self.total *= 0.9;
        }
    }
}

fn save_order_to_db(order: &amp;Order) {
    // hanya urusan penyimpanan
}
</code></code></pre><p>Pada contoh benar, fungsi <code>save_order_to_db()</code> hanya fokus pada <strong>data persistence</strong>, sedangkan <code>apply_discount()</code> berisi <strong>logika bisnis</strong>.<br>Keduanya terpisah untuk memudahkan pengujian, refaktor, dan perubahan aturan bisnis tanpa merusak cara penyimpanan data.</p><p>Pemisahan antara data, logika bisnis, dan presentasi adalah prinsip dasar arsitektur aplikasi, sering disebut sebagai <strong>three-layer (or three-tier) architecture</strong>.</p><ul><li><p>Presentation layer</p><ul><li><p>Tugas utama: Menampilkan data kepada pengguna dan menerima input.</p></li><li><p>Contoh dalam aplikasi: Antarmuka pengguna (UI), web page, REST API endpoint, CLI.</p></li></ul></li><li><p>Business Logic layer</p><ul><li><p>Tugas utama: Menjalankan aturan dan keputusan bisnis.</p></li><li><p>Contoh dalam aplikasi: Fungsi domain, service, entitas, aggregate.</p></li></ul></li><li><p>Data Access layer atau Persistence Layer</p><ul><li><p>Tugas utama: menyimpan dan mengambil data.</p></li><li><p>Contoh dalam aplikasi: Database, ORM, repository.</p></li></ul></li></ul><p>Dalam konteks arsitektur, &#8220;presentation layer&#8221; mencakup <em>segala sesuatu yang berhubungan dengan interaksi pengguna atau sistem lain. </em>Misalnya:</p><ul><li><p>UI web atau mobile,</p></li><li><p>API endpoint (yang melayani HTTP request),</p></li><li><p>atau bahkan CLI untuk admin.</p></li></ul><p>Presentasi <em>tidak boleh</em> tahu detail logika bisnis, cukup memanggil fungsinya saja.<br>Contoh:</p><pre><code><code>// presentation layer
fn handle_checkout_request(user_input: CheckoutData) {
    let mut order = Order::new(user_input.items);
    order.apply_discount(); // business logic
    repository::save(order); // data layer
}
</code></code></pre><p>Ketiganya punya tanggung jawab berbeda:</p><ul><li><p>Presentation layer: berbicara dengan pengguna atau sistem lain.</p></li><li><p>Business logic layer: memutuskan apa yang boleh atau harus terjadi.</p></li><li><p>Data layer: mengelola penyimpanan (database, cache, dsb).</p></li></ul><p>Prinsip ini disebut <strong>Separation of Concerns</strong>: memisahkan tanggung jawab agar sistem lebih modular dan mudah berkembang.</p><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Mengintegrasikan Bounded Contexts]]></title><description><![CDATA[Meski disebut bounded, konteks-konteks yang berbeda, meskipun penyebutannya, tidak boleh jalan sendiri-sendiri: mereka harus saling berinteraksi untuk mencapai tujuan sistem secara keseluruhan.]]></description><link>https://www.0-1.my.id/p/mengintegrasikan-bounded-contexts</link><guid isPermaLink="false">https://www.0-1.my.id/p/mengintegrasikan-bounded-contexts</guid><dc:creator><![CDATA[oon arfiandwi]]></dc:creator><pubDate>Mon, 13 Oct 2025 15:21:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!VNtl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Meski disebut <em>bounded</em>, konteks-konteks yang berbeda, meskipun penyebutannya, tidak boleh jalan sendiri-sendiri: mereka harus <strong>saling berinteraksi</strong> untuk mencapai tujuan sistem secara keseluruhan. Interaksi itu diwujudkan lewat <em>kontrak</em>, titik temu di mana satu konteks menggunakan output dari konteks lain. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VNtl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VNtl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!VNtl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!VNtl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!VNtl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VNtl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VNtl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!VNtl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!VNtl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!VNtl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2dee6ab-30d1-4c9f-8448-e398450ff5e8_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Mengintegrasikan Bounded Contexts.</figcaption></figure></div><p>Tergantung pada hubungan tim pengembangnya, DDD mengenalkan beberapa pola integrasi bounded context:</p><ul><li><p><strong>Partnership</strong> (Kerjasama Dua Arah): Dua tim berkolaborasi erat, saling bantu menyesuaikan antarmuka jika dibutuhkan. Tidak ada pihak yang memaksakan modelnya; setiap perubahan disepakati atau dinegosiasikan bersama. Pola ini memerlukan komunikasi intensif dan mungkin <em>Continuous Integration</em> agar tiap perubahan cepat diuji bersama.</p></li><li><p><strong>Shared Kernel</strong>: Dua atau lebih bounded context berbagi sebagian model yang sama (misalnya model otorisasi pengguna). Perubahan di bagian bersama (kernel) langsung memengaruhi semua konteks. Oleh karena itu, hanya fitur inti yang benar-benar perlu yang sebaiknya digabungkan di sini, biasanya berupa kontrak integrasi atau struktur data bersama. Untuk implementasi, kode bersama bisa diletakkan di satu modul yang di-<em>link</em> oleh setiap konteks. Setiap perubahan mesti diuji secara lintas-konteks agar tidak ada yang rusak.</p></li></ul><p>Kelompok berikutnya adalah <strong>Customer&#8211;Supplier</strong>, hubungan satu arah dengan tim penyuplai (supplier) dan tim pelanggan (customer):</p><ul><li><p><strong>Conformist</strong>: Tim supplier mendikte modelnya dan tim pelanggan <em>mengikuti begitu saja</em>. Misalnya, jika API yang disediakan rekanan sudah baku, tim kita mungkin cuma mengonsumsi mentah-mentah data itu tanpa negosiasi. Pola ini tidak memerlukan adaptasi besar; tim pelanggan menerima persyaratan supplier seperti adanya. Biasanya cocok untuk model standar industri yang <em>cukup baik</em> dan tidak ingin diubah.</p></li><li><p><strong>Anticorruption Layer (ACL)</strong>, Jika tim supplier <em>berkuasa penuh</em>, tetapi modelnya tidak cocok atau sering berubah (misal sistem warisan dengan schema kacau), tim pelanggan bisa membuat lapisan perantara (translator) yang menerjemahkan model supplier ke model sendiri. Misalnya, jika subdomain kita termasuk inti yang rumit, kita tidak mau ikut-ikutan merusak modelnya. Atau jika kontrak sering berubah, ACL menjaga agar perubahan itu hanya mengganggu translator, bukan seluruh sistemnya. Intinya, ACL <em>mengisolasi</em> konteks kita dari istilah asing dan membuat model kita lebih bersih sesuai kebutuhan.</p></li><li><p><strong>Open-Host Service</strong>: Kebalikan dari ACL, di sini supplier <em>melindungi</em> pelanggannya. Supplier membuat model publik (<em>published language</em>) yang nyaman bagi konsumen, lalu menjembatani model internalnya ke model publik tersebut. Dengan begitu, supplier dapat mengubah model internalnya tanpa mengganggu konsumen, asalkan masih menerjemahkannya ke bahasa publik yang sudah ditetapkan. Pola ini sering digunakan jika supplier ingin memberi layanan yang stabil bagi banyak konsumen sekaligus.</p></li></ul><p>Terakhir, ada pola <strong>Separate Ways</strong>, dua tim memutuskan <em>tidak berkolaborasi sama sekali</em>. Ini bukan ideal, tapi bisa terjadi karena berbagai alasan. Misalnya, jika komunikasi antar tim sangat sulit (pemisahan geografis atau politik internal), lebih murah menyalin fungsionalitas di kedua sisi daripada memaksakan integrasi. Atau jika yang ingin dibagikan adalah subdomain <em>generik</em> (seperti logging, notifikasi, dll), mungkin lebih simpel setiap tim melokalkan solusinya sendiri daripada bikin satu layanan terpusat. Juga, jika model di kedua sisi benar-benar berbeda sehingga ACL atau Conformist menjadi mahal atau tidak mungkin, tim bisa memilih Duplicate (Separate Ways). <br><strong>Peringatan:</strong> pola ini <strong>tidak boleh</strong> dipakai untuk subdomain inti perusahaan, karena menyalin inti bisnis berarti merugi, kita kehilangan optimasi dan konsistensi yang seharusnya menjadi sumber keunggulan.</p><p>Setelah semua hubungan integrasi ini terdefinisi, kita dapat menggambarnya dalam <strong>context map</strong>, peta visual bounded context beserta tipe integrasi antaranya. Context map ini memberikan wawasan strategis tinggi: apa saja komponen besar sistem, siapa bermitra dengan siapa, siapa yang mandiri atau bahkan memisahkan diri, dan pola komunikasi seperti apa yang terjadi antar tim. <br>Misalnya, sebuah panah &#8216;anticorruption layer&#8217; dari tim A ke B menunjukkan tim A memakai ACL terhadap tim B. Context map sebaiknya disusun sejak awal proyek dan terus diperbarui bersama tim &#8211; misalnya setiap tim bertanggung jawab menjaga gambaran integrasi kontekstualnya tetap up-to-date.</p><p>Diulang kembali secara singkat, berikut pola-pola utama integrasi bounded context dalam DDD (Khononov, 2022):</p><ul><li><p><strong>Partnership:</strong> Integrasi ad hoc dengan komunikasi dua arah.</p></li><li><p><strong>Shared Kernel:</strong> Dua konteks berbagi potongan model yang konsisten.</p></li><li><p><strong>Conformist:</strong> Konsumen <em>menyesuaikan diri</em> dengan model penyedia layanan.</p></li><li><p><strong>Anticorruption Layer:</strong> Konsumen membuat lapisan penerjemah agar model penyedia tidak merusak model internalnya.</p></li><li><p><strong>Open-Host Service:</strong> Penyedia menyiapkan antarmuka publik agar konsumennya nyaman, sementara detail internal tetap fleksibel.</p></li><li><p><strong>Separate Ways:</strong> Dua tim bekerja terpisah, setiap konteks menduplikasi kebutuhan umum agar integrasi tidak diperlukan.</p></li></ul><p>Peta konteks (<em>context map</em>) menggambarkan semua ini secara keseluruhan. Dengan memahami pola-pola integrasi ini, kita dapat menyelaraskan desain teknis dengan struktur organisasi dan strategi bisnis yang ada.</p><h2><strong>Referensi</strong></h2><p>Khononov, V. (2022). <em>Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy</em>. O&#8217;Reilly Media.</p>]]></content:encoded></item></channel></rss>