<?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[Dev Details]]></title><description><![CDATA[Big-picture software architecture, low-level details, and how they're entangled.]]></description><link>https://blog.devdetails.com</link><image><url>https://substackcdn.com/image/fetch/$s_!zMus!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png</url><title>Dev Details</title><link>https://blog.devdetails.com</link></image><generator>Substack</generator><lastBuildDate>Fri, 17 Apr 2026 07:18:52 GMT</lastBuildDate><atom:link href="https://blog.devdetails.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Dev Details]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[devdetails@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[devdetails@substack.com]]></itunes:email><itunes:name><![CDATA[Mike]]></itunes:name></itunes:owner><itunes:author><![CDATA[Mike]]></itunes:author><googleplay:owner><![CDATA[devdetails@substack.com]]></googleplay:owner><googleplay:email><![CDATA[devdetails@substack.com]]></googleplay:email><googleplay:author><![CDATA[Mike]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Binary search finds things fast]]></title><description><![CDATA[I wrote a small interactive book to teach binary search.]]></description><link>https://blog.devdetails.com/p/binary-search-finds-things-fast</link><guid isPermaLink="false">https://blog.devdetails.com/p/binary-search-finds-things-fast</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Tue, 13 Aug 2024 07:55:55 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ea27225a-0724-419a-9925-4429a8423f98_1440x1440.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Binary search is an algorithm that finds things fast.</p><p>When I was twelve and didn't know programming, my dad taught me about binary search. His explanation was so simple that it stuck with me.</p><p>I wrote a small interactive book to teach binary search the way he taught me. </p><p>The Binary Search Handbook is short and teaches by example. </p><p>First, download the book and try it for yourself. It will help illustrate the topics below.</p><p>In this post, I'll explain binary search in more detail.</p><div class="file-embed-wrapper" data-component-name="FileToDOM"><div class="file-embed-container-reader"><div class="file-embed-container-top"><image class="file-embed-thumbnail" src="https://substackcdn.com/image/fetch/w_400,h_600,c_fill,f_auto,q_auto:best,fl_progressive:steep,g_auto/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4c65238-d391-404e-ab47-5546379a205d_1152x1728.jpeg"></image><div class="file-embed-details"><div class="file-embed-details-h1">Binary Search Handbook</div><div class="file-embed-details-h2">1.13MB &#8729; PDF file</div></div><a class="file-embed-button wide" href="https://blog.devdetails.com/api/v1/file/687049a8-abc8-49f8-a802-9f9df5bec882.pdf"><span class="file-embed-button-text">Download</span></a></div><div class="file-embed-description">Learn binary search by playing a game with this book.</div><a class="file-embed-button narrow" href="https://blog.devdetails.com/api/v1/file/687049a8-abc8-49f8-a802-9f9df5bec882.pdf"><span class="file-embed-button-text">Download</span></a></div></div><p></p><h2>What is binary search?</h2><p>Binary search is an efficient algorithm for finding an item's position in a sorted array. It works by dividing the search range in half multiple times.</p><p>The array must be sorted for binary search to work.</p><p>The search begins in the middle of the array. If the target value matches the middle element, the search ends.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MSxM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MSxM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png 424w, https://substackcdn.com/image/fetch/$s_!MSxM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png 848w, https://substackcdn.com/image/fetch/$s_!MSxM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png 1272w, https://substackcdn.com/image/fetch/$s_!MSxM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MSxM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png" width="549" height="102" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:102,&quot;width&quot;:549,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6835,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!MSxM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png 424w, https://substackcdn.com/image/fetch/$s_!MSxM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png 848w, https://substackcdn.com/image/fetch/$s_!MSxM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png 1272w, https://substackcdn.com/image/fetch/$s_!MSxM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bcdf63b-8b51-4052-9c54-07b605481195_549x102.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div><hr></div><p>If the target value is less than the middle value, the search moves to the left half.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!koXe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!koXe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png 424w, https://substackcdn.com/image/fetch/$s_!koXe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png 848w, https://substackcdn.com/image/fetch/$s_!koXe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png 1272w, https://substackcdn.com/image/fetch/$s_!koXe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!koXe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png" width="550" height="275" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:275,&quot;width&quot;:550,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17240,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!koXe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png 424w, https://substackcdn.com/image/fetch/$s_!koXe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png 848w, https://substackcdn.com/image/fetch/$s_!koXe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png 1272w, https://substackcdn.com/image/fetch/$s_!koXe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff8622dd-ce89-47f2-8fd5-b796b04fcb22_550x275.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div><hr></div><p>If the target value is higher than the middle value, the search moves to the right half.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CzB5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CzB5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png 424w, https://substackcdn.com/image/fetch/$s_!CzB5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png 848w, https://substackcdn.com/image/fetch/$s_!CzB5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png 1272w, https://substackcdn.com/image/fetch/$s_!CzB5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CzB5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png" width="549" height="263" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8f64931d-8a7b-4172-87df-674a12148834_549x263.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:263,&quot;width&quot;:549,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16959,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!CzB5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png 424w, https://substackcdn.com/image/fetch/$s_!CzB5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png 848w, https://substackcdn.com/image/fetch/$s_!CzB5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png 1272w, https://substackcdn.com/image/fetch/$s_!CzB5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f64931d-8a7b-4172-87df-674a12148834_549x263.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div><hr></div><p>This process continues until it finds the target or nothing is left to search.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!897F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!897F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png 424w, https://substackcdn.com/image/fetch/$s_!897F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png 848w, https://substackcdn.com/image/fetch/$s_!897F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png 1272w, https://substackcdn.com/image/fetch/$s_!897F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!897F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png" width="549" height="289" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:289,&quot;width&quot;:549,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17414,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!897F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png 424w, https://substackcdn.com/image/fetch/$s_!897F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png 848w, https://substackcdn.com/image/fetch/$s_!897F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png 1272w, https://substackcdn.com/image/fetch/$s_!897F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94cd5c4a-38e4-49dc-bb09-cda18936dabe_549x289.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div><hr></div><h2>Use Cases</h2><p>Binary search is useful for cases like:</p><ul><li><p><strong>Checking if a value is in a sorted array</strong>: Determine if a specific element exists in a sorted list.</p></li><li><p><strong>Finding the first occurrence of a value</strong>: Locate the first instance of a target value in a sorted array with or without duplicates.</p></li><li><p><strong>Finding the insertion point</strong>: Identify the correct index to insert a new element to maintain order.</p></li></ul><h2>Finding a word in a dictionary</h2><p>Finding a word in a dictionary is a great use case for binary search. The Binary Search Handbook illustrates this. A dictionary is a sorted list of words spread across many pages in a book. Let's see how binary search helps find a specific word.</p><p>Imagine you have a printed dictionary with thousands of words. Instead of checking each word one by one, binary search lets you find your word in just a few steps.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.devdetails.com/subscribe?"><span>Subscribe now</span></a></p><h3>Step 1: Start in the Middle</h3><p>Open your dictionary to the middle page. Let's say the dictionary has 300 pages. Open to page 150. This is your starting point.</p><h3>Step 2: Ask a Simple Question</h3><p>Look at the first word on page 150 and ask, "Is the word I'm looking for before this word?" This yes/no question eliminates half of the search results. If the answer is yes, you only have to search the first half. If the answer is no, you only have to search the last half.</p><h3>Step 3: Halve Your Search</h3><p>Based on the answer, you either move to the middle of the first half or the second half of the dictionary. If the word is after page 150, go to the middle of the second half, page 225. If it&#8217;s before, go to the middle of the first half, page 75.</p><h3>Repeat Until You Find It</h3><p>Repeat this process: go to the middle of your current section and ask the same yes/no question. Each time, you cut the number of pages to search in half. This is the power of binary search.</p><p>Within a few guesses, you'll have only one page left. This is the page with your word. You can take this further and find the exact line with your word.</p><p>First, go to the middle of the page and ask the question. Depending on the answer, your word is on the top or bottom half of the page. Each time, you cut the number of words to search on the page in half. Repeat until there is only one word left.</p><h3>Why It Works</h3><p>Binary search is efficient because it reduces the number of pages to check by a large margin. Instead of looking through 300 pages, you can find the page in about 8 steps. That&#8217;s because each step narrows down the possibilities by half.</p><p><code>number&nbsp;of&nbsp;steps = log2&#8203;(n)</code></p><h3>A Fun Example</h3><p>You can find a word you don't know using the same process. You only need a function to answer the question, "Is it before this?"</p><p>You can use this trick to find a word a friend is thinking of in a dictionary without them telling you the word. All they have to do is answer, "Is it before this?"</p><h2>Big-O</h2><ul><li><p><code>O(log n)</code> time complexity &#8211; Binary search halves the array each time. So, the maximum number of comparisons needed is the logarithm (base 2) of the number of elements.</p></li><li><p><code>O(1)</code> space complexity &#8211; Binary search uses the same amount of extra memory regardless of the input array size. It operates in place, only using a few extra variables to keep track of the search range.</p></li></ul><h2>Binary Search Tree</h2><p>Binary search is an algorithm. Its cousin data structure is a Binary Search Tree (BST).</p><p>Binary search is great for static, sorted arrays. However, if you insert items into the array, you must resort. Sorting an array is expensive, with an <code>O(n log n)</code> to <code>O(n&#178;)</code> complexity.</p><p>A Binary Search Tree fixes this by maintaining elements in sorted order. Each node in a BST has up to two children. The <code>left</code> child contains values less than the parent node. The <code>right</code> child contains values greater than the parent node. This structure ensures searches, inserts, and deletes perform in <code>O(log n)</code> time on average.</p><h3>When to use Binary Search vs Binary Search Tree</h3><ul><li><p><strong>Static Data (Binary Search)</strong>: If the data is static (i.e., it doesn't change), a binary search on a sorted array is more efficient. The overhead of creating a BST is usually greater than sorting and searching a static array.</p></li><li><p><strong>Dynamic Data (BST)</strong>: A BST is more efficient for dynamic datasets with frequent inserts or deletes. BSTs provide efficient <code>O(log n)</code> time complexity for operations. This is more efficient than repeatedly sorting an array for binary search.</p></li></ul><h2>That&#8217;s it.</h2><p>Binary search is a simple yet powerful algorithm. A code example is at the end of this article.</p><p>If you enjoyed the Binary Search Handbook, consider sharing it with someone who might be interested in programming.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/p/binary-search-finds-things-fast?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.devdetails.com/p/binary-search-finds-things-fast?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2>What I&#8217;m reading</h2><ul><li><p>I often take on more work than I should. <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Jordan Cutler&quot;,&quot;id&quot;:58854493,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fe86d99-af64-4285-b982-9466a4c58d63_1311x1312.jpeg&quot;,&quot;uuid&quot;:&quot;1f555b5e-d754-4957-af4c-99c649a817bd&quot;}" data-component-name="MentionToDOM"></span> and <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Sidwyn Koh&quot;,&quot;id&quot;:321369,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7bc8b98-4c12-42ce-8720-5bb3cc6f6647_2100x2100.jpeg&quot;,&quot;uuid&quot;:&quot;4cc2186b-4bc1-44cc-abec-6c4f46018244&quot;}" data-component-name="MentionToDOM"></span> wrote some tips to help with that in <a href="https://read.highgrowthengineer.com/p/how-to-say-no-and-win-back-your-time?r=lae64&amp;utm_campaign=post&amp;utm_medium=web">How to say "No" and win back your time as a software engineer</a>.</p></li><li><p><a href="https://read.developingskills.fyi/p/dont-criticise?r=lae64&amp;utm_campaign=post&amp;utm_medium=web">Don&#8217;t Criticise</a> and <a href="https://read.developingskills.fyi/p/you-are-wrong?r=lae64&amp;utm_campaign=post&amp;utm_medium=web">YOU ARE WRONG!</a> are great contradictory titles from <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;John Crickett&quot;,&quot;id&quot;:27801024,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5216b4ab-f9a8-4803-b318-a8285e26a873_800x800.jpeg&quot;,&quot;uuid&quot;:&quot;2c98d67c-f781-4d53-99c0-c009078830af&quot;}" data-component-name="MentionToDOM"></span>. They&#8217;ll both help you correct people without offending them.</p></li><li><p>In <a href="https://mahopacheco.substack.com/p/glue-work-the-hidden-hero-of-team">Glue Work: The Hidden Hero of Team Success</a>, <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Maho Pacheco&quot;,&quot;id&quot;:74588628,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ebee7e1-c261-4c33-864b-96e10b5cef50_500x500.jpeg&quot;,&quot;uuid&quot;:&quot;50c9dda1-a985-4f91-870a-cc9a80516b04&quot;}" data-component-name="MentionToDOM"></span> highlights those who work on often-overlooked tasks that hold a team together.</p></li></ul><h2>Example code</h2><p>I've provided an example Python binary search implementation below. This should illustrate how a binary search algorithm works.</p><p>Python has efficient built-in functions, such as <a href="https://docs.python.org/3/tutorial/datastructures.html">list.index</a>, to find positions of a value in a list and <a href="https://docs.python.org/3/library/bisect.html">bisect</a> for binary search operations. You should use those instead of making your own.</p><p>This type of algorithm is generally called a &#8220;two-pointer&#8221;. That&#8217;s because it has two pointers, left and right, representing the bounds of the search window.</p><pre><code><code>def binary_search(items: list[int], target: int) -&gt; int:
    # The left and right pointers represent the bounds 
    # of our search window.
    # Initialize them to the entire index range.
    # For example, if the initial list is 
    # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    # It starts with left=0, right=9 and looks like this:
    # [&gt;0 1 2 3 4 5 6 7 8 9&lt;]
    left, right = 0, len(items) - 1

    # Continue searching while there is a valid range.
    # The loop stops when left is greater than right,
    # meaning the target is not within the range.
    while left &lt;= right:
        # Calculate the middle index by cutting the
        # current search window in half.
        middle = (left + right) // 2

        # The first time around, left=0, right=9, middle=4
        # [&gt;0 1 2 3(4)5 6 7 8 9&lt;]

        # If the middle element is the target, return its index.
        if items[middle] == target:
            return middle
        # If the target is greater than the middle element,
        # narrow the search range to the right half.
        elif items[middle] &lt; target:
            left = middle + 1
            # The first time around, left=5, right=9, middle=4
            # [ 0 1 2 3(4&gt;5 6 7 8 9&lt;]
        # If the target is less than the middle element,
        # narrow the search range to the left half.
        else:
            right = middle - 1
            # The first time around, left=0, right=3, middle=4
            # [&gt;0 1 2 3&lt;4)5 6 7 8 9]

    # If the target is not found in the array, return -1.
    return -1

assert binary_search([1, 2, 3, 4, 5], 3) == 2
assert binary_search([1, 2, 3, 4, 5], 1) == 0
assert binary_search([1, 2, 3, 4, 5], 5) == 4
assert binary_search([1, 2, 3, 4, 5], 6) == -1
assert binary_search([], 3) == -1
assert binary_search([1], 1) == 0
assert binary_search([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 7) == 6
assert binary_search([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2) == 1
assert binary_search([1, 3, 5, 7, 9], 4) == -1</code></code></pre>]]></content:encoded></item><item><title><![CDATA[Design is about the abstractions]]></title><description><![CDATA[Abstractions simplify designs and tell us when to stop designing.]]></description><link>https://blog.devdetails.com/p/design-is-about-the-abstractions</link><guid isPermaLink="false">https://blog.devdetails.com/p/design-is-about-the-abstractions</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Mon, 05 Aug 2024 15:55:48 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6oNv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Before getting into software engineering, <a href="https://blog.devdetails.com/p/i-wanted-to-design-buildings-but">I was on my way to becoming a house designer</a>. <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Jordan Cutler&quot;,&quot;id&quot;:58854493,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fe86d99-af64-4285-b982-9466a4c58d63_1311x1312.jpeg&quot;,&quot;uuid&quot;:&quot;db3ee6ec-ea12-4b90-8ce2-72456ee1dcf9&quot;}" data-component-name="MentionToDOM"></span> asked what lessons from house design I apply to software architecture.</p><p>You can read my reply and the lessons on <a href="https://read.highgrowthengineer.com/p/home-architect-lessons-on-software-design">Jordan's High Growth Engineer</a>. I cover the things I noticed software engineers struggle with the most:</p><ul><li><p>Knowing what to design</p></li><li><p>Dealing with unclear requirements</p></li><li><p>How much detail to put in a design</p></li></ul><div><hr></div><h2>From software back to house design</h2><p>This post is about a concept from software that reshaped my perspective on building design.</p><p>I learned about abstraction from software engineering. When I apply the concept to house design, I see many abstractions within houses. In fact, abstractions and standardization are what make modern construction possible.</p><p>Abstractions also give us the solution to another challenge with software design: <strong>when to stop designing.</strong></p><p>When to stop designing relates to <a href="https://read.highgrowthengineer.com/p/home-architect-lessons-on-software-design">how much detail we design</a>. When you've put enough detail, you're done. But how can you reduce the required level of detail to speed up the completion of designs?</p><p>Abstractions simplify designs if we:</p><ul><li><p>Design at boundaries and encapsulate details.</p></li><li><p>Get the API right and allow inner details to change during implementation.</p></li><li><p>Stop when we've covered all the abstractions.</p></li></ul><h2>Abstractions in the home</h2><p>What abstractions do houses have?</p><ul><li><p>Doors and windows</p></li><li><p>Electrical sockets and light fixtures</p></li><li><p>Appliances like stoves and ovens</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6oNv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6oNv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png 424w, https://substackcdn.com/image/fetch/$s_!6oNv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png 848w, https://substackcdn.com/image/fetch/$s_!6oNv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png 1272w, https://substackcdn.com/image/fetch/$s_!6oNv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6oNv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png" width="1456" height="754" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:754,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:200418,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!6oNv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png 424w, https://substackcdn.com/image/fetch/$s_!6oNv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png 848w, https://substackcdn.com/image/fetch/$s_!6oNv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png 1272w, https://substackcdn.com/image/fetch/$s_!6oNv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fceec73d4-92a8-4467-b548-1845e80c333c_2051x1062.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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>These abstractions have an expected way of working. There is a standard way to create and use them.</p><h2>Electricity as a service</h2><p>We can apply the lessons of how house design uses abstractions back to software design. Take, for example, electrical sockets.</p><p>The socket is an interface that provides the service of "electricity." Power delivery to a house has many details:</p><ul><li><p>Wires</p></li><li><p>Breaker boxes</p></li><li><p>Power poles</p></li><li><p>Distribution nodes</p></li><li><p>Power plants</p></li><li><p>Fuel</p></li></ul><p>Electrical sockets are interchangeable interfaces. Anything implementing the interface can get power. Thousands of devices work simply because they implement the socket interface and protocol.</p><p>As a homeowner, you don't care about these details. You plug a device into the socket, and it runs. You care that outlets are near furniture and have enough power to run everything.</p><p>You don't care about any of that as a house designer, either. You only care how an electrical socket functions and serves the homeowner. You know the value it provides, and you describe where to place them.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Abstractions hide complexity</h2><p>The same is true for software. <strong>Users don&#8217;t care about the complexity or technology behind it.</strong> They don't think about how they're using an abstraction (a UI, a button, an API) or the fundamentals of how it works. They just know that using the interface gives them the desired behavior.</p><p><strong>Standards and abstractions make it so you only need to design where to put the socket&#8212;not what it is.</strong>&nbsp;</p><p>As designers of software or houses, we only need to define abstractions and interactions&#8212;not the internal details.</p><p>Abstractions are reusable and interchangeable building blocks. They limit the concepts a designer and builder need to know. This complexity-hiding is what makes them perfect for simplifying designs. <strong>Designers only need to consider the details that they can't ignore.</strong> The builder can figure out and adapt the rest of the details.</p><p>When designing software or houses, focus on which abstractions to use and how they interact. Designing the interface is more important than the internal details.</p><p>For example, when we describe a new part of a complex system, we do not need to explain how the other parts work. We focus on the new component and treat all the existing components as abstractions.</p><p>Say we want to add a Project component. The existing Payments and Database components are abstractions. In the design, we don&#8217;t need to know how they work. Only the APIs that support customer requirements are important.</p><ul><li><p>How will users interact with Projects?</p></li><li><p>How will Projects interact with the Database?</p></li><li><p>How will users pay for Projects?</p></li></ul><p>The Projects component itself is an abstraction. The API (HTTP port or code interface) is like the electrical socket. The details of how it works within the boundary are irrelevant to the design. </p><h2>When to stop designing</h2><p>What's important is describing the interactions at the boundaries:</p><ul><li><p>Describe interactions between components using API documentation formats like OpenAPI.</p></li><li><p>Describe complex order of operations with sequence or flow diagrams.</p></li></ul><p>Those who build it have the flexibility to figure out the inner details.</p><p>You only have to design the internals of an abstraction if it is novel. Even then, you only have to design it enough so that the builder understands the interactions.</p><p>We stop designing when:</p><ul><li><p>We've identified all the abstractions.</p></li><li><p>Everyone understands how they interact.</p></li></ul><p>There is usually no need to go deeper. <strong>The design is good enough to move forward.</strong> </p><p>But it isn&#8217;t finished. As the building progresses, new issues will arise. Update the design with any significant changes as they occur.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/p/design-is-about-the-abstractions?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thank you for reading Dev Details.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/p/design-is-about-the-abstractions?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.devdetails.com/p/design-is-about-the-abstractions?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><h2>What I&#8217;m reading</h2><ul><li><p><span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Micha&#322; Poczwardowski&quot;,&quot;id&quot;:141222242,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F475838ea-8fbf-473b-9678-ea792c061ede_764x784.jpeg&quot;,&quot;uuid&quot;:&quot;7f46c7b4-fa80-4bf7-bc86-0ed08610f1bf&quot;}" data-component-name="MentionToDOM"></span> has a good physics analogy for software: <a href="https://read.perspectiveship.com/p/entropy?r=lae64&amp;utm_campaign=post&amp;utm_medium=web">Entropy - Mental Model</a>. </p></li><li><p><a href="https://newsletter.eng-leadership.com/p/how-to-propose-an-impactful-improvement?r=lae64&amp;utm_campaign=post&amp;utm_medium=web">How to propose an impactful improvement to the codebase and own the implementation</a> by <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Gregor Ojstersek&quot;,&quot;id&quot;:106098672,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1b7fdc30-d8c4-45f2-b0df-0b60baf9d4f4_1000x1000.jpeg&quot;,&quot;uuid&quot;:&quot;4c0b0724-fc88-4508-934c-089727015384&quot;}" data-component-name="MentionToDOM"></span> delivers on its title.</p></li><li><p><span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Neo Kim&quot;,&quot;id&quot;:135589200,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c103940f-0d8b-47e7-9a33-013202e17bb8_389x389.jpeg&quot;,&quot;uuid&quot;:&quot;26443ff2-1cfb-4a3f-8f0e-2405b385d768&quot;}" data-component-name="MentionToDOM"></span> explains Chaos Monkey in <a href="https://newsletter.systemdesign.one/p/chaos-engineering?r=lae64&amp;utm_campaign=post&amp;utm_medium=web">How Netflix Uses Chaos Engineering to Create Resilience Systems &#128018;</a></p><p></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Monoliths, microservices, and serverless aren't what you think they are]]></title><description><![CDATA[Or are they?]]></description><link>https://blog.devdetails.com/p/monoliths-microservices-and-serverless</link><guid isPermaLink="false">https://blog.devdetails.com/p/monoliths-microservices-and-serverless</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Fri, 19 Jan 2024 05:42:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_i0t!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Can you identify a monolithic pattern vs. microservices? microservices vs. serverless?</p><p>Technology terms evolve over time. Sometimes, the meaning is stuck in the past. Sometimes, not everyone has caught up with the current interpretation. Sometimes, the meaning is mired by misconceptions.</p><ol><li><p>Is it a monolith?</p></li><li><p>Are they microservices?</p></li><li><p>Is it serverless?</p></li></ol><p>For each one below, take a look at the diagram and consider the question. Then, consider my take (apologies in advance for the LinkedIn speak). Afterward, I'd appreciate yours in the comments or a Restack.</p><h2>Is it a monolith?</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_i0t!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_i0t!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png 424w, https://substackcdn.com/image/fetch/$s_!_i0t!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png 848w, https://substackcdn.com/image/fetch/$s_!_i0t!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png 1272w, https://substackcdn.com/image/fetch/$s_!_i0t!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_i0t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png" width="727.9971313476562" height="727.9971313476562" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/abc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:727.9971313476562,&quot;bytes&quot;:137868,&quot;alt&quot;:&quot;Diagram with three sections, A showing a single app connected to one database, B with multiple apps connected to clustered databases, and C with apps connected to databases through a queue.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&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="Diagram with three sections, A showing a single app connected to one database, B with multiple apps connected to clustered databases, and C with apps connected to databases through a queue." title="Diagram with three sections, A showing a single app connected to one database, B with multiple apps connected to clustered databases, and C with apps connected to databases through a queue." srcset="https://substackcdn.com/image/fetch/$s_!_i0t!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png 424w, https://substackcdn.com/image/fetch/$s_!_i0t!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png 848w, https://substackcdn.com/image/fetch/$s_!_i0t!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.png 1272w, https://substackcdn.com/image/fetch/$s_!_i0t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc83684-81fd-48d5-bf1b-fe1e139fe47c_2161x2161.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 role="img" 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><title></title><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"></figcaption></figure></div><p>Is a monolith just a single block of software, or does it extend to the SQL database?</p><ul><li><p>What if you distribute events?</p></li><li><p>What if your UI is served from the same container?</p></li><li><p>What if you scale a giant container horizontally to meet demand?</p></li><li><p>What if your job workers are instances of the same container as your API?</p></li></ul><p>Is it still a monolith?</p><p>Someone told me, "You can&#8217;t scale a monolith horizontally. You can only scale it vertically." That seems silly because I&#8217;ve scaled huge monoliths across hundreds of small servers.</p><p>Whether it&#8217;s a monolith has nothing to do with the size of the application or how you scale it.</p><p>If multiple applications must always be redeployed together when one changes, they are not microservices. They are parts of a distributed monolith.</p><p>Web applications are almost always multi-component systems.</p><p>Even the simplest monolith of <code>UI -&gt; web server -&gt; application -&gt; SQL</code> is not a single block of software.</p><p>What makes it a monolith?</p><ul><li><p>Not how many repositories it has.</p></li><li><p>Not how many containers it has.</p></li><li><p>Not how many lambdas it has.</p></li><li><p>Not how many teams it has.</p></li></ul><p>Tight coupling makes it a monolith.</p><h2>Are they microservices?</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zsxb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zsxb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png 424w, https://substackcdn.com/image/fetch/$s_!zsxb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png 848w, https://substackcdn.com/image/fetch/$s_!zsxb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png 1272w, https://substackcdn.com/image/fetch/$s_!zsxb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zsxb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:134444,&quot;alt&quot;:&quot;Diagram with four sections, A and B showing apps with dedicated databases, C with shared databases, and D with apps linked to a single database without clear separation.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram with four sections, A and B showing apps with dedicated databases, C with shared databases, and D with apps linked to a single database without clear separation." title="Diagram with four sections, A and B showing apps with dedicated databases, C with shared databases, and D with apps linked to a single database without clear separation." srcset="https://substackcdn.com/image/fetch/$s_!zsxb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png 424w, https://substackcdn.com/image/fetch/$s_!zsxb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png 848w, https://substackcdn.com/image/fetch/$s_!zsxb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png 1272w, https://substackcdn.com/image/fetch/$s_!zsxb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8b224e62-c98a-4dc5-af71-8d9b84f6834f_2161x2161.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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>Is a microservice completely isolated, or can it share databases?</p><ul><li><p>What if it's the same database server?</p></li><li><p>What if it's the same logical database?</p></li><li><p>What if they use different tables?</p></li><li><p>What if they use the same table?</p></li></ul><p>Are they still microservices?</p><p>Someone told me, "If they share even the same database server, they aren't microservices." That seems silly because running a database server per microservice would be costly and complicated to maintain.</p><p>What if you used <a href="https://aws.amazon.com/dynamodb/">DynamoDB</a> and had a separate table for each microservice. Are they using the same server? Are they running on the same machine? You don't know and don't care.</p><p>Whether it&#8217;s a microservice has nothing to do with if they share the same database server.</p><p>What matters is how tightly coupled the services are to dependencies, each other, and the data they manage.</p><p>If multiple applications own the same data, they are not microservices. If each application owns data isolated from data owned by other services, then they might be microservices.</p><p>Databases have different ways of logically separating data, including logical databases, namespaces, and tables.</p><p>What makes it a microservice?</p><ul><li><p>Not how many repositories it has.</p></li><li><p>Not how many databases it has.</p></li><li><p>Not how many lambdas it has.</p></li><li><p>Not how many teams it has.</p></li></ul><p>Loose coupling and high cohesion make it a microservice.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Is it serverless?</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!df77!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!df77!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png 424w, https://substackcdn.com/image/fetch/$s_!df77!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png 848w, https://substackcdn.com/image/fetch/$s_!df77!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png 1272w, https://substackcdn.com/image/fetch/$s_!df77!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!df77!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:180416,&quot;alt&quot;:&quot;Diagram with three sections, A showing individual functions linked to HTTP methods, B with a single container for all methods, and C with multiple containers for different methods.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram with three sections, A showing individual functions linked to HTTP methods, B with a single container for all methods, and C with multiple containers for different methods." title="Diagram with three sections, A showing individual functions linked to HTTP methods, B with a single container for all methods, and C with multiple containers for different methods." srcset="https://substackcdn.com/image/fetch/$s_!df77!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png 424w, https://substackcdn.com/image/fetch/$s_!df77!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png 848w, https://substackcdn.com/image/fetch/$s_!df77!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png 1272w, https://substackcdn.com/image/fetch/$s_!df77!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5fb98e3-1583-4c4c-b544-8f02118e9c9c_2161x2161.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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>Is it serverless because the functions are built and run on demand?</p><ul><li><p>What if the code runs in containers?</p></li><li><p>What if containers are pre-built?</p></li><li><p>What if it's microservices?</p></li><li><p>What if it's a monolith?</p></li></ul><p>Is it still serverless?</p><p>Someone told me, "Only Functions as a Service is serverless." That seems silly because I've used serverless solutions with monoliths, microservices, databases, and machine learning without a single server to worry about.</p><p>Whether it&#8217;s serverless has nothing to do with if its built on demand or if it uses FaaS like <a href="https://aws.amazon.com/lambda/">AWS Lambda</a> or <a href="https://cloud.google.com/functions">Google Cloud Functions</a>.</p><p>What matters is that you don't have to manage the servers. That the instances can scale to zero or there are no instances to think about. That it scales up with demand. That you are only billed for what you use.</p><p><a href="https://www.openfaas.com/">OpenFaaS</a> uses pre-built containers. <a href="https://aws.amazon.com/fargate/">AWS Fargate</a> and <a href="https://cloud.google.com/run">Google Cloud Run</a> manage and run containers for you. S3 is serverless storage. <a href="https://aws.amazon.com/rds/aurora/">AWS Aurora</a> is serverless Postgres DB.</p><p>Monoliths, microservices, databases, storage, API gateways, event buses, and even complex software like machine learning models can be serverless.</p><p>What makes it serverless?</p><ul><li><p>Not where it's built.</p></li><li><p>Not if it uses functions.</p></li><li><p>Not if it uses containers.</p></li><li><p>Not how many APIs it exposes.</p></li></ul><p>The abstraction of infrastructure management makes it serverless.</p><p>(Because "serverless" was originally associated with FaaS, people are now using "Serverless Functions" and "Serverless Containers" to distinguish the type of serverless architecture.)</p><p>("serverless" actually goes back much further. It originally, originally meant "only clients" as in peer-to-peer. That all changed in 2014 at re:Invent <a href="https://en.wikipedia.org/wiki/AWS_Lambda">when Amazon announced Lamba</a>)</p><h2>Next actions</h2><p>What are your thoughts?</p><p>I originally posted these on <a href="https://www.linkedin.com/in/devdetails/">LinkedIn</a>. They sparked some interesting discussions.</p><ul><li><p><a href="https://www.linkedin.com/posts/devdetails_is-it-a-monolith-is-a-monolith-just-a-activity-7125813844001595392-SJ_K">Is it a monolith?</a></p></li><li><p><a href="https://www.linkedin.com/posts/devdetails_are-they-microservices-is-a-microservice-activity-7140368516125192192-15nk">Are they microservices?</a></p></li><li><p><a href="https://www.linkedin.com/posts/devdetails_is-it-serverless-is-it-serverless-because-activity-7153747864442036225-73pV">Is it serverless?</a></p></li><li><p>Bonus: <a href="https://www.linkedin.com/posts/devdetails_microservices-are-not-apps-thats-what-activity-7140739255131123712-Wt-W">Microservices are not Apps?</a></p></li></ul><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.devdetails.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Design context is more important than a detailed solution]]></title><description><![CDATA[We will never have enough information before implementation to be able to design a perfect solution. Inevitably, what we know will change as we implement.]]></description><link>https://blog.devdetails.com/p/design-context-is-more-important</link><guid isPermaLink="false">https://blog.devdetails.com/p/design-context-is-more-important</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Sun, 10 Dec 2023 06:29:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_QH0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>With a software design, having enough context is more important than having a detailed solution.</p><p>We will never have enough information before implementation to be able to design a perfect solution. Inevitably, what we know will change as we implement.</p><p>We learn from the implementation done so far. Outside factors change requirements, schedules, or resources. A detailed design is too rigid to allow the team to adapt to changes.</p><p>Too much up-front design-decision slows projects down. It limits the flexibility of the people implementing it. I prefer lightweight design processes that enable <a href="https://blog.devdetails.com/p/autonomy-for-software-architecture">autonomy</a>. We want just enough information for stakeholders to move forward.</p><p>We don't need a perfect solution &#8212; only a good enough one.<br>We don't need a detailed solution &#8212; only just enough of one.</p><p>A solution direction is better than a solution destination. If the team understands the problem, they can pivot as much as needed to deliver a good enough solution. So, providing just enough context is crucial to enabling autonomy. Leave the details for later &#8212; <a href="https://blog.codinghorror.com/the-last-responsible-moment/">for the last responsible moment</a>.</p><p>So then, what is just enough context? Let's dig into the details.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Why do we need a design document anyway?</h2><p>A Design Document describes the context of a problem, the outcome expectations, and the solution to address it.</p><p>Its purpose is to:</p><ul><li><p>Get alignment on business needs.</p></li><li><p>Provide a solution that will satisfy those needs.</p></li><li><p>Inform those impacted.</p></li><li><p>Guide those who will implement it.</p></li></ul><p>It is the rallying point for all technical discussions around a problem.</p><p>It should only be extensive enough to meet the team's needs &#8212; no more, no less.</p><h2>Who figures out all this context?</h2><p>The engineers&nbsp;close to the problem&nbsp;drive the design &#8212; they are the "Driver". Not product. Not architects. Everyone supports and collaborates with the Driver.</p><p>In <a href="https://blog.devdetails.com/p/adopting-daci">DACI</a> terms, the Driver is the person who moves the project forward and is responsible for the decision-making process. (For more on what it means to be the Driver, see <a href="https://blog.devdetails.com/p/driving-software-design-forward">Driving software design forward</a>)</p><p>So, the Driver figures out the context.</p><h2>Who is all this context for?</h2><p>The goal is that you can hand the document to anyone with the required experience on your team, and they can implement the solution without your further input.</p><p>The more context you can provide, the better they will understand the problem and how your solution addresses it. The more they understand the problem, the more capable they'll be of adapting the solution direction to changing demands.</p><p>Who needs this context depends on the particular problem that a solution is being designed for. Depending on the scope of the problem, the audience can include:</p><ul><li><p>Product team</p></li><li><p>Security, Privacy, or Compliance teams</p></li><li><p>Architects</p></li><li><p>Engineering managers</p></li><li><p>Operations, Platform, or Infrastructure teams</p></li><li><p>Quality Assurance</p></li><li><p>Implementing engineers</p></li></ul><p>You are writing for the audience. Consider who your audience is when designing. Anticipate the audience's questions and answer them in the document before they have to ask. Make it easy for them to see that you understand the problem and that your solution addresses it.</p><h2>Yes, but how much context is that?</h2><p>Keep in mind that readers have a limited context window. For designs, the context window is everything they know about the products within the organization. Everyone's context window overlaps with each other's at different points. You can only address so much context, so your document itself has a limited context window.</p><p>The document's context window is a sliding window that falls somewhere between high-level business information and low-level implementation details.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_QH0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_QH0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png 424w, https://substackcdn.com/image/fetch/$s_!_QH0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png 848w, https://substackcdn.com/image/fetch/$s_!_QH0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png 1272w, https://substackcdn.com/image/fetch/$s_!_QH0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_QH0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:134867,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!_QH0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png 424w, https://substackcdn.com/image/fetch/$s_!_QH0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png 848w, https://substackcdn.com/image/fetch/$s_!_QH0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png 1272w, https://substackcdn.com/image/fetch/$s_!_QH0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d6f98f3-9b9f-4606-b571-5f4c001d4d91_2161x2161.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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>Put the most relevant and urgent information in the design context. Then, go a step further and widen the window slightly to the left to give engineers hints of where to go for more business information. Much of the document will go into implementation details, so there is usually no need to widen the context window further to the right.</p><p>One way to provide additional context, especially if you're feeling <s>lazy</s> efficient, is to provide links. Everyone can use the links as a breadcrumb to find more relevance. The links also bind related information together through backlinks. Future developers, including future you, will thank you for these links.</p><h2>Isn't that a lot of work?</h2><p>The challenge is to figure out what information will drive the design in a good direction and well inform the people implementing it.</p><p>All this might sound like I suggest you design every function call and write pseudo code. I am emphatically not. The document should stay high-level and leave low-level implementation details up to the team who will implement it.</p><p>Convey just enough context so the people implementing it understand enough to have autonomy. Then, they can make micro-decisions while satisfying the organization's needs.</p><p>The amount of context you need to provide is proportional to the complexity and impact of the problem you are solving.</p><ul><li><p>More complexity = more context</p></li><li><p>Involves multiple internal teams = more context</p></li><li><p>Huge impact on customers = more context</p></li><li><p>Affects many services = more context</p></li></ul><p>If you are designing a simple solution to a problem that only affects your team, then the context and document should be relatively small.</p><p>If you are designing something that affects a lot of teams or has a huge business impact, then you will need to provide enough context to inform those affected and convey that impact.</p><h2>What context is valuable?</h2><ul><li><p>Current state and how it falls short of the business need</p></li><li><p>Problem description, particularly user or business pain points</p></li><li><p>Why this change needs doing from a business perspective</p></li><li><p>Level 1 or 2 <a href="https://c4model.com/">C4 Model</a> diagrams</p></li><li><p>Use cases that explain goals a user should achieve using the system</p></li></ul><p>You might notice an emphasis on "business." Business impact is the most crucial consideration of a design. If it does not satisfy the needs of the business, what is the point?&nbsp;</p><p>If someone can't convey business needs and impact or they are not well understood, the design's fitness can not be judged. If it can't be judged fit, the design, its context, or the project should be reconsidered.</p><p>Understanding the business needs and the impact of a change is a key motivator and grantor of autonomy for the team. It enables them to take pride in ownership.</p><p>With enough context, the team can make sound decisions when adapting to changing demands.</p><p>For more details on design, see:</p><ul><li><p><a href="https://blog.devdetails.com/p/autonomy-for-software-architecture">Autonomy for Software Architecture Design</a></p></li><li><p><a href="https://blog.devdetails.com/p/architecture-principles-streamline">Architecture Principles streamline development</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Do I still code?]]></title><description><![CDATA[I started writing Dev Details regularly at the beginning of the year. It seems like so long ago, though it hasn&#8217;t been that long at all. Since then, I&#8217;ve gained many new subscribers and many times more followers on LinkedIn. In the last 3 months, 1000+ people have subscribed to Dev Details.]]></description><link>https://blog.devdetails.com/p/do-i-still-code</link><guid isPermaLink="false">https://blog.devdetails.com/p/do-i-still-code</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Sat, 07 Oct 2023 05:59:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I started writing Dev Details regularly at the beginning of the year. It seems like so long ago, though it hasn&#8217;t been that long at all. </p><p>Since then, I&#8217;ve gained many new subscribers and many times more followers on LinkedIn. In the last 3 months, 1000+ people have subscribed to Dev Details.</p><p>That means many of you are recent subscribers who probably haven&#8217;t seen my earlier posts. I&#8217;ve included a few below to highlight my past content.</p><p>Thank you for reading Dev Details. It would mean a great deal to me if you shared my posts with software engineers you think will appreciate them.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/p/do-i-still-code?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://blog.devdetails.com/p/do-i-still-code?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p>Writing is thinking. It helps me to formulate my ideas more clearly and share them with everyone. Each time I write, I get better at it and the topic I&#8217;m writing about. I encourage any software engineer who wants to expand their engineering skills to start writing publicly.</p><p>I write a lot as part of my role as a software architect. But do I still code? I answer that in the post below.</p><h2>Early Posts</h2><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;5d8e1240-90f8-4252-88e1-3e52fb049204&quot;,&quot;caption&quot;:&quot;How much do software architects code? How much should they code? Consider the following if you want to collaborate better with architects or seek a role with architectural responsibilities. Spotting architecture roles Not all job descriptions have a title with \&quot;architect\&quot; in it.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Do software architects code?&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:35756860,&quot;name&quot;:&quot;Mike&quot;,&quot;bio&quot;:&quot;A Software Architect that connects the dots between big-picture software architecture and low-level details. \n&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4fa0330c-4d94-4c0e-b012-8c678571101e_1024x1138.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-01-03T14:01:26.328Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/h_600,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F23e21abf-92f6-4fcc-bc39-a5428d0596ea_1024x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://blog.devdetails.com/p/do-software-architects-code&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:93780532,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:6,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Dev Details&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e27b4bb3-b14b-4383-985e-69b3fc5bb63c&quot;,&quot;caption&quot;:&quot;Throughout high school, I was interested in building architecture &#127968;. I started drafting classes in high school and got my first real job as a drafter at an architectural firm. I was learning home design from the best. Then the unexpected happened: Before the dotcom crash, the firm had a website to sell house plans.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;I wanted to design buildings, but I'm a software architect&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:35756860,&quot;name&quot;:&quot;Mike&quot;,&quot;bio&quot;:&quot;A Software Architect that connects the dots between big-picture software architecture and low-level details. \n&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4fa0330c-4d94-4c0e-b012-8c678571101e_1024x1138.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-06-26T15:00:29.802Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://blog.devdetails.com/p/i-wanted-to-design-buildings-but&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:130273462,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:2,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Dev Details&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e8e9c688-b967-4d95-8b19-ceaf973410dd&quot;,&quot;caption&quot;:&quot;Software Architecture is both an art and a science and a critical part of a Software (and Product) Development Lifecycle (SDLC/PDLC). The Software Architecture processes an engineering organization employs ultimately determine how successfully the organization can scale to meet quality, speed, and capability demands.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Autonomy for Software Architecture Design&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:35756860,&quot;name&quot;:&quot;Mike&quot;,&quot;bio&quot;:&quot;A Software Architect that connects the dots between big-picture software architecture and low-level details. \n&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4fa0330c-4d94-4c0e-b012-8c678571101e_1024x1138.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-05-03T16:34:27.962Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb71c113b-639e-4d09-86ba-9c2621269001_1024x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://blog.devdetails.com/p/autonomy-for-software-architecture&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:118908950,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:4,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Dev Details&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h2>Popular posts</h2><div class="embedded-post-wrap" data-attrs="{&quot;id&quot;:127680806,&quot;url&quot;:&quot;https://blog.devdetails.com/p/a-practical-example-of-using-ai-for&quot;,&quot;publication_id&quot;:350569,&quot;publication_name&quot;:&quot;Dev Details&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;title&quot;:&quot;A practical example of using AI for coding&quot;,&quot;truncated_body_text&quot;:&quot;ChatGPT and other LLMs have impressive coding capabilities. However, the obvious way to use it is like driving a race car on square wheels &#8212; inefficient, teeth-rattling, and headache-inducing. I've developed some techniques for working with AI coding tools that get good results. Here, I'll focus on how you can add generative AI to your workflow.&quot;,&quot;date&quot;:&quot;2023-06-14T03:34:57.914Z&quot;,&quot;like_count&quot;:5,&quot;comment_count&quot;:1,&quot;bylines&quot;:[{&quot;id&quot;:35756860,&quot;name&quot;:&quot;Mike&quot;,&quot;handle&quot;:&quot;devdetails&quot;,&quot;previous_name&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4fa0330c-4d94-4c0e-b012-8c678571101e_1024x1138.jpeg&quot;,&quot;bio&quot;:&quot;A Software Architect that connects the dots between big-picture software architecture and low-level details. \n&quot;,&quot;profile_set_up_at&quot;:&quot;2021-04-29T15:40:08.397Z&quot;,&quot;publicationUsers&quot;:[{&quot;id&quot;:272174,&quot;user_id&quot;:35756860,&quot;publication_id&quot;:350569,&quot;role&quot;:&quot;admin&quot;,&quot;public&quot;:true,&quot;is_primary&quot;:false,&quot;publication&quot;:{&quot;id&quot;:350569,&quot;name&quot;:&quot;Dev Details&quot;,&quot;subdomain&quot;:&quot;devdetails&quot;,&quot;custom_domain&quot;:&quot;blog.devdetails.com&quot;,&quot;custom_domain_optional&quot;:false,&quot;hero_text&quot;:&quot;Big-picture software architecture, low-level details, and how they're entangled.&quot;,&quot;logo_url&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;author_id&quot;:35756860,&quot;theme_var_background_pop&quot;:&quot;#99A2F1&quot;,&quot;created_at&quot;:&quot;2021-04-29T15:38:34.797Z&quot;,&quot;rss_website_url&quot;:null,&quot;email_from_name&quot;:&quot;Dev Details&quot;,&quot;copyright&quot;:&quot;Dev Details&quot;,&quot;founding_plan_name&quot;:&quot;Founding Member&quot;,&quot;community_enabled&quot;:true,&quot;invite_only&quot;:false,&quot;payments_state&quot;:&quot;enabled&quot;,&quot;language&quot;:null}}],&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;utm_campaign&quot;:null,&quot;belowTheFold&quot;:true,&quot;type&quot;:&quot;newsletter&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="EmbeddedPostToDOM"><a class="embedded-post" native="true" href="https://blog.devdetails.com/p/a-practical-example-of-using-ai-for?utm_source=substack&amp;utm_campaign=post_embed&amp;utm_medium=web"><div class="embedded-post-header"><img class="embedded-post-publication-logo" src="https://substackcdn.com/image/fetch/$s_!zMus!,w_56,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png" loading="lazy"><span class="embedded-post-publication-name">Dev Details</span></div><div class="embedded-post-title-wrapper"><div class="embedded-post-title">A practical example of using AI for coding</div></div><div class="embedded-post-body">ChatGPT and other LLMs have impressive coding capabilities. However, the obvious way to use it is like driving a race car on square wheels &#8212; inefficient, teeth-rattling, and headache-inducing. I've developed some techniques for working with AI coding tools that get good results. Here, I'll focus on how you can add generative AI to your workflow&#8230;</div><div class="embedded-post-cta-wrapper"><span class="embedded-post-cta">Read more</span></div><div class="embedded-post-meta">3 years ago &#183; 5 likes &#183; 1 comment &#183; Mike</div></a></div><div class="embedded-post-wrap" data-attrs="{&quot;id&quot;:133962402,&quot;url&quot;:&quot;https://blog.devdetails.com/p/algorithms-in-interviews-suck-cut&quot;,&quot;publication_id&quot;:350569,&quot;publication_name&quot;:&quot;Dev Details&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;title&quot;:&quot;Algorithms in interviews suck. Cut it out.&quot;,&quot;truncated_body_text&quot;:&quot;Modern software development is a spectrum ranging from deep algorithmic work to system design. The majority of software development happens between that range. Most developers work on application development, which is closer to system design than it is to low-level algorithms.&quot;,&quot;date&quot;:&quot;2023-07-08T20:12:06.246Z&quot;,&quot;like_count&quot;:11,&quot;comment_count&quot;:0,&quot;bylines&quot;:[{&quot;id&quot;:35756860,&quot;name&quot;:&quot;Mike&quot;,&quot;handle&quot;:&quot;devdetails&quot;,&quot;previous_name&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4fa0330c-4d94-4c0e-b012-8c678571101e_1024x1138.jpeg&quot;,&quot;bio&quot;:&quot;A Software Architect that connects the dots between big-picture software architecture and low-level details. \n&quot;,&quot;profile_set_up_at&quot;:&quot;2021-04-29T15:40:08.397Z&quot;,&quot;publicationUsers&quot;:[{&quot;id&quot;:272174,&quot;user_id&quot;:35756860,&quot;publication_id&quot;:350569,&quot;role&quot;:&quot;admin&quot;,&quot;public&quot;:true,&quot;is_primary&quot;:false,&quot;publication&quot;:{&quot;id&quot;:350569,&quot;name&quot;:&quot;Dev Details&quot;,&quot;subdomain&quot;:&quot;devdetails&quot;,&quot;custom_domain&quot;:&quot;blog.devdetails.com&quot;,&quot;custom_domain_optional&quot;:false,&quot;hero_text&quot;:&quot;Big-picture software architecture, low-level details, and how they're entangled.&quot;,&quot;logo_url&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;author_id&quot;:35756860,&quot;theme_var_background_pop&quot;:&quot;#99A2F1&quot;,&quot;created_at&quot;:&quot;2021-04-29T15:38:34.797Z&quot;,&quot;rss_website_url&quot;:null,&quot;email_from_name&quot;:&quot;Dev Details&quot;,&quot;copyright&quot;:&quot;Dev Details&quot;,&quot;founding_plan_name&quot;:&quot;Founding Member&quot;,&quot;community_enabled&quot;:true,&quot;invite_only&quot;:false,&quot;payments_state&quot;:&quot;enabled&quot;,&quot;language&quot;:null}}],&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;utm_campaign&quot;:null,&quot;belowTheFold&quot;:true,&quot;type&quot;:&quot;newsletter&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="EmbeddedPostToDOM"><a class="embedded-post" native="true" href="https://blog.devdetails.com/p/algorithms-in-interviews-suck-cut?utm_source=substack&amp;utm_campaign=post_embed&amp;utm_medium=web"><div class="embedded-post-header"><img class="embedded-post-publication-logo" src="https://substackcdn.com/image/fetch/$s_!zMus!,w_56,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png" loading="lazy"><span class="embedded-post-publication-name">Dev Details</span></div><div class="embedded-post-title-wrapper"><div class="embedded-post-title">Algorithms in interviews suck. Cut it out.</div></div><div class="embedded-post-body">Modern software development is a spectrum ranging from deep algorithmic work to system design. The majority of software development happens between that range. Most developers work on application development, which is closer to system design than it is to low-level algorithms&#8230;</div><div class="embedded-post-cta-wrapper"><span class="embedded-post-cta">Read more</span></div><div class="embedded-post-meta">3 years ago &#183; 11 likes &#183; Mike</div></a></div><div class="embedded-post-wrap" data-attrs="{&quot;id&quot;:135294386,&quot;url&quot;:&quot;https://blog.devdetails.com/p/driving-software-design-forward&quot;,&quot;publication_id&quot;:350569,&quot;publication_name&quot;:&quot;Dev Details&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;title&quot;:&quot;Driving software design forward&quot;,&quot;truncated_body_text&quot;:&quot;In order to scale, Architects should not design. They should facilitate the software architecture process. This is how to scale and enable autonomy. But then, who should design? Effectively, all engineers. Junior Engineers design for small problems that only impact things the team owns&quot;,&quot;date&quot;:&quot;2023-07-20T05:10:27.083Z&quot;,&quot;like_count&quot;:5,&quot;comment_count&quot;:0,&quot;bylines&quot;:[{&quot;id&quot;:35756860,&quot;name&quot;:&quot;Mike&quot;,&quot;handle&quot;:&quot;devdetails&quot;,&quot;previous_name&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4fa0330c-4d94-4c0e-b012-8c678571101e_1024x1138.jpeg&quot;,&quot;bio&quot;:&quot;A Software Architect that connects the dots between big-picture software architecture and low-level details. \n&quot;,&quot;profile_set_up_at&quot;:&quot;2021-04-29T15:40:08.397Z&quot;,&quot;publicationUsers&quot;:[{&quot;id&quot;:272174,&quot;user_id&quot;:35756860,&quot;publication_id&quot;:350569,&quot;role&quot;:&quot;admin&quot;,&quot;public&quot;:true,&quot;is_primary&quot;:false,&quot;publication&quot;:{&quot;id&quot;:350569,&quot;name&quot;:&quot;Dev Details&quot;,&quot;subdomain&quot;:&quot;devdetails&quot;,&quot;custom_domain&quot;:&quot;blog.devdetails.com&quot;,&quot;custom_domain_optional&quot;:false,&quot;hero_text&quot;:&quot;Big-picture software architecture, low-level details, and how they're entangled.&quot;,&quot;logo_url&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;author_id&quot;:35756860,&quot;theme_var_background_pop&quot;:&quot;#99A2F1&quot;,&quot;created_at&quot;:&quot;2021-04-29T15:38:34.797Z&quot;,&quot;rss_website_url&quot;:null,&quot;email_from_name&quot;:&quot;Dev Details&quot;,&quot;copyright&quot;:&quot;Dev Details&quot;,&quot;founding_plan_name&quot;:&quot;Founding Member&quot;,&quot;community_enabled&quot;:true,&quot;invite_only&quot;:false,&quot;payments_state&quot;:&quot;enabled&quot;,&quot;language&quot;:null}}],&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;utm_campaign&quot;:null,&quot;belowTheFold&quot;:true,&quot;type&quot;:&quot;newsletter&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="EmbeddedPostToDOM"><a class="embedded-post" native="true" href="https://blog.devdetails.com/p/driving-software-design-forward?utm_source=substack&amp;utm_campaign=post_embed&amp;utm_medium=web"><div class="embedded-post-header"><img class="embedded-post-publication-logo" src="https://substackcdn.com/image/fetch/$s_!zMus!,w_56,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png" loading="lazy"><span class="embedded-post-publication-name">Dev Details</span></div><div class="embedded-post-title-wrapper"><div class="embedded-post-title">Driving software design forward</div></div><div class="embedded-post-body">In order to scale, Architects should not design. They should facilitate the software architecture process. This is how to scale and enable autonomy. But then, who should design? Effectively, all engineers. Junior Engineers design for small problems that only impact things the team owns&#8230;</div><div class="embedded-post-cta-wrapper"><span class="embedded-post-cta">Read more</span></div><div class="embedded-post-meta">3 years ago &#183; 5 likes &#183; Mike</div></a></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.devdetails.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Career-ending advice]]></title><description><![CDATA[I post "career-ending" advice. People are taking it seriously.]]></description><link>https://blog.devdetails.com/p/career-ending-advice</link><guid isPermaLink="false">https://blog.devdetails.com/p/career-ending-advice</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Fri, 29 Sep 2023 16:54:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!MEGd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Fridays on LinkedIn, I post "career-ending" advice. I don't expect anyone to follow this advice because it is satire. If you follow it, you'll likely cause your career to come tumbling down.</p><p>While they're mostly joking, there is a kernel of truth and a lesson in them. I want people to think, "If I shouldn't do this, what should I do?".</p><p>I end every post with:</p><blockquote><p>Follow me for more career-ending &#128721; advice on Fridays and hit that &#128718;&#65039;</p></blockquote><p>Not everyone reads to the end before getting outraged at how stupid I must be to believe what I say.</p><p>The disturbing part is that the more ridiculous I make the posts, the more people think I'm serious.</p><p>Based on the reactions, this means there are people who think my career-ending advice is reasonable and not career-ending at all.</p><h2>Reactions</h2><p>From the LinkedIn reactions, it's hard to say what people think. The thing is, I can't tell if I myself am falling to <a href="https://en.wikipedia.org/wiki/Poe%27s_law">Poe's Law</a>.</p><blockquote><p><em>Without a winking smiley or other blatant display of humor, it is utterly impossible to parody a {topic} in such a way that someone won't mistake for the genuine article.</em></p></blockquote><p>Here's how I can interpret the reactions:</p><ul><li><p><strong>&#128514; Funny</strong>: They get the joke and think it's funny.</p></li><li><p><strong>&#128077; Like</strong>: Default reaction, so it can be a mix of people who understand the joke, people who click like on all my posts, and people who do not understand it's a joke and genuinely think it's good advice.</p></li><li><p><strong>&#10084;&#65039; Love</strong>: Do they love the joke or love the advice?</p></li><li><p><strong>&#128161;Insightful</strong>: Seriously? What am I supposed to think here? You must be messing with me!</p></li><li><p><strong>&#128079; Celebrate</strong>: &#129327;</p></li><li><p><strong>&#129782; Support</strong>: Does this mean, "Nice try, better luck next time?"</p></li></ul><p>I know some of the non-funny reactions are to troll me. (Looking at you <a href="https://substack.com/@darsadowski">Dariusz Sadowski</a>). Now that I've pointed this out, I'm sure to get even less useful data as more people troll by giving non-funny reactions to my post.</p><p>(BTW, if you want to troll me by clicking random reactions on all my old posts that you haven't read yet, I support that &#129782;.)</p><h3>Diagram</h3><p>To illustrate the point, here's a graph. Impressions and engagement are trending up, so my content is getting more attention over time. Presumably, this means it&#8217;s better. However, the Funny reaction percentage is trending down. It either means more people are taking this seriously and using non-Funny reactions, or it&#8217;s large-scale trolling.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MEGd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MEGd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png 424w, https://substackcdn.com/image/fetch/$s_!MEGd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png 848w, https://substackcdn.com/image/fetch/$s_!MEGd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png 1272w, https://substackcdn.com/image/fetch/$s_!MEGd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MEGd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png" width="473" height="426.8536585365854" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:814,&quot;width&quot;:902,&quot;resizeWidth&quot;:473,&quot;bytes&quot;:106587,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!MEGd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png 424w, https://substackcdn.com/image/fetch/$s_!MEGd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png 848w, https://substackcdn.com/image/fetch/$s_!MEGd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png 1272w, https://substackcdn.com/image/fetch/$s_!MEGd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02d2ed6d-d79f-4bcc-a181-4062cfae5d4b_902x814.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><h3>Full stats of posts since the beginning</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JRe5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JRe5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png 424w, https://substackcdn.com/image/fetch/$s_!JRe5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png 848w, https://substackcdn.com/image/fetch/$s_!JRe5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!JRe5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JRe5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png" width="1456" height="1530" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/af53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1530,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:609113,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!JRe5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png 424w, https://substackcdn.com/image/fetch/$s_!JRe5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png 848w, https://substackcdn.com/image/fetch/$s_!JRe5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!JRe5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf53ff2c-9e0d-47a8-8fc1-92d7073d3add_1462x1536.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><h2>Career-ending Advice</h2><p>Anyway, enough about my confusion. Here&#8217;s all the career-ending advice from latest to the beginning.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Gmdl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Gmdl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png 424w, https://substackcdn.com/image/fetch/$s_!Gmdl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png 848w, https://substackcdn.com/image/fetch/$s_!Gmdl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png 1272w, https://substackcdn.com/image/fetch/$s_!Gmdl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Gmdl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png" width="455" height="1399.125" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:3075,&quot;width&quot;:1000,&quot;resizeWidth&quot;:455,&quot;bytes&quot;:473953,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!Gmdl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png 424w, https://substackcdn.com/image/fetch/$s_!Gmdl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png 848w, https://substackcdn.com/image/fetch/$s_!Gmdl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png 1272w, https://substackcdn.com/image/fetch/$s_!Gmdl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49f7556e-20d3-42b8-ad40-4bf426b1bf91_1000x3075.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!X92K!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!X92K!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png 424w, https://substackcdn.com/image/fetch/$s_!X92K!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png 848w, https://substackcdn.com/image/fetch/$s_!X92K!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png 1272w, https://substackcdn.com/image/fetch/$s_!X92K!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!X92K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png" width="457" height="1107.768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2424,&quot;width&quot;:1000,&quot;resizeWidth&quot;:457,&quot;bytes&quot;:436232,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!X92K!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png 424w, https://substackcdn.com/image/fetch/$s_!X92K!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png 848w, https://substackcdn.com/image/fetch/$s_!X92K!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png 1272w, https://substackcdn.com/image/fetch/$s_!X92K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffee291bb-5ad4-40db-a7ad-1cf6d561b21d_1000x2424.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9Zr5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9Zr5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png 424w, https://substackcdn.com/image/fetch/$s_!9Zr5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png 848w, https://substackcdn.com/image/fetch/$s_!9Zr5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png 1272w, https://substackcdn.com/image/fetch/$s_!9Zr5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9Zr5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png" width="459" height="1052.028" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2292,&quot;width&quot;:1000,&quot;resizeWidth&quot;:459,&quot;bytes&quot;:367465,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!9Zr5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png 424w, https://substackcdn.com/image/fetch/$s_!9Zr5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png 848w, https://substackcdn.com/image/fetch/$s_!9Zr5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png 1272w, https://substackcdn.com/image/fetch/$s_!9Zr5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F604fb569-a9d2-4c48-91da-c9ceab7cc72c_1000x2292.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GSRJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GSRJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png 424w, https://substackcdn.com/image/fetch/$s_!GSRJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png 848w, https://substackcdn.com/image/fetch/$s_!GSRJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png 1272w, https://substackcdn.com/image/fetch/$s_!GSRJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GSRJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png" width="461" height="705.5548780487804" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1506,&quot;width&quot;:984,&quot;resizeWidth&quot;:461,&quot;bytes&quot;:218100,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!GSRJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png 424w, https://substackcdn.com/image/fetch/$s_!GSRJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png 848w, https://substackcdn.com/image/fetch/$s_!GSRJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png 1272w, https://substackcdn.com/image/fetch/$s_!GSRJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a36b514-fb35-442e-baf3-701f423c25ac_984x1506.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rtdk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rtdk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png 424w, https://substackcdn.com/image/fetch/$s_!rtdk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png 848w, https://substackcdn.com/image/fetch/$s_!rtdk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png 1272w, https://substackcdn.com/image/fetch/$s_!rtdk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rtdk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png" width="463" height="331.92668024439917" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:704,&quot;width&quot;:982,&quot;resizeWidth&quot;:463,&quot;bytes&quot;:128804,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!rtdk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png 424w, https://substackcdn.com/image/fetch/$s_!rtdk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png 848w, https://substackcdn.com/image/fetch/$s_!rtdk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png 1272w, https://substackcdn.com/image/fetch/$s_!rtdk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F340f0315-42d2-4a4d-adaf-153ac75b5488_982x704.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_Djt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_Djt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png 424w, https://substackcdn.com/image/fetch/$s_!_Djt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png 848w, https://substackcdn.com/image/fetch/$s_!_Djt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png 1272w, https://substackcdn.com/image/fetch/$s_!_Djt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_Djt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png" width="463" height="306.1923847695391" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/eb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:660,&quot;width&quot;:998,&quot;resizeWidth&quot;:463,&quot;bytes&quot;:120484,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!_Djt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png 424w, https://substackcdn.com/image/fetch/$s_!_Djt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png 848w, https://substackcdn.com/image/fetch/$s_!_Djt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png 1272w, https://substackcdn.com/image/fetch/$s_!_Djt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb95d9aa-524d-464a-9341-45b1f670bb1c_998x660.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!axPY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!axPY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png 424w, https://substackcdn.com/image/fetch/$s_!axPY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png 848w, https://substackcdn.com/image/fetch/$s_!axPY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png 1272w, https://substackcdn.com/image/fetch/$s_!axPY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!axPY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png" width="461" height="469.3987854251012" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1006,&quot;width&quot;:988,&quot;resizeWidth&quot;:461,&quot;bytes&quot;:158524,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!axPY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png 424w, https://substackcdn.com/image/fetch/$s_!axPY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png 848w, https://substackcdn.com/image/fetch/$s_!axPY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png 1272w, https://substackcdn.com/image/fetch/$s_!axPY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fb581c0-6226-4eb8-9b47-22a3c011c678_988x1006.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bNVk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bNVk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png 424w, https://substackcdn.com/image/fetch/$s_!bNVk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png 848w, https://substackcdn.com/image/fetch/$s_!bNVk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png 1272w, https://substackcdn.com/image/fetch/$s_!bNVk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bNVk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png" width="465" height="261.7987804878049" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:554,&quot;width&quot;:984,&quot;resizeWidth&quot;:465,&quot;bytes&quot;:118521,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!bNVk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png 424w, https://substackcdn.com/image/fetch/$s_!bNVk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png 848w, https://substackcdn.com/image/fetch/$s_!bNVk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png 1272w, https://substackcdn.com/image/fetch/$s_!bNVk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F402fc0e5-9d3e-41a3-864b-f6b1b969c0eb_984x554.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gwig!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gwig!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png 424w, https://substackcdn.com/image/fetch/$s_!gwig!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png 848w, https://substackcdn.com/image/fetch/$s_!gwig!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png 1272w, https://substackcdn.com/image/fetch/$s_!gwig!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gwig!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png" width="467" height="306.9127789046653" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:648,&quot;width&quot;:986,&quot;resizeWidth&quot;:467,&quot;bytes&quot;:118071,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!gwig!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png 424w, https://substackcdn.com/image/fetch/$s_!gwig!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png 848w, https://substackcdn.com/image/fetch/$s_!gwig!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png 1272w, https://substackcdn.com/image/fetch/$s_!gwig!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4722226d-4b82-4c7a-ac8f-8e688bb2fff6_986x648.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NH9r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NH9r!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png 424w, https://substackcdn.com/image/fetch/$s_!NH9r!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png 848w, https://substackcdn.com/image/fetch/$s_!NH9r!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png 1272w, https://substackcdn.com/image/fetch/$s_!NH9r!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NH9r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png" width="469" height="264.0508130081301" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ae8958f-f669-4665-8204-17e7816857a2_984x554.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:554,&quot;width&quot;:984,&quot;resizeWidth&quot;:469,&quot;bytes&quot;:118521,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!NH9r!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png 424w, https://substackcdn.com/image/fetch/$s_!NH9r!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png 848w, https://substackcdn.com/image/fetch/$s_!NH9r!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png 1272w, https://substackcdn.com/image/fetch/$s_!NH9r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae8958f-f669-4665-8204-17e7816857a2_984x554.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Balancing delivery speed and high-quality code]]></title><description><![CDATA[When building out new features, how do you balance speed of delivery with implementing higher quality yet more time-consuming code?]]></description><link>https://blog.devdetails.com/p/balancing-delivery-speed-and-high</link><guid isPermaLink="false">https://blog.devdetails.com/p/balancing-delivery-speed-and-high</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Fri, 22 Sep 2023 23:17:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!RXc8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Someone asked me:</p><blockquote><p>When building out new features, how do you balance speed of delivery with implementing higher quality yet more time-consuming code?</p></blockquote><p>At a high level, such as when designing, I try to design/envision&nbsp;what the end goal would look like. I think several iterations down the line. Then, I work backward from that design to figure out milestones that will get me there.</p><p>Since I know where I intend to go, I can take shortcuts. But I&#8217;m not taking blind shortcuts. I know what tradeoffs I&#8217;m making &#8212; what it will save in time now vs. cost in tech debt later.</p><p>At a low level, I optimize for speed of delivery by writing tests that validate behavior interwoven with writing code.</p><p>I'm cheating with my answer here because if you write good tests, higher-quality code naturally follows.</p><p>Starting with a test and refining it while you code allows you to develop and deliver faster. <em>Everything</em>&nbsp;else to speed up delivery or improve code quality is secondary. If you have <em>no</em> tests or <em>bad</em> tests, you will become slower and slower each time you deliver.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RXc8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RXc8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg 424w, https://substackcdn.com/image/fetch/$s_!RXc8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg 848w, https://substackcdn.com/image/fetch/$s_!RXc8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!RXc8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RXc8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg" width="958" height="958" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:958,&quot;width&quot;:958,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:93636,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RXc8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg 424w, https://substackcdn.com/image/fetch/$s_!RXc8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg 848w, https://substackcdn.com/image/fetch/$s_!RXc8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!RXc8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5336bb4c-e1ce-4e3f-87ed-29ace562c404_958x958.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 role="img" 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><title></title><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><h2>OMG is this really a post about TDD??</h2><p>Not entirely. But I&#8217;ll need to explain the reasoning behind the answer to the original question.</p><p>Many people have a negative reaction to Test-Driven Development (TDD). Some might say, "If you don't like it, you're doing it wrong". Instead, let me explain a little about how I develop, and then you can see if it resonates.</p><p><a href="https://www.kentbeck.com/">Kent Beck</a> is well-known for TDD. His writings on the matter are much better than mine. He's been writing about his next book on his Substack <a href="https://tidyfirst.substack.com/">Software Design: Tidy First?</a>. You should check it out.</p><p>I'll give a pragmatic view of how I write tests as an integral part of coding. But first, what is a good test?</p><h2>What is a good test?</h2><p>If you're writing tests with the goal of reaching some coverage metric or because the CI gods demand it, you will fail. The goal of a test is to verify behavior &#8212; not simply exercise code.</p><p>When people think "testing", they usually think "unit tests". I don't think we need unit tests as they're commonly defined for the most part:</p><blockquote><p>A unit test is a way of testing a unit - the smallest piece of code that can be logically isolated in a system.</p></blockquote><p>A small piece of logically isolated code rarely does enough to be considered a useful behavior. (The exception here would be something like a low-level library. In that case, the code is generally small and logically isolated, and the user is someone who uses this library.)</p><p><strong>Focus on testing behaviors &#8212; not code units.</strong></p><div><hr></div><p>Behavior testing seems to be the key mind shift that people overlook. Many people get caught up with TDD because they're thinking unit tests. Writing unit tests first &#8212; for <em>everything</em> &#8212; will result in way too many tests, too much noise, and not enough signal. It will bind your tests to the implementation. That way is the fast track to codebases no one wants to work on. You will hate it. This says more about approaches to excessive unit testing than it does about TDD.</p><p>Good tests are from the point of view of the caller (of the API, of the function, end user, etc.), and they verify a desired behavior.</p><p>This is the basics of Behavior-Driven Development (BDD).</p><p><strong>Fewer unit tests; more tests of behaviors.</strong></p><div><hr></div><p>Behavioral tests may result in a single test covering a large area of code when a lot of code is necessary to enact a behavior. This is okay. This is desirable (a topic for another day). It usually leads to more functional and integration testing and very little unit testing. (<em>Aside: This doesn't mean use mocks &#8212; excessive mocking is an anti-pattern. Look at testing analogs or just run the dependency, e.g. SQL, on a RAM-disk instead.</em>)</p><p>So...</p><p><strong>A good test is a test that verifies behavior.</strong></p><h2>Writing tests as an integral part of coding</h2><p>It seems many people think test-driven development means "write the entire test first." Sometimes, they think it means "write all the tests first." The immediate follow-up to this is, "I don't know what code I'm going to write, so I don't know how to write the entire test first." Another common argument is that "TDD works when you know what you're going to build but not when you're doing a proof of concept."</p><p>These points are emphatically incorrect.</p><p>With TDD, you write a test intermingled with writing the implementation. It is what helps you figure out what the code will do. So, it works even better when you have no idea what you want the code to do.</p><p>The basics of TDD (Red; Green; Refactor):</p><ol><li><p>Write a test that does the behavior you're thinking of. It should fail when you run it.</p></li><li><p>Write a minimal implementation to make that test pass.</p></li><li><p>Consider improvements to your implementation. If there are none, go to step 1 for the next behavior.</p></li></ol><p>Consider this experiment: Do not run the UI while writing server code. How would you verify your server code is working? (<em>Aside: I never run the UI when I write server code.</em>)</p><p>You could use something like <code>curl</code>, Postman, or another API client.</p><p>The tests are my user/my API consumer/my Postman &#8212; except I can run them repeatedly on-demand.</p><p>I write a test that does one simple API call. Maybe just a&nbsp;<code>GET /api/ping</code>. It will fail.</p><p>I add server boilerplate and the implementation for <code>ping</code>, so now I have a repeatable API server setup.</p><p>Then I think, &#8220;Okay, what does this API need to do?&#8221; So, I write an experiment in code. I write a new test to&nbsp;<code>POST /api/thing</code>.</p><p>Half the time, I write what I expect the response to be. Half the time, I don't even bother to anticipate the expected result. </p><p>I do something like&nbsp;<code>assert response == {}</code> in my test, which will fail when I add a body. I then do a minimal implementation and design what I want the body to return as I write the code. Then, I go back to the test, run it, visually inspect the response, and copy/paste it as the expected response.</p><p><em>Note that Kent Beck considers this practice <a href="https://tidyfirst.substack.com/p/canon-tdd">to be a TDD mistake</a>. I agree in principle, but practical need (developer <s>laziness</s> efficiency) often outweighs the value of principle. Handwriting an expected JSON response can be tedious. &#128514;</em></p><blockquote><p>Mistake: copying actual, computed values &amp; pasting them into the expected values of the test. That defeats double checking, which creates much of the validation value of TDD.</p></blockquote><p>With unknown or vague requirements, I'm discovering the requirements and the implementation simultaneously. I'm designing the user interaction <em>and</em> the implementation at the same time. </p><p>The tests are my requirement assumptions and the user interface. I'm not trying to cover all cases, only the ones I want the user to perform and the error states I expect.</p><h2>How does writing tests like this help me deliver faster?</h2><p>As long as the tests cover the business use cases &#8212; the behavior, you can write whatever fast/hacky code you need to.</p><p>The tests ensure the behavior is correct. When you have time (this is a fallacy: <code>later == never</code> &#8212; there is never time to refactor until you are forced to &#128517;), you can refactor the implementation safely because the tests ensure you keep the correct behavior.</p><p>To deliver faster, we can take deliberate shortcuts to get something done faster. We agree to take on tech debt that we will pay down later. This might involve writing code that will be completely thrown away or using less-than-ideal technologies in the beginning.</p><p>For the &#8220;throw-away code&#8221; aspect, this is also where tests shine. If you don&#8217;t write tests, you&#8217;re hesitant to throw away code because it&#8217;s working, and you might not actually know how it works.</p><p>So, instead of throwing away the old implementation (and keeping the tests) &#8212; which would allow you to write better faster &#8212; you keep tinkering on the old code until it is a spaghetti mess.</p><p>&#8220;throw-away code&#8221; should actually be thrown away. A new implementation should be written using what you learned from the experimental code with the tests as the driver.</p><h2>Managing risk to deliver quickly with high-quality</h2><p><em>All</em>&nbsp;code has tech debt. Accepting that tech debt is a reality and making deliberate decisions about when and where to take it on is risk management. Ignoring tech debt or blindly coding without acknowledging it exists means the tech debt is in control and decides when and where to present itself.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>It&#8217;s more about deciding where to put the debt &#8212; where&nbsp;<em>I&#8217;m</em>&nbsp;willing to take on the risk of debt.</p><p>Once it comes time to code, here is the order I think it is important to get things &#8220;right&#8221;. The later the stage, the less risk when accepting tech debt.</p><ol><li><p><strong>The tests</strong> &#8212; capture the business use cases and behavior.</p><ul><li><p>Tech debt here is problematic because if you can&#8217;t write the test, you don&#8217;t understand the feature.</p></li><li><p>If you don&#8217;t understand the feature, you have no idea what tech debt and risks are involved.</p></li><li><p>It is always harder to add tests after the feature is complete because you must first figure out how it was implemented and then write tests around it &#8212; warts and all.</p></li></ul></li><li><p><strong>The public interface</strong> &#8212; A minimal interface that provides the operations needed by the business use cases.</p><ul><li><p>Writing this with the tests helps you design a minimal interface.</p></li><li><p>You write what is needed by the business use cases instead of what might be needed.</p></li><li><p>The interface is hard to change once it is public &#8212; especially if we&#8217;re talking about a library or API.</p></li><li><p>Once in the wild, you must support that interface or force people to stop using it.</p></li><li><p>The smaller you make the interface, the less you have to support, which reduces tech debt.</p></li></ul></li><li><p><strong>The implementation</strong> &#8212; This is where it is easiest to accept tech debt.</p><ul><li><p>Since the tests describe how it should work, and the interface is what your users are using, you can change this as much as you like, freely.</p></li><li><p>This includes complete rewrites and changing technologies (databases, event-based vs. HTTP, etc.).</p></li></ul></li></ol><p>Essentially, leave the details to the end. Tests drive the interface. The interface is essential, but not a detail. Whether it uses MySQL vs. PostgreSQL, or HTTP vs. events, or threads vs. blocking, etc. are details. The longer you wait to fill in the details, the more flexibility you have.</p><p>Good tests mean you can change the details with ease later &#8212; even if you already wrote a working implementation.</p><h2>Conclusion</h2><p>To balance speed of delivery with delivering higher quality, write implementation intermingled with writing the test in a cycle.</p><p>It's the easiest way to manage risk so you can deliver code faster.</p><p>To manage risk, get things "right" in this order:</p><ol><li><p>Tests</p></li><li><p>Public interface</p></li><li><p>Implementation</p></li></ol><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.devdetails.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Roundup: Travel, career advice, microservices, and architecture principles]]></title><description><![CDATA[Posts from week 2 of August]]></description><link>https://blog.devdetails.com/p/roundup-travel-career-advice-microservices</link><guid isPermaLink="false">https://blog.devdetails.com/p/roundup-travel-career-advice-microservices</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Mon, 14 Aug 2023 23:02:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!UH7X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last week I traveled to meet with my team at <a href="https://www.bluebeam.com/">Bluebeam</a> for an architecture summit. We had a lot of great architecture discussions, and I got to meet several people for the first time face-to-face. </p><p>Working remotely is great, and getting to occasionally meet in person with people grows relationships that make remote interactions smoother. For these in-person meetings, I focus on sharing ideas and meeting people rather than making decisions. We can discuss topics as a vehicle for getting to know one another and then handle the process of actually making the decision remotely.</p><p>I did have a mishap one night, though. <a href="https://www.linkedin.com/posts/devdetails_what-do-you-do-when-the-ceiling-in-your-hotel-activity-7095328694176534528-La1M">What do you do when the ceiling in your hotel bathroom starts leaking at 1 AM?</a></p><h3>Roundup</h3><p>I typically write rather detailed posts about various architectural topics that come up during the course of my work. The newsletter is called &#8220;Dev Details&#8221;, after all. I&#8217;ll write a long, detailed article on a particular topic and then do some short posts on <a href="https://www.linkedin.com/in/devdetails/">LinkedIn</a> related to that main topic. This is a summary of those posts for the week.</p><h3>Design Patterns</h3><p>I pointed out that: <a href="https://www.linkedin.com/posts/devdetails_singleton-is-the-most-design-pattern-activity-7095855160677044224-MAC6">Singleton is the most design pattern</a>. There were many helpful and not-so-helpful comments on why it&#8217;s the most design pattern.</p><h3>Career Advice</h3><p>On Fridays, I give (bad) career advice. There is real advice here though. Basically do the opposite of what I suggest.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://www.linkedin.com/posts/devdetails_put-all-your-data-in-the-user-table-as-a-activity-7095793920537726977-imvq" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UH7X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png 424w, https://substackcdn.com/image/fetch/$s_!UH7X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png 848w, https://substackcdn.com/image/fetch/$s_!UH7X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png 1272w, https://substackcdn.com/image/fetch/$s_!UH7X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UH7X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png" width="1262" height="558" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:558,&quot;width&quot;:1262,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:122199,&quot;alt&quot;:&quot;Put all your data in the User table as a JSON string called &#8220;user_data&#8221;   This follows the Architecture Principle: User-centric Software  Follow me for more career-ending advice and hit that bell.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://www.linkedin.com/posts/devdetails_put-all-your-data-in-the-user-table-as-a-activity-7095793920537726977-imvq&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Put all your data in the User table as a JSON string called &#8220;user_data&#8221;   This follows the Architecture Principle: User-centric Software  Follow me for more career-ending advice and hit that bell." title="Put all your data in the User table as a JSON string called &#8220;user_data&#8221;   This follows the Architecture Principle: User-centric Software  Follow me for more career-ending advice and hit that bell." srcset="https://substackcdn.com/image/fetch/$s_!UH7X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png 424w, https://substackcdn.com/image/fetch/$s_!UH7X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png 848w, https://substackcdn.com/image/fetch/$s_!UH7X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png 1272w, https://substackcdn.com/image/fetch/$s_!UH7X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a2808b4-68aa-4ce5-ad8b-bd493f4b377f_1262x558.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><h3>SQL</h3><p>I asked, what does SQL sound like? Your thoughts?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://www.linkedin.com/posts/devdetails_activity-7095638947363487744-aqs4" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z3Hp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png 424w, https://substackcdn.com/image/fetch/$s_!z3Hp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png 848w, https://substackcdn.com/image/fetch/$s_!z3Hp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png 1272w, https://substackcdn.com/image/fetch/$s_!z3Hp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z3Hp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png" width="1270" height="808" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:808,&quot;width&quot;:1270,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:114311,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://www.linkedin.com/posts/devdetails_activity-7095638947363487744-aqs4&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!z3Hp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png 424w, https://substackcdn.com/image/fetch/$s_!z3Hp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png 848w, https://substackcdn.com/image/fetch/$s_!z3Hp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png 1272w, https://substackcdn.com/image/fetch/$s_!z3Hp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84353eb3-23ea-4099-8497-c04b7717dc57_1270x808.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h3>Microservices</h3><p>Some advice on tools in your tool belt. Sometimes you don&#8217;t have enough.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://www.linkedin.com/posts/devdetails_when-you-have-a-microservice-hammer-every-activity-7094900311940612096-J8NU" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0e2i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png 424w, https://substackcdn.com/image/fetch/$s_!0e2i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png 848w, https://substackcdn.com/image/fetch/$s_!0e2i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png 1272w, https://substackcdn.com/image/fetch/$s_!0e2i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0e2i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png" width="1252" height="352" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:352,&quot;width&quot;:1252,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:91641,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://www.linkedin.com/posts/devdetails_when-you-have-a-microservice-hammer-every-activity-7094900311940612096-J8NU&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!0e2i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png 424w, https://substackcdn.com/image/fetch/$s_!0e2i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png 848w, https://substackcdn.com/image/fetch/$s_!0e2i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png 1272w, https://substackcdn.com/image/fetch/$s_!0e2i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F73499bf8-48a3-4ac7-8172-c870e80bb089_1252x352.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><h3>Artificial Intelligence</h3><p>I want AI to be better at generating code. Maybe ChatGPT will scrape this and be encouraged.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://www.linkedin.com/posts/devdetails_i-hope-this-take-ages-poorly-ai-writes-garbage-activity-7094394024635072512-ONGX" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A8Z0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png 424w, https://substackcdn.com/image/fetch/$s_!A8Z0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png 848w, https://substackcdn.com/image/fetch/$s_!A8Z0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png 1272w, https://substackcdn.com/image/fetch/$s_!A8Z0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A8Z0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png" width="1258" height="296" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:296,&quot;width&quot;:1258,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83234,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://www.linkedin.com/posts/devdetails_i-hope-this-take-ages-poorly-ai-writes-garbage-activity-7094394024635072512-ONGX&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!A8Z0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png 424w, https://substackcdn.com/image/fetch/$s_!A8Z0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png 848w, https://substackcdn.com/image/fetch/$s_!A8Z0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png 1272w, https://substackcdn.com/image/fetch/$s_!A8Z0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54cfb081-76ce-4ca9-84c8-703a4dc0fe9c_1258x296.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Architecture Principles</h3><p>The deep dive Dev Details article for this week was on how <a href="https://blog.devdetails.com/p/architecture-principles-streamline">Architecture Principles streamline development</a>. Here is the <a href="https://www.linkedin.com/posts/devdetails_architecture-principles-streamline-development-activity-7095325766120341504-3u_K">LinkedIn post</a>:</p><p>Architecture teams can shift culture, streamline development, and increase quality without being an ivory tower<br><br>How? One tool is Architecture Principles.<br><br>Architectural principles streamline the development process by setting clear guidelines and standards.<br><br>However, they only do so if everyone, from top to bottom, is aligned on those principles.<br><br>&#128313; What's that you say; your company has no Architectural Principles?<br><br>It might not be easy to see them. But they&#8217;re there, affecting every decision.<br><br>&#128312; Each developer has their own set of architectural principles.<br>&#128312; Each team implicitly has them based on the collection of developers and past implementations.<br>&#128312; Engineering leaders have them whether they're technical or not.<br>&#128312; The CTO and CEO have them.<br><br>The problem arises when everyone has architectural principles but does not know what everyone else's is.</p><p>One of the topics we discussed was Architecture Principles, so I wrote about how <a href="https://blog.devdetails.com/p/architecture-principles-streamline">Architecture Principles streamline development</a>. One of my favorites is </p><h3>Interview</h3><p>I did an interview with <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Gregor Ojstersek&quot;,&quot;id&quot;:106098672,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdbe0558-3b80-4d09-9925-34ff44ed066e_400x400.jpeg&quot;,&quot;uuid&quot;:&quot;6473b786-8d76-465f-bc9f-7691124709e7&quot;}" data-component-name="MentionToDOM"></span>. Want to know what it&#8217;s like to be a Software Architect? Read this interview where he asks me about my approach to Software Architecture, how I got started with it, and how others might follow the same path.</p><div class="embedded-post-wrap" data-attrs="{&quot;id&quot;:135736688,&quot;url&quot;:&quot;https://newsletter.eng-leadership.com/p/growing-from-engineer-to-architect&quot;,&quot;publication_id&quot;:1115815,&quot;publication_name&quot;:&quot;Engineering Leadership&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce408894-f1c0-4b61-bd35-d010be631ae2_317x317.png&quot;,&quot;title&quot;:&quot;Growing from engineer to architect and thriving&quot;,&quot;truncated_body_text&quot;:&quot;Intro This article is the next edition of &#8220;Which is the right engineering career path for you?&#8221;. This edition is particularly made for engineers to make good decisions regarding their career growth. Knowing in which direction to grow, will ensure you focus on learning the right things.&quot;,&quot;date&quot;:&quot;2023-08-06T07:15:33.390Z&quot;,&quot;like_count&quot;:25,&quot;comment_count&quot;:6,&quot;bylines&quot;:[{&quot;id&quot;:106098672,&quot;name&quot;:&quot;Gregor Ojstersek&quot;,&quot;handle&quot;:&quot;gregorojstersek&quot;,&quot;previous_name&quot;:&quot;Gregor&quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdbe0558-3b80-4d09-9925-34ff44ed066e_400x400.jpeg&quot;,&quot;bio&quot;:&quot;CTO | Author of Engineering Leadership newsletter - Helping Engineering Leaders to build high-performing teams&quot;,&quot;profile_set_up_at&quot;:&quot;2022-10-03T11:48:31.646Z&quot;,&quot;publicationUsers&quot;:[{&quot;id&quot;:1066676,&quot;user_id&quot;:106098672,&quot;publication_id&quot;:1115815,&quot;role&quot;:&quot;admin&quot;,&quot;public&quot;:true,&quot;is_primary&quot;:false,&quot;publication&quot;:{&quot;id&quot;:1115815,&quot;name&quot;:&quot;Engineering Leadership&quot;,&quot;subdomain&quot;:&quot;gregorojstersek&quot;,&quot;custom_domain&quot;:&quot;newsletter.eng-leadership.com&quot;,&quot;custom_domain_optional&quot;:false,&quot;hero_text&quot;:&quot;All things Engineering Leadership!&quot;,&quot;logo_url&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ce408894-f1c0-4b61-bd35-d010be631ae2_317x317.png&quot;,&quot;author_id&quot;:106098672,&quot;theme_var_background_pop&quot;:&quot;#FF0000&quot;,&quot;created_at&quot;:&quot;2022-10-03T11:49:36.188Z&quot;,&quot;rss_website_url&quot;:null,&quot;email_from_name&quot;:null,&quot;copyright&quot;:&quot;Gregor Ojstersek&quot;,&quot;founding_plan_name&quot;:&quot;Founding Member&quot;,&quot;community_enabled&quot;:true,&quot;invite_only&quot;:false,&quot;payments_state&quot;:&quot;disabled&quot;}}],&quot;twitter_screen_name&quot;:&quot;gregorojstersek&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;utm_campaign&quot;:null,&quot;belowTheFold&quot;:true,&quot;type&quot;:&quot;newsletter&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="EmbeddedPostToDOM"><a class="embedded-post" native="true" href="https://newsletter.eng-leadership.com/p/growing-from-engineer-to-architect?utm_source=substack&amp;utm_campaign=post_embed&amp;utm_medium=web"><div class="embedded-post-header"><img class="embedded-post-publication-logo" src="https://substackcdn.com/image/fetch/$s_!LTf8!,w_56,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce408894-f1c0-4b61-bd35-d010be631ae2_317x317.png" loading="lazy"><span class="embedded-post-publication-name">Engineering Leadership</span></div><div class="embedded-post-title-wrapper"><div class="embedded-post-title">Growing from engineer to architect and thriving</div></div><div class="embedded-post-body">Intro This article is the next edition of &#8220;Which is the right engineering career path for you?&#8221;. This edition is particularly made for engineers to make good decisions regarding their career growth. Knowing in which direction to grow, will ensure you focus on learning the right things&#8230;</div><div class="embedded-post-cta-wrapper"><span class="embedded-post-cta">Read more</span></div><div class="embedded-post-meta">3 years ago &#183; 25 likes &#183; 6 comments &#183; Gregor Ojstersek</div></a></div><h3>Next Steps</h3><p>If you enjoyed the content, repost or forward to someone else that might enjoy it.</p><p>If you&#8217;re not already, <a href="https://www.linkedin.com/in/devdetails/">follow me on LinkedIn</a> for more short form content.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.devdetails.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Architecture Principles streamline development]]></title><description><![CDATA[Architecture Principles guide the development, design, and operation of software systems.]]></description><link>https://blog.devdetails.com/p/architecture-principles-streamline</link><guid isPermaLink="false">https://blog.devdetails.com/p/architecture-principles-streamline</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Thu, 10 Aug 2023 08:26:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!4H4L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Architectural principles streamline the development process by setting clear guidelines and standards. However, they only do so if everyone, from top to bottom, is aligned on those principles. When everyone is aligned, all levels of the organization benefit. When everyone has different principles, it leads to conflicts, confusion, and frustration.</p><p>I use Architecture Principles to make positive cultural shifts, simplify development processes, and increase the quality of the software delivered. Continue reading to learn how I introduce, choose, and use them.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4H4L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4H4L!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!4H4L!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!4H4L!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!4H4L!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4H4L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:125162,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4H4L!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!4H4L!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!4H4L!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!4H4L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.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 role="img" 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><title></title><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><h2>Awareness</h2><p>Whether you're aware or not, your company, whether they are aware or not, is already using architectural principles.</p><p>What's that you say; your company has no architectural principles?</p><p>It might not be easy to see them. But they guide big system-wide decisions as well as small, every day, one-line-of-code-at-a-time decisions.</p><p>Each developer has their own set of architectural principles they work with. Each team implicitly has them based on the collection of developers and past implementations. Engineering leaders have them whether they're technical or not. The CTO and CEO have them.</p><p>The problem arises when everyone has architectural principles but does not know what everyone else's is. Software development suffers when everyone is not aligned on Architecture Principles.</p><h2>Okay, everyone has architectural principles, so what?</h2><p>For developers, architectural principles offer clear direction and a framework for decision-making. They foster a culture of autonomy, allowing teams to make decisions and develop solutions independently, free from constant oversight or approval from a central authority. This independence empowers teams to innovate, iterate, and quickly adapt to changing requirements.</p><p>For businesses, architectural principles clarify the business's technical goals. This reduces technical debt by promoting consistent, scalable, and maintainable software. That leads to robust, adaptable systems that make change easy. Which, in effect, increases market responsiveness and competitive edge. They foster a culture of quality, enhancing customer trust and satisfaction.</p><p>For customers, architectural principles may not be directly visible, but their impact is evident in the quality, reliability, and user experience. Good principles guide the creation of software systems that are secure, scalable, and have a user-centric design. Ultimately, the principles contribute to the timely delivery of features and solutions that meet customer needs and expectations.</p><p>Alignment of architectural principles is critical to achieving these positive effects. They define the boundaries and guidelines within which teams should work while still granting them the freedom to innovate and make independent decisions. By adhering to these principles, teams can align their designs with the organization's overall objectives.</p><h2>When are the principles used?</h2><p>I prefer design processes that do not require central approval. Architecture Principles are a key component that enables <a href="https://blog.devdetails.com/p/autonomy-for-software-architecture">autonomy in software development</a>. Whenever a member of the team has a decision to make or a design to create, they reference the Architecture Principles for guidance. When the team adheres to the principles, their decisions will align with business and architectural goals.</p><p>During the review of a design for fitness to a solution, the team verifies it adheres to the principles. Concerns can be raised by anyone on the team, including Engineers, Architects, QA, Product Managers, etc.</p><p>For the design processes I champion, if a design adheres to Architecture Principles and uses only technology from a Tech Menu/Radar, then the team is empowered to self-approve the designs. My goal is to minimize oversight and give teams the autonomy to make their own decisions.</p><p>However, sometimes there is a legitimate reason to ignore or go against an Architecture Principle. In that case, autonomy can't be maintained, and the decision must be approved by a higher authority. This is typically done by an Architecture Advisory Forum (AAF), Architecture Board, Engineering Leaders, etc.</p><h2>What do Architecture Principles look like?</h2><p>Architecture Principles typically address various aspects, ranging from system security, performance, and scalability to coding standards, data management, and user experience.</p><p>A few common principles are:</p><ol><li><p><strong>API First</strong>: Treat APIs as a user-facing and critical part of the product. Design APIs first -- before implementation -- to ensure they meet a user need, are interoperable, and ease integration.</p></li><li><p><strong>Don't Reinvent</strong>: Avoid "Not Invented Here" Syndrome by preferring to use existing products, services, and libraries instead of developing them in-house. Buy -- not build.</p></li><li><p><strong>User-Centric</strong>: Focus on end-user needs, preferences, and feedback in design and development. Endeavor to understand why a user needs a solution and how that solution serves the user's needs.</p></li></ol><div class="embedded-post-wrap" data-attrs="{&quot;id&quot;:135820515,&quot;url&quot;:&quot;https://blog.devdetails.com/p/architecture-principle-examples&quot;,&quot;publication_id&quot;:350569,&quot;publication_name&quot;:&quot;Dev Details&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;title&quot;:&quot;Architecture Principle Examples&quot;,&quot;truncated_body_text&quot;:&quot;Below are over 25 examples for inspiring your Architecture Principles. Expand upon them to fit your specific use cases, drive your culture, and remove ambiguity. Independently Deployable: Modular Software, Modular Teams. Isolate software and team development to increase flexibility and robustness. This approach promotes efficiency, maintainability, and adaptability.&quot;,&quot;date&quot;:&quot;2023-08-09T21:00:26.672Z&quot;,&quot;like_count&quot;:0,&quot;comment_count&quot;:0,&quot;bylines&quot;:[{&quot;id&quot;:35756860,&quot;name&quot;:&quot;Mike&quot;,&quot;handle&quot;:&quot;devdetails&quot;,&quot;previous_name&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb539e9-8f6b-4c7d-a33c-862ee33a9872_200x200.jpeg&quot;,&quot;bio&quot;:&quot;A Software Architect that connects the dots between big-picture software architecture and low-level details. \n&quot;,&quot;profile_set_up_at&quot;:&quot;2021-04-29T15:40:08.397Z&quot;,&quot;publicationUsers&quot;:[{&quot;id&quot;:272174,&quot;user_id&quot;:35756860,&quot;publication_id&quot;:350569,&quot;role&quot;:&quot;admin&quot;,&quot;public&quot;:true,&quot;is_primary&quot;:false,&quot;publication&quot;:{&quot;id&quot;:350569,&quot;name&quot;:&quot;Dev Details&quot;,&quot;subdomain&quot;:&quot;devdetails&quot;,&quot;custom_domain&quot;:&quot;blog.devdetails.com&quot;,&quot;custom_domain_optional&quot;:false,&quot;hero_text&quot;:&quot;Big-picture software architecture, low-level details, and how they're entangled.&quot;,&quot;logo_url&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/e3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;author_id&quot;:35756860,&quot;theme_var_background_pop&quot;:&quot;#99A2F1&quot;,&quot;created_at&quot;:&quot;2021-04-29T15:38:34.797Z&quot;,&quot;rss_website_url&quot;:null,&quot;email_from_name&quot;:&quot;Dev Details&quot;,&quot;copyright&quot;:&quot;Dev Details&quot;,&quot;founding_plan_name&quot;:&quot;Founding Member&quot;,&quot;community_enabled&quot;:true,&quot;invite_only&quot;:false,&quot;payments_state&quot;:&quot;enabled&quot;}}],&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;utm_campaign&quot;:null,&quot;belowTheFold&quot;:true,&quot;type&quot;:&quot;newsletter&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="EmbeddedPostToDOM"><a class="embedded-post" native="true" href="https://blog.devdetails.com/p/architecture-principle-examples?utm_source=substack&amp;utm_campaign=post_embed&amp;utm_medium=web"><div class="embedded-post-header"><img class="embedded-post-publication-logo" src="https://substackcdn.com/image/fetch/$s_!zMus!,w_56,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png" loading="lazy"><span class="embedded-post-publication-name">Dev Details</span></div><div class="embedded-post-title-wrapper"><div class="embedded-post-title">Architecture Principle Examples</div></div><div class="embedded-post-body">Below are over 25 examples for inspiring your Architecture Principles. Expand upon them to fit your specific use cases, drive your culture, and remove ambiguity. Independently Deployable: Modular Software, Modular Teams. Isolate software and team development to increase flexibility and robustness. This approach promotes efficiency, maintainability, and adaptability&#8230;</div><div class="embedded-post-cta-wrapper"><span class="embedded-post-cta">Read more</span></div><div class="embedded-post-meta">3 years ago &#183; Mike</div></a></div><h2>What makes a good principle?</h2><p>Principles should be <a href="https://en.wikipedia.org/wiki/SMART_criteria">SMART</a> (Specific, Measurable, Achievable, Realistic, and Testable).</p><p>First, let's consider a principle that is not SMART: Zero Bugs.</p><ul><li><p><strong>Specific</strong>: Unclear what defines a "bug" universally.</p></li><li><p><strong>Measurable</strong>: Proving zero bugs across scenarios is nearly impossible.</p></li><li><p><strong>Achievable</strong>: Reaching zero bugs is unrealistic due to complexity.</p></li><li><p><strong>Relevant</strong>: Aiming for zero bugs may divert crucial resources.</p></li><li><p><strong>Testable</strong>: Testing for the absence of all bugs is virtually impossible.</p></li></ul><p>Let's see how the example principles are SMART.</p><h3>API First</h3><ul><li><p><strong>Specific</strong>: Design APIs before implementation for a user need and make them public.</p></li><li><p><strong>Measurable</strong>: Quality of integration, interoperability, and documentation can be assessed.</p></li><li><p><strong>Achievable</strong>: Can be implemented with proper planning and design.</p></li><li><p><strong>Realistic</strong>: Within the capability of most development teams.</p></li><li><p><strong>Testable</strong>: CI can enforce that API specifications are present and covered with automated tests.</p></li></ul><h3>Don't Reinvent</h3><ul><li><p><strong>Specific</strong>: Use existing solutions over in-house development.</p></li><li><p><strong>Measurable</strong>: Time and cost savings can be evaluated.</p></li><li><p><strong>Achievable</strong>: Solutions can be found in commercial or open-source products and services.</p></li><li><p><strong>Realistic</strong>: Aligns with the capabilities and resources of the team.</p></li><li><p><strong>Testable</strong>: The value between buying and building can be clearly assessed.</p></li></ul><h3>User-Centric</h3><ul><li><p><strong>Specific</strong>: Designing based on end-user needs and preferences.</p></li><li><p><strong>Measurable</strong>: Customer satisfaction and user experience can be quantified.</p></li><li><p><strong>Achievable</strong>: Can be implemented through research and user feedback.</p></li><li><p><strong>Realistic</strong>: Possible with the right mindset and team focus.</p></li><li><p><strong>Testable</strong>: User satisfaction and experience can be tested.</p></li></ul><h2>How do I choose Architecture Principles?</h2><p>There are a few ground rules I set for choosing principles:</p><ol><li><p>They must align with business goals.</p></li><li><p>They must be sourced from the teams.</p></li><li><p>All teams must accept and actively support them.</p></li></ol><p>Principles should be tightly aligned with the organization's goals, vision, and mission. Good principles positively influence the behavior and culture of the team. They should inspire and guide without stifling innovation or being too rigid.</p><p>To help align principles to business goals, first, define the business goals. If you&#8217;ve already done that, then great, make them available to everyone. If the business goals aren&#8217;t clearly defined, that&#8217;s another topic, but start with acute problems the business is facing. Are you trying to grow the user base, increase customer satisfaction, improve reliability, improve quality, etc?</p><p>How many principles you need largely depends on your goals. I typically start with 6 principles to address acute issues. As your needs grow in complexity and variety, add principles to address them. Companies tend to end up with around a dozen. You&#8217;ll want to evaluate principles regularly, every six months or so, and remove ones that are no longer providing value.</p><h2>How do I source principles from the team?</h2><p>You&#8217;ll need to get alignment and buy-in across the organization, but you have to start somewhere. I like to start with a small group of representatives from every team to draft the initial 6 principles. Then run through a roll-out strategy with checkpoints to get alignment amongst all the teams.</p><p>A typical process that I use:</p><ol><li><p>Assemble Architects, Principal Engineers, and engineering leaders for a brainstorming session.</p></li><li><p>Use <a href="https://blog.devdetails.com/p/adopting-daci">DACI</a>: Elect an Architect or leader to Drive this exercise. The engineering group will be Approvers by voting (see below). Everyone is by nature a Collaborator, and other people (such as Product) may be consulted. The entire engineering organization will be Informed.</p></li><li><p>Have each member pre-read this article (possibly with a silent meeting).</p></li><li><p>Lay out the business goals.</p></li><li><p>Review example principles.</p></li><li><p>Put the example principles in a spreadsheet as a starting point. Only put principles that you can reasonably align with business goals.</p></li><li><p>Have everyone raise additional principles for consideration. Whoever raises a principle should explain how it&#8217;s applicable, aligned with business goals, and SMART.</p></li><li><p>Each member only gets half the votes for the number of principles we want. So, in this case, everyone gets 3 votes.</p></li><li><p>Add a column to the spreadsheet for each member.</p></li><li><p>Each member will put a ranking, 1, 2, or 3, alongside up to 3 principles.</p></li><li><p>Tally the totals for each principle.</p></li><li><p>Take the top-voted half (in this case 3) of principles and automatically &#8220;ratify&#8221; them.</p></li><li><p>Discuss and debate the remaining top-voted principles to see what else belongs on the list of 6.</p></li><li><p>The Driver will refine the principles and record the results.</p></li><li><p>The Driver will create one Any Decision Record (ADR) per principle.</p></li><li><p>At this point, you might be satisfied approving the ADRs but hold off so you can get feedback from the rollout process. An Architecture Advisory Forum (AAF) could be used, but this group likely is the same group as the AAF.</p></li><li><p>The Driver will start the rollout process.</p></li></ol><h2>What is the rollout process?</h2><p>&#8220;Geez, it&#8217;s like you have a process for everything,&#8221; you might say. Well, yes, everything has a process, whether we explicitly state it or not. I like to make processes explicit so everyone understands where we are and what to expect next.</p><p>If you have a small team and everyone was well-represented during the selection process above, you&#8217;re done! Approve the ADRs, and inform anyone who missed out. Don&#8217;t worry; principles are reversible by design, so don&#8217;t fret about being too hasty with the approve button.</p><p>However, if you have a large team, which you likely do because you weren&#8217;t already aligned on principles, then a roll-out strategy is needed to get alignment. Alignment is required. If your teams don&#8217;t believe in and agree with the principles you&#8217;ve chosen, they will not use them, and they will have false autonomy.</p><p>Here&#8217;s the rollout strategy I&#8217;ve used:</p><ol><li><p>Start with getting alignment with Staff+ Engineers. The Principal Engineers will drive this, with the support of the architecture team.</p></li><li><p>Give the Staff+ Engineers this article as pre-reading material.</p></li><li><p>Call a meeting to discuss the principles you&#8217;re considering adopting. Make it clear you want feedback before moving forward.</p></li><li><p>Discuss each principle you&#8217;ve chosen and, most importantly, why you chose it and how it meets business needs.</p></li><li><p>Discuss some of the other principles you considered and why you didn&#8217;t ultimately choose them.</p></li><li><p>Ask for feedback. Are there any other principles you should have considered? Were the assumptions of why the principles were chosen wrong? Are any principles in actuality untenable?</p></li><li><p>If there is no alignment, refine the principles and repeat. This might involve going back to choosing different principles. If so, there are likely some larger communication problems between engineering leadership and individual contributors to address. If there is alignment, move forward.</p></li><li><p>Have the Staff+ Engineers repeat this exercise with the rest of their team. Their resident Principal Engineer or Architect can sit in for support. If any revisions are needed, the Principal Engineer should drive it.</p></li><li><p>This should result in all engineering teams having a chance to collaborate and provide enough feedback for the Architects, Principal Engineers, and engineering leadership to approve.</p></li><li><p>Approve the ADRs.</p></li><li><p>Inform the rest of the company about the decisions, especially close partners like Product, User Experiences, Customer Support, QA, etc.</p></li></ol><h2>What's next?</h2><ul><li><p>Learn more about <a href="https://blog.devdetails.com/p/autonomy-for-software-architecture">autonomy in software development</a>.</p></li><li><p>Check out <a href="https://blog.devdetails.com/p/architecture-principle-examples">these example principles</a> as inspiration for your own.</p></li><li><p>Use your chosen Architecture Principles for guidance in your day-to-day work.</p></li><li><p>Evaluate your principles a couple of times a year, keep what's providing value, drop what's no longer useful, and add what's needed.</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Related Reading</h2><ul><li><p><a href="https://www.oreilly.com/library/view/art-of-scalability/9780134031408/">Art of Scalability</a>&nbsp;discusses Architecture Principles in greater detail.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Architecture Principle Examples]]></title><description><![CDATA[Examples to inspire your own Architecture Principles]]></description><link>https://blog.devdetails.com/p/architecture-principle-examples</link><guid isPermaLink="false">https://blog.devdetails.com/p/architecture-principle-examples</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Wed, 09 Aug 2023 21:00:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QTOz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Below are over 50 examples for inspiring your Architecture Principles. Expand upon them to fit your specific use cases, drive your culture, and remove ambiguity.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;952c3050-5682-4289-b647-d65c0c3f9729&quot;,&quot;caption&quot;:&quot;Architectural principles streamline the development process by setting clear guidelines and standards. However, they only do so if everyone, from top to bottom, is aligned on those principles. When everyone is aligned, all levels of the organization benefit. When everyone has different principles, it leads to conflicts, confusion, and frustration.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Architecture Principles streamline development&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:35756860,&quot;name&quot;:&quot;Mike&quot;,&quot;bio&quot;:&quot;A Software Architect that connects the dots between big-picture software architecture and low-level details. \n&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4fa0330c-4d94-4c0e-b012-8c678571101e_1024x1138.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-08-10T08:26:21.407Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe6e9813-0c47-46f6-a84d-22d27e805bf2_1024x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://blog.devdetails.com/p/architecture-principles-streamline&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:135820465,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:3,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Dev Details&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3bb2380-4086-479b-91cc-5087e63362a5_1280x1280.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QTOz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QTOz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!QTOz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!QTOz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!QTOz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QTOz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:222221,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QTOz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!QTOz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!QTOz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!QTOz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89c60f58-536b-4b15-b154-723d76b80e3c_1024x1024.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 role="img" 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><title></title><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><ul><li><p><strong>Independently Deployable</strong>: Modular Software, Modular Teams.<strong> </strong>Isolate software between teams to increase flexibility and robustness. This approach promotes efficiency, maintainability, and adaptability.</p></li><li><p><strong>Pit of Success</strong>: Make it easy to do the right thing and hard to do the wrong thing. Design intuitively to guide users and developers towards success, making correct paths easy and mistakes difficult.</p></li><li><p><strong>Contribute to Open Source</strong>: Foster community collaboration, promote knowledge sharing, improve software quality, and give back.</p></li><li><p><strong>Deploy Continuously</strong>: Emphasize regular, automated testing and deployment to enhance rapid iteration, resilience, and adaptability.</p></li><li><p><strong>Enable Local Development</strong>: Use practices and patterns that allow components to be developed and run in local development environments.</p></li><li><p><strong>API First</strong>: Treat APIs as a user-facing and critical part of the product. Design APIs first -- before implementation -- to ensure they meet a user need, are interoperable, and ease integration.</p></li><li><p><strong>Test First</strong>: Write tests before code to clarify requirements, prevent defects early, and maintain code more easily.</p></li><li><p><strong>User-Centric</strong>: Focus on end-user needs, preferences, and feedback in design and development. Endeavor to understand why a user needs a solution and how that solution serves the user's needs.</p></li><li><p><strong>Don't Reinvent</strong>: Avoid "Not Invented Here" Syndrome by preferring to use existing products, services, and libraries instead of developing them in-house. Utilize existing solutions to save time and resources, focusing on unique value propositions. Buy -- not build.</p></li><li><p><strong>You Build It, You Get the Alert</strong>: Put ownership of observability, monitoring, and the resulting alerts on the team that codes it. This ties responsibility to creators, encouraging careful development and a culture of accountability and responsiveness.</p></li><li><p><strong>Graceful Degradation</strong>: Design the system to continue functioning even when some components fail, providing a lower-quality service instead of total failure.</p></li><li><p><strong>Integrate Continuously</strong>: Automate the build and integration process, and use trunk-based development to enable frequent merges, ensuring that code changes are consistently tested and integrated into the shared repository.</p></li><li><p><strong>Security by Design</strong>: Embed security considerations from the outset, including authorization, authentication, and encryption to protect data integrity and privacy.</p></li><li><p><strong>Security by Depth</strong>: Implement multiple security controls throughout the system, layering protections at various levels such as network, host, application, and data, to enhance overall security and ensure that breaching one layer doesn't provide access to others.</p></li><li><p><strong>Reactive Design</strong>: Build systems that respond gracefully to change, whether in load, user behavior, or underlying subsystem behavior.</p></li><li><p><strong>Emphasize Interoperability</strong>: Focus on creating interfaces and components that can work seamlessly with various systems, promoting flexibility and adaptability.</p></li><li><p><strong>Environment Agnosticism</strong>: Design the system to run across various environments and platforms, reducing dependencies on specific technologies or vendors.</p></li><li><p><strong>Immutable Infrastructure</strong>: Once deployed, components are never modified. Use infrastructure as code and recreate components instead of modifying them, ensuring consistency and reducing potential discrepancies across environments.</p></li></ul><p>These principles come from <a href="https://www.oreilly.com/library/view/art-of-scalability/9780134031408/">Art of Scalability</a>:</p><ul><li><p><strong>N + 1 Design</strong>: Ensure that there is at least one additional instance of a system to handle failures. It's about building redundancy for reliability, and follows the rule of three: one for you, one for the customer, and one to fail.</p></li><li><p><strong>Design for Rollback</strong>: Create systems that are backward compatible so that changes can be rolled back if problems arise. It's about being able to revert to a previous state if a failure or issue occurs after an update.</p></li><li><p><strong>Design to Be Disabled</strong>: Create systems with the ability for parts of it to be disabled, especially in risky components. This enables more time to fix issues without the system going down. One way to do this is with feature flags.</p></li><li><p><strong>Design to Be Monitored</strong>: Build systems that are self-diagnosing. This involves monitoring and logging the right information so that scalability issues can be addressed earlier.</p></li><li><p><strong>Design for Multiple Live Sites</strong>: Plan for having multiple geographically dispersed data centers from the design phase. This allows for rapid deployment and helps in ensuring continuity during geographically isolated disasters.</p></li><li><p><strong>Use Mature Technologies</strong>: Employ proven and reliable technology when high availability is required. New technologies may offer competitive advantages but can also introduce more risk.</p></li><li><p><strong>Asynchronous Design</strong>: Design systems to act asynchronously instead of synchronously. Asynchronous systems are more tolerant of slowdowns and do not block the entire chain, enhancing scalability.</p></li><li><p><strong>Stateless Systems</strong>: Avoid maintaining information about previous operations (state) as it can cost money, processing power, availability, and scalability. Designing stateless systems whenever possible simplifies scaling and enhances flexibility.</p></li><li><p><strong>Scale Out, Not Up</strong>: Focus on horizontal scaling (adding more systems) instead of vertical scaling (upgrading a single system). It facilitates near-infinite scaling and is essential to leveraging the elasticity and auto-scaling features of modern infrastructure.</p></li><li><p><strong>Design for at Least Two Axes of Scale</strong>: Think ahead to ensure systems are scalable, considering both present and future needs. Implement strategies like horizontal splits and customer segmentation to accommodate growth.</p></li><li><p><strong>Buy When Non-Core</strong>: Focus on core competencies and purchase non-core components. Building should only occur if it creates a significant difference in the product or platform, enhancing competitive differentiation and shareholder value.</p></li><li><p><strong>Use Commodity Hardware</strong>: Opt for cheaper, commodity hardware if it can scale horizontally and if the cost of ownership, even with higher failure rates, is lower than using higher-end hardware.</p></li><li><p><strong>Build Small, Release Small, Fail Fast</strong>: Emphasize small, iterative development to minimize failure risk, save costs, and allow for quick course corrections if initiatives don't work.</p></li><li><p><strong>Isolate Faults</strong>: Design systems to contain failures within isolated zones, similar to circuit breakers in electrical systems, to prevent a failure in one area from affecting others.</p></li><li><p><strong>Automation over People</strong>: Prefer automation over human involvement for repetitive tasks. Automation is more consistent and often less expensive, making it more reliable and easier to tune for tasks like deployment, builds, testing, monitoring, and alerting.</p></li></ul><p>25 more principle inspirations are available to paid subscribers below.</p>
      <p>
          <a href="https://blog.devdetails.com/p/architecture-principle-examples">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Even if you’re unaware of patterns, you’re using them]]></title><description><![CDATA[Ignoring patterns is a great way to repeat past mistakes]]></description><link>https://blog.devdetails.com/p/even-if-youre-unaware-of-patterns</link><guid isPermaLink="false">https://blog.devdetails.com/p/even-if-youre-unaware-of-patterns</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Sat, 22 Jul 2023 21:19:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!SyTQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Any type of code you&#8217;ve written or are thinking of writing has likely already been done by someone, somewhere. Someone has already identified the pattern you&#8217;re implicitly using and gave it a name and formal definition.</p><p>How we write code today is not innovative. People just keep forgetting and rediscovering patterns that have existed for 50 to 75 years, or even more considering much of software is mathematics.</p><p>Patterns are a shorthand that gets everyone on the same page quickly. If I say &#8220;event actor model&#8221; or &#8220;repository pattern,&#8221; even if you don&#8217;t know them, you can look them up and know what I mean without me having to explain it in detail.</p><div class="pullquote"><p>Know that everything you are about to write likely has a pattern.</p></div><p>Understanding that, instead of starting off designing or writing something from scratch, look for a pattern that matches your use case. You will be able to learn from the mistakes and successes of others. Maybe it&#8217;s the right pattern. Maybe it&#8217;s the wrong pattern. </p><p>At the very least, you will know what not to do. How else will you know that a Singleton is generally a bad idea if you don&#8217;t know what one is? You&#8217;ll just make one and not know its name.</p><p>By writing code, ignorant of patterns, you&#8217;re more likely to repeat the mistakes of others who learned the pros and cons of a particular pattern.<br><br>That&#8217;s good for learning, but bad for productivity.</p><h2>Phases Of Pattern Usage</h2><p>I see developers go through phases with patterns:<br><br>1. No idea about patterns<br>2. Starts seeing patterns<br>3. Realizes others recognized these patterns too<br>4. Sees many more patterns and starts applying them wrongly or too much<br>5. Realizes they went overboard<br>6. Shuns patterns as overkill<br>7. Thinks &#8220;hm, this looks like that pattern I used before&#8221;<br>8. Realizes patterns are good if applied to the problem they were meant to solve when needed<br>9. Realizes patterns, used pragmatically, are simpler than not using patterns<br><br>Typically, for people to learn phase 9, they have to go through all the phases. The sooner you understand this, the sooner you can use patterns to make things simpler, more quickly, and with a shared understanding.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SyTQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SyTQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png 424w, https://substackcdn.com/image/fetch/$s_!SyTQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png 848w, https://substackcdn.com/image/fetch/$s_!SyTQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png 1272w, https://substackcdn.com/image/fetch/$s_!SyTQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SyTQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png" width="1456" height="1020" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1020,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:76346,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!SyTQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png 424w, https://substackcdn.com/image/fetch/$s_!SyTQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png 848w, https://substackcdn.com/image/fetch/$s_!SyTQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png 1272w, https://substackcdn.com/image/fetch/$s_!SyTQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7a95c0c-6d3a-4a22-88b7-acc9aa6c6f53_1465x1026.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><br></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Driving software design forward]]></title><description><![CDATA[The last person I'd let design is me, the Architect]]></description><link>https://blog.devdetails.com/p/driving-software-design-forward</link><guid isPermaLink="false">https://blog.devdetails.com/p/driving-software-design-forward</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Thu, 20 Jul 2023 05:10:27 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Prbv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In order to scale, Architects should not design. They should facilitate the software architecture process. This is how to <a href="https://blog.devdetails.com/p/autonomy-for-software-architecture">scale and enable autonomy</a>.</p><p>But then, who should design? Effectively, all engineers.</p><ul><li><p>Junior Engineers design for small problems that only impact things the team owns</p></li><li><p>Senior Engineers design for large problems that only impact things the team owns</p></li><li><p>Staff Engineers design for problems that may impact things owned by other teams</p></li><li><p>Principal Engineers design for problems that may impact many things owned by many other teams</p></li><li><p>Architects design for problems that impact a majority of the teams and projects</p></li></ul><p>For most designs, the person designing should be someone other than the Architect. Unless all your problems impact a majority of the teams and projects. In that case, I weep for you.</p><p>The Engineer that owns the design is the "Driver" of the design. Architects are always there to assist.</p><p>Let&#8217;s dig into the details.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Prbv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Prbv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Prbv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Prbv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Prbv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Prbv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:79870,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Prbv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Prbv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Prbv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Prbv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F48a47f9a-519c-4e4d-b51e-4db46817a833_1024x1024.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 role="img" 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><title></title><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><h2>Start with the Driver</h2><p>In <a href="https://blog.devdetails.com/p/adopting-daci">DACI</a> terms, the Driver is the person who moves the project forward and is responsible for the decision-making process.</p><p>Ideally, Driver election is voluntary. To get everyone familiar with the concept, though, the Driver might need to be chosen. The Architects, Principal Engineers, or Engineering Managers should help with choosing.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>What does "driving" mean for design?</h2><p>A software design is a means to discuss a problem and how to address it. Ultimately, it results in a decision: How and whether we address the problem.</p><p>A design is only an artifact, though. Designing is an active process that involves many people. Without clear responsibilities, everyone assumes someone else will do it. To set clear responsibilities, there is exactly one Driver.</p><p>The Driver will endeavor to help everyone involved understand and agree on:</p><ul><li><p>the problem</p></li><li><p>what the user needs</p></li><li><p>the constraints we're working with</p></li><li><p>what the business needs</p></li><li><p>the risks involved</p></li><li><p>potential solutions</p></li><li><p>who is impacted</p></li><li><p>what the impact is</p></li><li><p>how we'll solve the problem</p></li></ul><p>Essentially, the Driver aligns everyone on the user's experience, how the current solution fails to meet the user's needs, and how we think we can improve the user's experience. This, in effect, is design. So in effect, the Driver drives the design.</p><p>Drivers aren't just waiting for alignment and approval. They're "driving" for it. That means reaching out and figuring out "what do we need to do to move this forward?".</p><p>In practice, getting alignment means having conversations, researching, informing, and negotiating. The Driver doesn't do all this alone. Software development is a team activity. For a design, there may be many collaborators. An Architect or a more senior engineer that is familiar with the process is one of those collaborators.</p><p>Architects can help with:</p><ul><li><p>removing blockers</p></li><li><p>identifying and connecting to stakeholders</p></li><li><p>conveying technical strategy</p></li><li><p>refining requirements</p></li><li><p>managing expectations</p></li><li><p>mitigating risks</p></li></ul><p>With an Architect's high-level understanding and connections, it seems like they are the ideal person to drive the design.</p><p>Typically the higher level an engineer is, the more they should focus on strategy and elevating other engineers. Architects are no different. If Architects are doing all the designing, they will not have time to do any of their other responsibilities. Just as if a Staff+ Engineer is coding all day, they can not do any of their other responsibilities.</p><p>The team who is responsible for implementing the design and its Engineers are better suited to do the design.</p><p>Not only will they learn more, they will:</p><ul><li><p>feel more ownership of the solution</p></li><li><p>better understand the needs of customers</p></li><li><p>better understand the impact of their work</p></li><li><p>build connections with other teams</p></li></ul><p>In short, they'll be empowered with autonomy. Autonomy, is key to scaling software design.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share Dev Details&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.devdetails.com/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share Dev Details</span></a></p>]]></content:encoded></item><item><title><![CDATA[LeetCode-style algorithms in interviews suck. Cut it out.]]></title><description><![CDATA[Interviews that focus on algorithms get false signals and overlook qualified candidates]]></description><link>https://blog.devdetails.com/p/algorithms-in-interviews-suck-cut</link><guid isPermaLink="false">https://blog.devdetails.com/p/algorithms-in-interviews-suck-cut</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Sat, 08 Jul 2023 20:12:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!DGot!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Modern software development is a spectrum ranging from deep algorithmic work to system design.</p><p>The majority of software development happens between that range.&nbsp;</p><p>Most developers work on application development, which is closer to system design than it is to low-level algorithms.</p><p>Most software development interviews are for jobs somewhere between application development and system design. Yet many interviewers do technical interview rounds only for algorithmic challenges and system design &#8212; nothing in between.&nbsp;</p><p>The assumption here is that if you can solve algorithms and do system design, you have the skills to develop applications. That assumption is flawed. A broad range of skills is needed to develop applications. You will not get them by just practicing a hundred hours to recognize specific algorithm problem patterns. You also won&#8217;t get them by staring at overly simplified systems designs of Netflix, Uber, or <s>Twitter</s> <s>X</s> Threads.</p><p>You get application development skills by, well, developing applications. But many technical interviews do not assess those skills.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DGot!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DGot!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!DGot!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!DGot!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!DGot!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DGot!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:279446,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DGot!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!DGot!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!DGot!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!DGot!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa096b7e1-e28b-4307-a73a-6c30f38fc04e_1024x1024.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 role="img" 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><title></title><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><h2>Algorithm Interviews</h2><p>For clarity, I&#8217;m talking about LeetCode-style algorithmic problems. The majority of algorithmic interviews I&#8217;ve done were LeetCode medium and above. They&#8217;re often referred to as Data Structures and Algorithms (DSA).</p><p>Typically, during an algorithm interview, a candidate is given a problem and is expected to solve and evaluate the solution&#8217;s complexity using Big-O notation in less than 30 minutes. Often, the interview is longer, but time is taken up for introductions and other questions.</p><p>You&#8217;re expected to start by thinking through the problem aloud before writing any code. While solving the problem, you&#8217;re expected to explain your reasoning as you go along. </p><p>Here are some example problems:</p><ul><li><p><a href="https://leetcode.com/problems/maximal-square/">Maximal Square</a> (LeetCode-Medium): Given an <code>m x n</code> binary <code>matrix</code> filled with <code>0</code>'s and <code>1</code>'s, <em>find the largest square containing only</em> <code>1</code>'s <em>and return its area</em>.</p></li><li><p><a href="https://leetcode.com/problems/longest-substring-without-repeating-characters/">Longest Substring Without Repeating Characters</a> (LeetCode-Medium): Given a string <code>s</code>, find the length of the <strong>longest</strong> <strong>substring</strong> without repeating characters.</p></li><li><p><a href="https://leetcode.com/problems/merge-k-sorted-lists/">Merge k Sorted Lists</a> (LeetCode-Hard): You are given an array of <code>k</code> linked-lists <code>lists</code>, each linked-list is sorted in ascending order. <em>Merge all the linked-lists into one sorted linked-list and return it.</em></p></li></ul><p>These problems can be fun to solve when you have time to reason about them. However, in interview scenarios, the time constraint and general pressure of needing to pass to get a job can induce anxiety. To minimize anxiety, candidates prepare by practicing problems to become familiar with the patterns.</p><p>The standard advice from books like &#8220;Cracking The Coding Interview&#8221; (recommended reading by Meta) is to spend several weeks to several months on preparation, depending on your current skill level and familiarity with Data Structures and Algorithms.</p><p>LeetCode's &#8220;Interview Crash Course&#8221; includes 93+ walkthroughs of example problems, 67+ curated practice problems, and 12 quizzes. To get through all this content while you&#8217;re also presumably working or otherwise living your life can take months.</p><p>This brings me to my next point.</p><h2>Don't waste a candidate's valuable time</h2><p>A typical set of interviews includes two algorithm rounds and a system design round. 66% of the technical interview is dedicated to something you will likely code less than 1% of during your entire career.</p><p>I've been doing software development for more than two decades. The only time I study algorithms is:</p><ul><li><p>For fun. Difficult challenges can be fun in your free time when no pressure exists.</p></li><li><p>For an interview.</p></li></ul><p>If they appear in the course of my actual work, I use a (typically built-in) library that is battle tested. Without specializing in that type of work, there is no way I could improve upon them.</p><p>Very few people learn algorithmic development on the job. It requires hours of personal time to practice enough of them to be useful in an interview. They are not job relevant for most developers.</p><h2>Algorithm interviews get false signals</h2><p>Algorithmic challenges in an interview signal only one thing:&nbsp;</p><ul><li><p>You practiced algorithmic challenges enough to recognize their patterns and solve them.</p></li></ul><p>But, they do not signal general development skills. They signal pattern recognition of specific algorithms and preparation more than they signal problem-solving.</p><p>By focusing on a person's ability to solve algorithms under the extreme pressure of the artificial interview environment, you ignore other factors necessary for application development. The biggest being that a candidate can turn business requirements into a solution that solves that business need. Few customers have ever needed you to bubble sort better than another vendor. Besides,&nbsp;<a href="https://www.deepmind.com/blog/alphadev-discovers-faster-sorting-algorithms">AI can already do that better than humans (AlphaDev uncovers up-to 70% faster algorithm for libcc++ sorting library)</a>.</p><p>In the best case, you find candidates that can productively develop applications. In the nominal case, you find candidates that have studied algorithms well enough to pass the interview. In the worst case, you alienate many candidates that do not perform well with "gotcha" type algorithm questions, such as candidates with neurodivergence.</p><h2>Alternatives considered</h2><p>So what should you do instead of using algorithms in interviews?</p><p>Create tests more like what you expect the developer to do regularly and which skills are essential for that work.&nbsp;</p><p>For example, focus on getting signals for:</p><ul><li><p>Interpreting business needs, functional requirements, and non-functional requirements into efficient solutions.</p></li><li><p>Breaking down complex projects into manageable tasks and steps.</p></li><li><p>Application of design patterns.</p></li><li><p>Use <a href="https://blog.devdetails.com/p/architecture-principles-streamline">Architecture Principles</a> like Event Driven Design, API First, and Buy vs. Build.</p></li><li><p>Evaluating what is worth automating (ex: builds and tests in a CI pipeline).</p></li><li><p>Reviewing code effectively and understanding the benefits of this process.</p></li><li><p>Comparing tradeoffs between threading and async coroutines for server construction.</p></li><li><p>Identifying opportunities for performance optimization in code.</p></li><li><p>Debugging and resolving issues in a given piece of code.</p></li><li><p>Refactoring code for improved readability and maintainability.</p></li><li><p>Integrating APIs effectively in software applications.</p></li></ul><p>Unsure of where to start with such a test?&nbsp;<a href="https://codingchallenges.fyi/">Coding Challenges</a>&nbsp;is an excellent resource for challenges that fit these requirements. They're great for interviews or preparing for interviews.</p><h2>Should I learn algorithms?</h2><p>Studying algorithms will make you a better overall developer. But that doesn&#8217;t mean you need to be good at solving them in under 30 minutes while explaining your thinking. Being able to do that has nothing to do with real word software problems. It&#8217;s only useful for the artificial interview environments that are broken and should be changed.</p><p>I recommend you learn challenging algorithms when you have free time and are under no pressure to get a new job. The best thing you actually learn from studying them that can be applied to broader areas is&nbsp;<a href="https://www.bigocheatsheet.com/">Big-O</a>&nbsp;notation and complexity. Understanding Big-O will help you see unneeded complexity in application and system development.</p><p>If you&#8217;re applying to jobs that have algorithm interviews, then you have two options:</p><ol><li><p>Refuse to do algorithm interviews.</p></li><li><p>Learn algorithms and practice them in an interview like environment.</p></li></ol><p>Only one of those will give you a chance to get that particular job. If you want that job, do #2.</p><p>These interviews are flawed. Unfortunately, if you&#8217;re trying to get a job and don&#8217;t have the luxury of refusing to do these types of interviews, then you must do them to get the job.</p><p>Here&#8217;s a <a href="https://github.com/dev-details/resources/blob/main/algorithms.md">list of resources to learn algorithms and Big-O</a> to help you.</p><h2>Conclusion</h2><p>I want to see change in the way we do technical interviews. I don&#8217;t do these types of problems when I give interviews. My goal is to bring awareness so others will change the way they interview.</p><p>If you are giving an interview, consider how you evaluate technical ability. If the job you are interviewing for actually involves working on deep algorithms, absolutely go ahead and test that. If your job is application development or more abstract: cut it out.</p><h2>Updated</h2><p>2023/09/09 clarified my stance in &#8220;Conclusion&#8221; and &#8220;Should I learn algorithms?&#8221;. Clarified what I mean by &#8220;extreme pressure&#8221;.</p><p>2023/09/08 added &#8220;Algorithm Interviews&#8221; section and some clarifications (like &#8220;async coroutines&#8221;) based on feedback from <a href="https://youtu.be/Jy-Bn-nUo_w?si=B03q2WiduxJlDfpI">The Primeagen's reaction video</a>.</p>]]></content:encoded></item><item><title><![CDATA[I wanted to design buildings, but I'm a software architect]]></title><description><![CDATA[Throughout high school, I was interested in building architecture &#127968;.]]></description><link>https://blog.devdetails.com/p/i-wanted-to-design-buildings-but</link><guid isPermaLink="false">https://blog.devdetails.com/p/i-wanted-to-design-buildings-but</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Mon, 26 Jun 2023 15:00:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!m0gq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Throughout high school, I was interested in building architecture &#127968;. I started drafting classes in high school and got my first real job as a drafter at an architectural firm. I was learning home design from the best.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m0gq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m0gq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!m0gq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!m0gq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!m0gq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m0gq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:91923,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!m0gq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!m0gq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!m0gq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!m0gq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10f486a0-b471-4c05-bdd4-4928cde89ae5_1024x1024.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 role="img" 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><title></title><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><br>Then the unexpected happened:</p><ul><li><p>Before the dotcom crash, the firm had a website to sell house plans.</p></li><li><p>The original developers abandoned the project.&nbsp;</p></li><li><p>I was good with computers and had done simple HTML websites, so the owner asked me to take a look.</p></li></ul><p><br>I was enamored. This was the first time I saw a website that actually did something useful for a business. No longer was coding just a fun exercise &#8212; it provided real value.<br><br>I learned how to program a new language and started managing the website alongside my drafting duties. Over time, the website gained more traction. More and more, I was coding instead of drafting.<br><br>Eventually, I decided to go to school for computer science instead of architecture.<br><br>What changed my mind was not just software development's interesting engineering challenges.<br><br>It was that I could provide much more real value to a business with just text on a screen. It was amazing!<br><br>While my path changed, it wasn't as big a leap as it may seem.<br><br>Software and building architecture both require a deep understanding and passion for the principles of design, architecture, mentoring, and project planning.<br><br>The end result? My hobbies flipped:<br></p><ul><li><p>When I was a teenager, software was a hobby, and my career path was building design.&nbsp;</p></li><li><p>As an adult, my career is in software, and my hobby is interior design and building.<br></p></li></ul><p>When I'm not doing software architecture at work &#9000;&#65039;, I'm remodeling my home &#128296;. It allows me to connect better with the physical world.</p><p>The site actually still exists.<br><br>It continued to operate as an outlet for thousands of house plans for hundred of designers for more than 20 years. Even after leaving the company, I did contract work for it from time to time.<br><br>It still exists today, but it only represents the original architecture firm as times have changed with social media.<br><br>So that makes it the longest continually running web service that I have worked on.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Generating application code from tests with AI]]></title><description><![CDATA[Part 5 of a practical example of using AI for coding]]></description><link>https://blog.devdetails.com/p/generating-application-code-from</link><guid isPermaLink="false">https://blog.devdetails.com/p/generating-application-code-from</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Wed, 14 Jun 2023 03:39:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!l0fJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is part 5 of a multi-part series:</p><ul><li><p>In <a href="https://blog.devdetails.com/p/a-practical-example-of-using-ai-for">Part 1</a>, we discussed setup and best practices and answered the question: &#8220;Will AI replace software developers?&#8221;.</p></li><li><p>In <a href="https://blog.devdetails.com/p/designing-software-with-ai">Part 2</a>, we designed a solution and created a design document.</p></li><li><p>In <a href="https://blog.devdetails.com/p/diagrams-and-api-design-with-ai">Part 3</a>, we generated a sequence diagram and an OpenAPI specification.</p></li><li><p>In <a href="https://blog.devdetails.com/p/generating-tests-with-ai">Part 4</a>, we generated tests. First.</p></li><li><p>In Part 5, we&#8217;ll generate the application code.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!l0fJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!l0fJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!l0fJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!l0fJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!l0fJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!l0fJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:403796,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!l0fJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!l0fJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!l0fJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!l0fJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3cedb-2e4b-4ed0-911a-cf5e91968d50_2048x2048.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 role="img" 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><title></title><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><h2>Recap: URL Shortening Service, generated by AI</h2><ul><li><p>We&#8217;re writing a solution for the&nbsp;<a href="https://codingchallenges.fyi/challenges/challenge-url-shortener/">URL Shortener Challenge</a>.</p></li><li><p>We&#8217;ve got a great design that we visualized with PlantUML and generated OpenAPI specifications for.</p></li><li><p>ChatGPT generated some tests.</p></li><li><p><em>Developers that use AI will replace those who don't&nbsp;&nbsp;&#8212; It will take more time before AI completely replaces developers.</em></p></li></ul><h2>Generating an application from tests</h2><p>If you&#8217;re not a fan of Test First development like me, you&#8217;re glad to finally be writing application code. You&#8217;re probably wondering why we didn&#8217;t just start there and ignore all this design and business needs nonsense. You might want to learn about <a href="https://blog.devdetails.com/p/autonomy-for-software-architecture">how all this nonsense makes teams autonomous.</a>  </p><h3>Boilerplate</h3><p>Boilerplate first. The code base has to be set up. I asked ChatGPT to give me commands for the poetry stuff. I&#8217;ll summarize it here.</p><ul><li><p>Using <a href="https://python-poetry.org/">poetry</a> to manage dependencies, create a <code>pyproject.toml</code> file with <code>poetry init</code>, adding <a href="https://github.com/spec-first/connexion">connexion</a> and <code>redis</code> as a dependency.</p></li><li><p><code>poetry add --dev</code> the test dependencies like <code>pytest</code>, <code>freezegun</code>, and <code>fakeredis</code>.</p></li><li><p>Paste tests into <code>test_shorty.py</code></p></li><li><p>Run the tests.</p></li></ul><p>Of course, they fail; we have no application code.</p><h3>Generate the code for real this time</h3><p>To generate the code, I&#8217;m using <a href="https://plugins.jetbrains.com/plugin/21056-codegpt">CodeGPT plugin</a> for PyCharm.</p><p>I select the code and use this prompt:</p><pre><code><code>Write an implementation that satisfies these tests in the selected code. Here is the design doc:

{complete design document}</code></code></pre><p>Note the &#8220;selected text&#8221; part. It uses whatever I have selected in the IDE as part of the input.</p><blockquote><pre><code>import hashlib
import random
import string
from datetime import timedelta
from flask import Flask, jsonify, redirect, request, url_for
from redis import Redis

app = Flask(__name__)
redis = Redis(host='redis', port=6379)

BASE_URL = "http://example.com/"
...</code></pre></blockquote><div><hr></div><p>&#128721; Stop generating!</p><p>It did a decent implementation, but it forgot one important piece:</p><pre><code>Not quite. This uses connexion as specified in the specs.</code></pre><p>After a quick and familiar apology:</p><blockquote><p>My apologies for that mistake.</p><p>Here is the updated source code using connexion:</p><pre><code>import hashlib
import random
import string
from datetime import timedelta
import connexion
from redis import Redis


app = connexion.FlaskApp(__name__, specification_dir="./")
app.add_api("openapi.yaml")


redis = Redis(host='redis', port=6379)

BASE_URL = "http://example.com/"

def generate_short_code(url: str) -&gt; str:
    """
    Generate a short code for the given URL.
    """
    # Generate a unique hash for the URL using SHA1
    sha1_hash = hashlib.sha1(url.encode('utf-8')).hexdigest()
    # Convert the hash to base62
    base62_hash = encode_base_n(int(sha1_hash, 16), 62)
    # Truncate the hash to 7 characters to get the short code
    short_code = base62_hash[:7]
    return short_code

...etc etc</code></pre></blockquote><div><hr></div><p>And just like that, it&#8217;s done. The code was close to correct without much cajoling because it had the tests and the design doc to work with.</p><p>It did need some corrections, though. The following prompts were followed by selecting the relevant part of the code and explaining the problem:</p><ul><li><p>The url_sha1 should be base62 encoded instead of hex encoded.</p></li><li><p>base62 is not a real module. Use the existing encode_base_n function instead</p></li><li><p>In the selected code, there is a lot of duplication. Be DRY.</p><ul><li><p>That made the duplication worse. &#129318;&#127996;</p></li></ul></li><li><p>Why is the selected code getting a TypeError('not all arguments converted during bytes formatting')</p></li><li><p>How do I convert bytes to an int? (Yes, I was being lazy)</p></li></ul><p> After many apologies, we got a good enough solution for me to take over with.</p><h2>Make it work</h2><p>The next part is not glamorous unless you like Test First development &#129321;.</p><ul><li><p>Run the tests.</p></li><li><p>Get an error.</p></li><li><p>Fix the error by letting <a href="https://aws.amazon.com/codewhisperer/">CodeWhisperer</a>&nbsp;auto-complete your thoughts.</p></li><li><p>Repeat until all the tests pass.</p></li></ul><div><hr></div><p>You can <a href="https://github.com/dev-details/ai-code-example/tree/main">view the complete code</a> along with:</p><ul><li><p>Design Document</p></li><li><p>PlantUML diagram</p></li><li><p>OpenAPI specification</p></li><li><p>Tests</p></li><li><p>Prompts</p></li><li><p>A note from our AI partner</p></li></ul><div><hr></div><h2>Conclusion</h2><ul><li><p>Most of the time was spent designing a solution with ChatGPT. </p></li><li><p>But that made everything else go faster. </p></li><li><p>The design doc was fed into the prompt to generate tests, generating correct tests nearly immediately.</p></li><li><p>Asking AI to generate code that satisfies a selected set of tests is freaky, but it works. It would not work as well if I didn&#8217;t supply it a design doc first.</p></li><li><p>The moral of this really is:</p><ul><li><p>Design First</p></li><li><p>API First</p></li><li><p>Test First</p></li></ul></li><li><p>Whether you get AI to help you with each stage or not, your results will be better, less error-prone, and faster.</p></li><li><p>And doing it with AI is faster and fun but also frustrating.</p></li></ul><h2>Alternatives Considered</h2><blockquote><p>What if I skipped all this design, test, PlantUML, etc. stuff and just pasted the challenge as a prompt into ChatGPT 4?</p></blockquote><ul><li><p>For a well know problem like a URL Shortener, it will give you working code right away.</p></li><li><p>When I tried it, it generated a partial &#8220;example&#8221; Javascript solution using the Express framework and MongoDB for storage.</p></li><li><p>I could tell it, &#8220;Write it in Python backed by redis.&#8221;</p></li><li><p>Then I could ask for alternatives to generating short URLs other than random letter choices.</p></li><li><p>And then I could ask it to write tests.</p></li><li><p>I could walk through each minor change with it and eventually come to a similar solution as starting with the design first.</p></li><li><p>Maybe I would have thought about traffic loads and other non-functional requirements. Maybe I would have thought of expiring URLs.</p></li></ul><p>Here&#8217;s the thing, though.</p><div class="pullquote"><p>It would have taken more time, I would have learned less, and the solution would have been less robust.</p></div><p>That might be okay when a quick and dirty solution is sufficient. My goal was to show you a practical example of how you can use generative AI to aid your work. </p><p>At a certain level, quick and dirty is not good enough.</p><p>By writing the design document first, we had thought through all the major details, so it was quick and easy when it came time to write code. Notice how this part of the article series was the shortest? </p><p>We could also have handed the design document to someone else, perhaps someone to develop the UI. Perhaps another AI. We would not have to walk them through every step to figure out what the software should do in order to generate the UI. </p><p>We&#8217;d start with the design doc and tell them to write code for it.</p><p>The design doc, the diagrams, and the API specification all contribute to making collaboration with other developers (human or AI) faster and more productive.</p><div><hr></div><h2>Next</h2><p>All done. Thanks for the journey.</p><ul><li><p><a href="https://blog.devdetails.com/p/a-practical-example-of-using-ai-for">Part 1: Setup and Process</a></p></li><li><p><a href="https://blog.devdetails.com/p/designing-software-with-ai">Part 2: Design</a></p></li><li><p><a href="https://blog.devdetails.com/p/diagrams-and-api-design-with-ai">Part 3: Sequence diagram and API specification</a></p></li><li><p><a href="https://blog.devdetails.com/p/generating-tests-with-ai">Part 4 Generating tests</a></p></li><li><p>Part 5: Generating the application and making it work &#8592; YOU ARE HERE</p><p></p></li></ul><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Generating tests with AI]]></title><description><![CDATA[Part 4 of a practical example of using AI for coding]]></description><link>https://blog.devdetails.com/p/generating-tests-with-ai</link><guid isPermaLink="false">https://blog.devdetails.com/p/generating-tests-with-ai</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Wed, 14 Jun 2023 03:38:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!8RG1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is part 4 of a multi-part series:</p><ul><li><p>In <a href="https://blog.devdetails.com/p/a-practical-example-of-using-ai-for">Part 1</a>, we discussed setup and best practices and answered the question: &#8220;Will AI replace software developers?&#8221;.</p></li><li><p>In <a href="https://blog.devdetails.com/p/designing-software-with-ai">Part 2</a>, we designed a solution and created a design document.</p></li><li><p>In <a href="https://blog.devdetails.com/p/diagrams-and-api-design-with-ai">Part 3</a>, we generated a sequence diagram and an OpenAPI specification.</p></li><li><p>In Part 4, we&#8217;ll generate tests.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8RG1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8RG1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!8RG1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!8RG1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!8RG1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8RG1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:411151,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8RG1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!8RG1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!8RG1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!8RG1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fb8a869-f3a9-4c54-a901-57497c48c3e8_2048x2048.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 role="img" 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><title></title><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><h2>Recap: URL Shortening Service</h2><ul><li><p>We&#8217;re writing a solution for the&nbsp;<a href="https://codingchallenges.fyi/challenges/challenge-url-shortener/">URL Shortener Challenge</a>.</p></li><li><p>We&#8217;ve got a great design.</p></li><li><p><em>AI won't replace developers; developers that use AI will replace those who don't.&nbsp;&nbsp;</em></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Test First</h2><p>I like Test Driven Development development. I usually write tests during coding -- interwoven with my coding.</p><p>In this case, I'm generating tests first, then using a different tool to write application code to demonstrate using AI in multiple ways.</p><p>Good tests describe the business use cases of our software. So, like the other prompts, let&#8217;s use our design document for this prompt.</p><pre><code>You and I are software engineers. We will use pair-development. Our goal is to craft the best possible application to satisfy the design. 

We will follow this process:

1. You will write tests that fit the design
2. We'll discuss the tests until they satisfy the design

{complete design document}</code></pre><p>It&#8217;s important to note a critical part of the <a href="https://github.com/dev-details/ai-code-example/blob/main/design.md">design document</a>. At the end is a style guide. This style guide drives how ChatGPT will generate the tests.</p><pre><code>## Style Guide

Our organization follows these principles for development.

- DRY
- SOLID
- TDD

Our company follows these coding styles and best practices:

- Use Python `black` formatting.
- Use Python type hints.
- Pytest for testing.
- Testing:
    - All business use cases should be covered in the tests.
    - Focus testing on business case functional testing to test at API
      boundaries such as REST APIs -- not class-level
      tests.
    - For fake data use "example" in the name. "test" must only be used for the
      test names themselves.
    - If monkey-patching or other dependency injection is necessary, only do so
      in pytest fixtures -- no dependency
      injection in tests themselves.
    - Use testing analogs for external dependencies like databases. Do not use
      test analogs for our own code.
    - Testing analogs should function the same as the libraries and services
      they mimic. Only implement as much analog
      functionality as needed for the test.
    - For test analogs, use "fake" in the name.</code></pre><p>ChatGPT takes this into account when generating the tests:</p><blockquote><pre><code>import pytest
from datetime import timedelta
from freezegun import freeze_time
from urllib.parse import urlparse
from your_app import create_app
from your_app.shortener import url_hash, generate_short_code

# create a fixture for test client
@pytest.fixture
def client():
    app = create_app()
    with app.test_client() as client:
        yield client

def test_shorten_valid_url(client):
    url = "https://www.very-long-url.com/"
    response = client.post('/shorten', json={'url': url})
    assert response.status_code == 200
    assert 'url' in response.get_json()
    short_code = urlparse(response.get_json()['url']).path.strip('/')
    assert short_code == generate_short_code(url_hash(url))

def test_redirect_to_long_url(client):
    url = "https://www.very-long-url.com/"
    # first we need to generate the short URL
    response = client.post('/shorten', json={'url': url})
    assert response.status_code == 200
    short_code = urlparse(response.get_json()['url']).path.strip('/')
    # then we use the short URL
    response = client.get('/' + short_code)
    assert response.status_code == 302
    assert response.headers['Location'] == url

@freeze_time("2023-06-10")
def test_expired_short_url(client):
    url = "https://www.very-long-url.com/"
    # first we generate the short URL
    response = client.post('/shorten', json={'url': url})
    assert response.status_code == 200
    short_code = urlparse(response.get_json()['url']).path.strip('/')
    # then we time travel 24 hours into the future
    with freeze_time("2023-06-11"):
        response = client.get('/' + short_code)
        assert response.status_code == 404

# [truncated]</code></pre></blockquote><div><hr></div><p>This is close. It covered most of the use cases in the first pass and styled the code based on the style guide.</p><p>Like with most of the other design and development phases with ChatGPT, this will be a conversation to generate optimal results.</p><pre><code>- generate_short_code is not idempotent so we can not use it this way in our tests. To verify the URL is shortened, validate the output URL matches the requirements, then call it to verify we are redirected.
- Call the app "shorty"
- Remember to use black formatting
- Do we have any external dependencies we need to fake?</code></pre><blockquote><p>You're right about the idempotence, my mistake. Instead, we'll validate the shortened URL by checking its length and calling it to verify the redirection.</p><p>As for external dependencies, we are using Redis as our backend storage. When testing, we don't want to rely on an actual Redis instance as it might not be available or it might have unexpected data. Therefore, we'll use a fake Redis server for our tests. Python has a library for that called <code>fakeredis</code>.</p><p>Now, let's modify our tests to use "shorty" as the app name and to use <code>fakeredis</code>. We'll also format the tests using <code>black</code>:</p><pre><code>from shorty import create_app
from fakeredis import FakeStrictRedis

@pytest.fixture
def client():
    app = create_app()
    app.config["REDIS"] = FakeStrictRedis()

    with app.test_client() as client:
        yield client</code></pre></blockquote><div><hr></div><p>More revisions, please.</p><pre><code>- test_redirect_to_long_url is now redundant. 
- Are there any other use cases we should cover?</code></pre><blockquote><p>You're correct. The <code>test_shorten_valid_url</code> test already covers the redirection to the long URL, so <code>test_redirect_to_long_url</code> is indeed redundant.</p><p>As for other use cases, we could add a test for the case where the user tries to access a non-existent short URL. This could happen if a user makes a typo when entering the URL manually, or if there's an issue with the code generating or storing the short URLs.</p><p>Here's a test for this use case:</p><pre><code>def test_nonexistent_short_url(client):
    response = client.get("/nonexistent")
    assert response.status_code == 404
    assert "error" in response.get_data(as_text=True)</code></pre><p>Additionally, we should consider adding a test to ensure that the shortened URLs are unique for different long URLs within the 24-hour period. Here is a test case for that:</p></blockquote><div><hr></div><p>We continue:</p><pre><code>looks good. One revision, for test_nonexistent_short_url, validate the error string contains a human friendly message. Generate the new test file.</code></pre><p>Then ChatGPT forgets what it&#8217;s doing:</p><pre><code>Some test cases are now missing such as expired URL. What happened to fakeredis?</code></pre><blockquote><p>My apologies for the confusion. Let's reintroduce the missing test case for an expired URL and include the fakeredis as a fixture for testing Redis-related functionality. Below are the changes:</p></blockquote><div><hr></div><p>At least we can get it back on track easily.</p><p>After a few iterations, we have a complete set of tests.</p><p>ChatGPT has understood our testing requirements. If I did not specify them, it would have generated less useful unit tests, used poor naming conventions, and littered test code with dependency injection.</p><p>The final results needed a few small tweaks to get the boilerplate setup done correctly. The tests themselves were spot on.</p><p>You can <a href="https://github.com/dev-details/ai-code-example/blob/main/test_shorty.py">view the completed test file</a>.</p><p>Now we can take these tests, drop them into our IDE and write code to satisfy them.</p><div><hr></div><h2>Next</h2><p>Head to Part 5. <a href="https://blog.devdetails.com/p/generating-application-code-from">Continue the journey.</a></p><ul><li><p><a href="https://blog.devdetails.com/p/a-practical-example-of-using-ai-for">Part 1: Setup and Process</a></p></li><li><p><a href="https://blog.devdetails.com/p/designing-software-with-ai">Part 2: Design</a></p></li><li><p><a href="https://blog.devdetails.com/p/diagrams-and-api-design-with-ai">Part 3: Sequence diagram and API specification</a></p></li><li><p>Part 4: Generating tests &#8592; YOU ARE HERE</p></li><li><p><a href="https://blog.devdetails.com/p/generating-application-code-from">Part 5: Generating the application and making it work</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Diagrams and API design with AI]]></title><description><![CDATA[Part 3 of a practical example of using AI for coding]]></description><link>https://blog.devdetails.com/p/diagrams-and-api-design-with-ai</link><guid isPermaLink="false">https://blog.devdetails.com/p/diagrams-and-api-design-with-ai</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Wed, 14 Jun 2023 03:37:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ab73021f-15da-49ee-8d09-e55245bff7b2_2048x2048.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is part 3 of a multi-part series:</p><ul><li><p>In <a href="https://blog.devdetails.com/p/a-practical-example-of-using-ai-for">Part 1</a>, we discussed setup and best practices and answered the question: &#8220;Will AI replace software developers?&#8221;.</p></li><li><p>In <a href="https://blog.devdetails.com/p/designing-software-with-ai">Part 2</a>, we designed a solution and created a design document.</p></li><li><p>In Part 3, we will generate a sequence diagram and an OpenAPI specification.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EVo8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EVo8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EVo8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EVo8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EVo8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EVo8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:417456,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EVo8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EVo8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EVo8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EVo8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6639dbd-41ad-4c13-9c16-68ce55e654f5_2048x2048.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 role="img" 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><title></title><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><h2>Recap: URL Shortening Service</h2><ul><li><p>We&#8217;re writing a solution for the&nbsp;<a href="https://codingchallenges.fyi/challenges/challenge-url-shortener/">URL Shortener Challenge</a>.</p></li><li><p>We&#8217;ve got a great design.</p></li></ul><h2>Visualizing The Design</h2><p>Few things explain what software is supposed to do more than a sequence diagram.</p><ul><li><p>ChatGPT can&#8217;t currently generate images, but it can generate <a href="https://plantuml.com/">PlantUML</a> text diagrams, and we can feed that into the <a href="http://www.plantuml.com/plantuml/uml/">online renderer</a> (or, as I prefer, an IDE plugin) to get an image.</p></li></ul><p>To visualize the design, I asked ChatGPT 4 (3.5 was not working out) to generate the diagram.</p><pre><code><code>Write a PlantUML sequence diagram for the API interactions of the design below.

- Use descriptive aliases. Don't use one-letter aliases.
- Activate/deactivate each component in the sequence diagram when appropriate
- Separate use cases with section titles
- Use "actor" instead of `participant` for the user
- Include each record of the data model that we need to store

{complete design document}</code></code></pre><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VXVV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VXVV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png 424w, https://substackcdn.com/image/fetch/$s_!VXVV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png 848w, https://substackcdn.com/image/fetch/$s_!VXVV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png 1272w, https://substackcdn.com/image/fetch/$s_!VXVV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VXVV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png" width="962" height="1084" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a360b5da-729d-4d57-954a-e079920f6307_962x1084.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1084,&quot;width&quot;:962,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84773,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&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_!VXVV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png 424w, https://substackcdn.com/image/fetch/$s_!VXVV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png 848w, https://substackcdn.com/image/fetch/$s_!VXVV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png 1272w, https://substackcdn.com/image/fetch/$s_!VXVV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa360b5da-729d-4d57-954a-e079920f6307_962x1084.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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></blockquote><div><hr></div><p>That&#8217;s pretty good. You can also <a href="https://github.com/dev-details/ai-code-example/blob/main/design.puml">view the PlantUML source</a> or <a href="https://github.com/dev-details/ai-code-example/blob/main/design.svg">an SVG</a>.</p><h2>API First</h2><p>I like API First development. </p><ul><li><p>It helps to get everyone on the same page of what the API will be before any code is written. </p></li><li><p>I use <a href="https://www.openapis.org/">OpenAPI</a> to describe APIs and share the specifications with team members.</p></li><li><p>UI developers can start coding without the server, and server developers can start coding without a UI. </p></li><li><p>When they&#8217;re both done, they integrate, and since the API was agreed upon first, it just works.</p></li></ul><p>So let&#8217;s have ChatGPT generate the OpenAPI spec. </p><pre><code>Your task is to generate an OpenAPI specification for API described in the 
design doc below.

- Included example requests and responses to cover the defined use cases.
- Provide example HTML errors in the spec.
- Use the PEP-8 standard for naming Python functions
- For the example domain, use `example.com`
- The error message should be in an `error` key
- Since we're using connexion, the operationId should point to the Python module 
  and function that will handle the request

{complete design document}</code></pre><ul><li><p>Here ChatGPT 3.5 worked well.</p></li><li><p>ChatGPT 4 provided more thorough results with better examples.</p></li></ul><blockquote><pre><code>openapi: 3.0.0
info:
  title: URL Shortening Service
  description: Service to shorten long URLs.
  version: 1.0.0
servers:
  - url: https://example.com/
paths:
  /shorten:
    post:
      summary: Shorten a URL
      operationId: shorty.shorten_url
      requestBody:
        description: URL to shorten
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Url'
            examples:
              shortenUrlRequest:
                value:
                  url: "https://www.very-long-url.com/"</code></pre></blockquote><div><hr></div><p>You can <a href="https://github.com/dev-details/ai-code-example/blob/main/openapi.yaml">view the complete generated OpenAPI specification</a>.</p><p>We&#8217;ll use this OpenAPI specification in our application development. </p><div><hr></div><h2>Next</h2><p>Head to Part 4. <a href="https://blog.devdetails.com/p/generating-tests-with-ai">Continue the journey.</a></p><ul><li><p><a href="https://blog.devdetails.com/p/a-practical-example-of-using-ai-for">Part 1: Setup and Process</a></p></li><li><p><a href="https://blog.devdetails.com/p/designing-software-with-ai">Part 2: Design</a></p></li><li><p>Part 3: Sequence diagram and API specification &#8592; YOU ARE HERE</p></li><li><p><a href="https://blog.devdetails.com/p/generating-tests-with-ai">Part 4: Generating tests</a></p></li><li><p>Part 5: Generating the application and making it work</p><p></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Designing software with AI]]></title><description><![CDATA[Part 2 of a practical example of using AI for coding]]></description><link>https://blog.devdetails.com/p/designing-software-with-ai</link><guid isPermaLink="false">https://blog.devdetails.com/p/designing-software-with-ai</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Wed, 14 Jun 2023 03:36:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5zTO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is part 2 of a multi-part series:</p><ul><li><p>In <a href="https://blog.devdetails.com/p/a-practical-example-of-using-ai-for">Part 1</a>, we discussed setup and best practices and answered the question: &#8220;Will AI replace software developers?&#8221;.</p></li><li><p>In Part 2, we will design a solution and create a design document.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5zTO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5zTO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5zTO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5zTO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5zTO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5zTO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:381765,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5zTO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5zTO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5zTO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5zTO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4295096a-a10a-4403-83e9-29e9de711d64_2048x2048.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 role="img" 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><title></title><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><h2>Recap: The Scenario</h2><p>AI is pretty great at leet code examples. I am not. Also, I said this would be a practical example. Leet code is not indicative of real-life work.&nbsp;</p><div class="pullquote"><p><em>(Anyone picking up that leet code and I are not on good terms?)</em></p></div><p>For practical examples, it helps to use something similar to real-life work.&nbsp;</p><ul><li><p><a href="https://codingchallenges.fyi/">Coding Challenges</a>&nbsp;is an excellent resource for building real-world applications.&nbsp;</p></li><li><p>A&nbsp;<a href="https://codingchallenges.fyi/challenges/challenge-url-shortener/">URL Shortener Challenge</a>&nbsp;looks like a good, practical example to work with.</p></li></ul><h2>Design</h2><p>I&#8217;ve formulated a prompt that lays out the roles, goals, and process and establishes the AI as a collaborator. I&#8217;ve also included the Design Document template in the prompt to help guide the end result.</p><p>I used ChatGPT 3.5 for this portion. I also used ChatGPT 4 as a test run, and it yielded better results, but I want to give you an idea of what 3.5 is capable of.</p><div><hr></div><p>I started off by prompting ChatGPT:</p><pre><code><code>You and I are software engineers. We will design software together. Our goal is to design the best possible application to satisfy the business requirements. 

Ask me clarifying questions as needed.

We will follow this process:

1. Discuss problem context
2. Discuss use cases
3. Discuss functional requirements
4. Discuss non-functional requirements (traffic, SLA, security, privacy, etc.)
5. Discuss data model
6. Discuss implementation details
7. Discuss observability (monitoring, logging)
8. Discuss any remaining design sections.
9. Finalize design.

At the end of each step in the process, we will update the design document.

Here is the design document template:

# {Design Name}

## Context

{Describe the problem}  

## Functional Requirements

- {requirement 1}

## Non-functional requirements

- {requirement 1}

## Use Cases

{Business use cases and user experience}

- {use case 1}

## Exclusions

{Things we are explicitly not doing}

- {exclusion 1}

## Implementation Details

- {detail 1}

### {Topic}
  
- {detail 1}

### Data Model

{data model overview}

#### {model 1}

{model description}

### Input Validation

- {validation}

## Observability

### Metrics

- {metric 1}

### Logging

- {logging 1}

## Privacy and Security

- {security 1}

## Deployment

- {deployment 1}

## API

The API has the following endpoints:

1. `{path}` - A `{HTTP method}` endpoint {description}.

## Style Guide

Our organization follows these principles for development.

- DRY
- SOLID
- TDD

Our company follows these coding styles and best practices:

- {style 1}</code></code></pre><blockquote><p>Great! Let's begin the process of designing the software application.</p><h3><strong>Step 1: Discuss problem context</strong></h3><p>Could you please provide some details about the problem that the application needs to solve? It would be helpful to understand the business domain, target users, and any specific pain points or goals that the application aims to address.</p></blockquote><div><hr></div><p>Okay, it picked up on the process and is guiding us.</p><p>I gave it the first bit of our <a href="https://codingchallenges.fyi/challenges/challenge-url-shortener">URL shortener coding challenge</a>:</p><pre><code><code>This challenge is to build your own URL shortening service. Think bit.ly or tinyurl.com.

Basically it&#8217;s a service that lets a client submit a long URL which is then shortened to make it easier to use. For example:

https://www.amazon.com/Rust-Programming-Language-2nd/dp/1718503105/ref=sr_1_1?crid=3977W67XGQPJR&amp;keywords=the+rust+programming+language&amp;qid=1685542718&amp;sprefix=the+%2Caps%2C3079&amp;sr=8-1

could become: https://tinyurl.com/bdds8utd

This is typically done with a web based user interface, that let&#8217;s users enter a long URL and get back a shortened version of the URL. For example:


The shortening service then keeps a record of the short code, i.e. bdds8utd in the example above and the long URL that it maps to. Then when a client requests the shortened URL the service returns a HTTP redirect code, sending them to the long URL.</code></code></pre><blockquote><p>Thank you for providing the problem context. I understand that we need to build a URL shortening service that takes a long URL as input and provides a shortened version of the URL as output. The service should also store a mapping between the shortened URL and the corresponding long URL. When a client accesses the shortened URL, they should be redirected to the original long URL.</p><p>Let's move on to the next step.</p><h3><strong>Step 2: Discuss use cases</strong></h3><p>Can you provide some specific use cases or scenarios that users might encounter when using the URL shortening service?</p></blockquote><div><hr></div><p>I could think up use cases here, but let&#8217;s see what ChatGPT thinks:</p><pre><code><code>What use cases do you foresee?</code></code></pre><blockquote><ol><li><p><strong>Shorten URL</strong>: Users can input a long URL into the service and request a shortened URL.</p></li><li><p><strong>Retrieve Short URL</strong>: Users can retrieve the shortened URL associated with a specific long URL.</p></li><li><p><strong>Redirect to Long URL</strong>: When users access a shortened URL, they are redirected to the original long URL.</p></li><li><p><strong>Analytics and Statistics</strong>: The service can provide analytics and statistics on the usage of the shortened URLs, such as the number of clicks or the geographical location of the users.</p></li></ol></blockquote><div><hr></div><p>Analytics is a realistic business need, but it&#8217;s too much work for our example.</p><pre><code><code>We will not worry about analytics in this version. Let's continue with those use cases.</code></code></pre><blockquote><p>Understood. </p><p>Let's proceed to the next step.</p><h3><strong>Step 3: Discuss functional requirements</strong></h3><p>From the use cases we discussed, here are the functional requirements:</p><ol><li><p><strong>Shorten URL</strong></p><ul><li><p>The service should accept a long URL from the user.</p></li><li><p>It should generate a unique shortened URL for the given long URL.</p></li><li><p>The mapping between the shortened URL and the long URL should be stored in the system.</p></li><li><p>The shortened URL should be returned to the user.</p></li></ul></li><li><p><strong>Retrieve Short URL</strong></p><ul><li><p>The service should allow users to retrieve the original long URL associated with a specific shortened URL.</p></li></ul></li><li><p><strong>Redirect to Long URL</strong></p><ul><li><p>When a user accesses a shortened URL, the service should redirect them to the corresponding long URL.</p></li></ul></li></ol></blockquote><div><hr></div><p>Cool. This time ChatGPT anticipated functional requirements.</p><p>Let&#8217;s throw in some more:</p><pre><code><code>- The code should be short, less than 10 chars
- The API should be a JSON API
- When visiting a short URL that is not found, the response should be an HTML error page with an appropriate HTTP status code and an error message instead of JSON</code></code></pre><blockquote><p>Great! I've added the additional functional requirements you mentioned</p><h3><strong>Step 4: Discuss non-functional requirements</strong></h3><p>In addition to the functional requirements, we should also consider the non-functional requirements that are important for the successful operation and performance of the URL shortening service.</p></blockquote><div><hr></div><p>&#128161; Don&#8217;t worry. I&#8217;m not going to paste all the output. I wanted to give you a sense that it does (more or less) know what it&#8217;s talking about. I&#8217;ll summarize the conversation more from here on out.</p><div><hr></div><p>ChatGPT wants to jump to listing non-functional requirements. I would like to brainstorm here. Our traffic needs will dictate some non-functional requirements, so we&#8217;ll start there.</p><pre><code><code>Let's estimate how much traffic we will have and how many URLs we need to store. How much traffic should we expect?</code></code></pre><blockquote><ul><li><p>Daily Traffic: Assume a moderate number of users initially, such as 1000 requests per day.</p></li><li><p>Request Rate: Assuming a uniform distribution of requests throughout the day, we can estimate around 70 requests per hour (1000 requests / 24 hours).</p></li><li><p>Peak Traffic: Consider the possibility of occasional spikes in traffic, especially during peak usage times. We can assume a peak traffic rate of 2-3 times the average request rate, resulting in around 140-210 requests per hour during peak periods.</p></li></ul></blockquote><div><hr></div><p>&#129393; This is a very modest traffic load. It&#8217;s probably realistic for a service with no marketing budget, but it would be hard to code something that doesn&#8217;t meet these needs. Let&#8217;s spice it up a little bit.</p><p>I asked my coding partner some leading questions to figure out what we could handle on a modest budget instead. </p><pre><code><code>Let's work backwards from storage to see what capacity we could support. We will store the data in-memory in Redis. We only want to use 2GB of RAM. How many URLs can we store?</code></code></pre><blockquote><ul><li><p>Assume each URL entry requires 100 bytes of memory. This includes the long URL, the shortened URL, and any additional metadata.</p></li><li><p>Considering the 2GB RAM constraint, we have approximately 2,000,000,000 bytes available.</p></li></ul></blockquote><div><hr></div><p>Hm &#129300;. I&#8217;m no mathematician magician, but that looks off. ChatGPT 3.5 seems to have issues doing math calculations. I will skip over the glaring calculation detail for now and address the more significant issue first.</p><pre><code><code>100 bytes seems short for a URL shortener. Likely users will want to shorten much longer URLs. What should we plan for for long URLs?</code></code></pre><blockquote><p>So, with an estimated average URL entry size of 500 bytes, we can store approximately 4 million URLs in Redis while utilizing 2GB of RAM.</p></blockquote><div><hr></div><p>Okay. The math checks out this time. But 500 seems arbitrary. I&#8217;ll guide ChatGPT to a more informed choice with some leading questions.</p><pre><code><code>What is the maximum URL length?</code></code></pre><blockquote><p>The maximum length of a URL is not strictly defined by any standard or specification.</p><p>For practical purposes, it's recommended to consider keeping URLs reasonably concise and within a reasonable length limit, typically around 2,000 to 4,000 characters.</p></blockquote><pre><code><code>Do web browsers impose a limit?</code></code></pre><blockquote><p>Yes, web browsers do impose a limit on the length of URLs they can handle. This limit is set by the individual browsers and can vary across different browser versions.</p><p>The maximum URL length that browsers can handle typically ranges from 2,000 to 8,000 characters.</p></blockquote><p></p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/p/designing-software-with-ai?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thank you for reading Dev Details. This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/p/designing-software-with-ai?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.devdetails.com/p/designing-software-with-ai?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p>&#128064; My independent research of Googling things and clicking on random StackOverflow links says various degrees of &#8220;some browsers support a ridiculously long URL, but you&#8217;ll have the most compatibility with around 2,000 characters.&#8221;</p><p>So I make a judgment call of using 1000 bytes on average for our calculations.</p><p>ChatGPT 3.5 can often be wrong on calculations. It helps to ask for more detail in tables to see if it&#8217;s thinking correctly.</p><pre><code><code>Let's plan for an average of 1000 bytes per URL. Give me a table of traffic and data estimates for this size of URL as well as the total RAM we'll need. We will want to allow room for spikes in traffic. Allow for a 10x spike.

Include the columns: scale, urls per hour, urls per day, urls per month, data per day, data per month

Show rows for different RAM amounts: 1 GB, 2 GB, 4 GB.</code></code></pre><blockquote><p>Sure! Let's estimate the traffic and data requirements based on an average URL size of 1000 bytes, and also factor in spikes in traffic. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uv4K!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uv4K!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png 424w, https://substackcdn.com/image/fetch/$s_!uv4K!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png 848w, https://substackcdn.com/image/fetch/$s_!uv4K!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png 1272w, https://substackcdn.com/image/fetch/$s_!uv4K!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uv4K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png" width="1456" height="589" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:589,&quot;width&quot;:1456,&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;:true,&quot;topImage&quot;:false,&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_!uv4K!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png 424w, https://substackcdn.com/image/fetch/$s_!uv4K!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png 848w, https://substackcdn.com/image/fetch/$s_!uv4K!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png 1272w, https://substackcdn.com/image/fetch/$s_!uv4K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb7d9f6d-6e71-4235-a814-4cd25b93ebfd_1458x590.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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></blockquote><div><hr></div><p>I didn&#8217;t bother checking if those numbers were correct. It&#8217;s not really the data I&#8217;m looking for. I want ChatGPT to figure out how many URLs the RAM can hold at a maximum.</p><pre><code><code>Those numbers aren't reaching anywhere near the RAM limits. Let's figure out the maximum data we can handle for each RAM amount.</code></code></pre><blockquote><p>Apologies for the confusion. Let's calculate the maximum data we can handle for each RAM amount, considering the URL size of 1000 bytes. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XoTY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XoTY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png 424w, https://substackcdn.com/image/fetch/$s_!XoTY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png 848w, https://substackcdn.com/image/fetch/$s_!XoTY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png 1272w, https://substackcdn.com/image/fetch/$s_!XoTY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XoTY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png" width="1456" height="318" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:318,&quot;width&quot;:1456,&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;:true,&quot;topImage&quot;:false,&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_!XoTY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png 424w, https://substackcdn.com/image/fetch/$s_!XoTY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png 848w, https://substackcdn.com/image/fetch/$s_!XoTY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png 1272w, https://substackcdn.com/image/fetch/$s_!XoTY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ecfa8bb-2350-4960-a591-d6f1d4446c44_1476x322.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div></blockquote><div><hr></div><p>Okay. Back to bad math.</p><pre><code><code>That does not add up. `1,073,741,824 bytes / 1000 bytes` is not 1,073,741,824</code></code></pre><blockquote><p>Apologies for the error in the calculation. You're correct; the division was incorrect in the previous response.</p><p>I apologize for the confusion caused by the previous incorrect calculations. </p></blockquote><div><hr></div><p>The data is still not quite right. What I do notice is that ChatGPT 3.5 apologizes&#8230; a lot. It gets pretty annoying. It seems ChatGPT 4 apologizes less often. Maybe because it&#8217;s correct more often and does not need to.</p><p>I decide to take the coaching approach and slightly change to a leading direction:</p><pre><code><code>How do we calculate how many URLs will fit in a given amount of RAM?</code></code></pre><blockquote><p>For example, if the average URL size is 1000 bytes and you have 1 GB (1,073,741,824 bytes) of available RAM, the calculation would be:</p><p>Maximum URLs = 1,073,741,824 bytes / 1000 bytes = 1,073,741 URLs</p></blockquote><div><hr></div><p>Okay, so it knows what to do. Let&#8217;s see if it is set on the right path.</p><pre><code><code>okay. Given that formula, update the table.</code></code></pre><blockquote><p>Apologies for the confusion earlier. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jWkG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jWkG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png 424w, https://substackcdn.com/image/fetch/$s_!jWkG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png 848w, https://substackcdn.com/image/fetch/$s_!jWkG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png 1272w, https://substackcdn.com/image/fetch/$s_!jWkG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jWkG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png" width="1456" height="417" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:417,&quot;width&quot;:1456,&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;:true,&quot;topImage&quot;:false,&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_!jWkG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png 424w, https://substackcdn.com/image/fetch/$s_!jWkG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png 848w, https://substackcdn.com/image/fetch/$s_!jWkG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png 1272w, https://substackcdn.com/image/fetch/$s_!jWkG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa31778da-eb94-40f9-8b4f-2d1a3431bf6b_1466x420.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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></blockquote><div><hr></div><p>&#129318;&#127996; *facepalm*</p><blockquote><p>I apologize for the confusion and any frustration caused. I understand the importance of accurate information in the design process. </p></blockquote><div><hr></div><p>At least it knows I&#8217;m frustrated.</p><p>For those of you bad at math like me, 2.15 trillion bytes is 2,105 GB &#8212; not 2 GB. I guess there&#8217;s that, I&#8217;m better at math than ChatGPT 3.5.</p><p>I simplify the problem for it.</p><pre><code><code>We have 3 scales: Small (1GB RAM), Medium (2GB RAM), Large (4GB RAM)

Create a table with these columns: scale, urls, total data

Work backward from the total data, which must be no higher than the RAM amount. We want to figure out for a given RAM amount, how many URLs can we fit.</code></code></pre><blockquote><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jYnP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jYnP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png 424w, https://substackcdn.com/image/fetch/$s_!jYnP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png 848w, https://substackcdn.com/image/fetch/$s_!jYnP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png 1272w, https://substackcdn.com/image/fetch/$s_!jYnP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jYnP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png" width="1456" height="312" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:312,&quot;width&quot;:1456,&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;:true,&quot;topImage&quot;:false,&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_!jYnP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png 424w, https://substackcdn.com/image/fetch/$s_!jYnP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png 848w, https://substackcdn.com/image/fetch/$s_!jYnP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png 1272w, https://substackcdn.com/image/fetch/$s_!jYnP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd77ad08-09e2-4d33-8d78-1f618a8dd731_1464x314.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div></blockquote><div><hr></div><p>Looks like it figured it out. We walked through some more calculations then I came to this conclusion:</p><pre><code><code>If we want to keep data only in memory, we'll either need a lot more RAM or to only store data for a short amount of time.</code></code></pre><p>So I figure:</p><pre><code><code>Let's be the SnapChat of URLs shorteners and only store the URLs for 24 hours. That should be long enough for quick sharing of URLs and allow us to use an in memory store like Redis. Right?</code></code></pre><blockquote><p>Storing URLs for a short period of time aligns with the goal of a temporary and ephemeral URL shortening service, similar to the concept of SnapChat.</p></blockquote><div><hr></div><p>Not an enthusiastic endorsement, but I&#8217;ll take it.</p><pre><code><code>Okay, let's plan for a max of ~200,000 URLs of capacity. Even though we 
only store URLs for 24 hours, we want to make sure we do not repeat URLs for 10 years. How many possible URLs is that and what's the shortest short code we can use to represent that number?</code></code></pre><p>Let&#8217;s skip ahead.</p><pre><code><code>We won't be storing the short codes, so we won't really know about duplicates for 10 years. Instead, we need to make it statistically unlikely that we'll hit a duplicate in that time frame. We do want to verify there are no duplicates for the 24-hour window we're storing data. We could use a random ID for the short code, base62 encoded. How many random bits do we need to avoid collisions for 10 years?</code></code></pre><p>&#9888;&#65039; Spoiler alert. This does not go well. &#9888;&#65039;</p><p>After much back in forth, I came to this conclusion:</p><pre><code><code>Your math is off so I asked ChatGPT 4. Here's what we came up with:</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Unj6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Unj6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png 424w, https://substackcdn.com/image/fetch/$s_!Unj6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png 848w, https://substackcdn.com/image/fetch/$s_!Unj6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png 1272w, https://substackcdn.com/image/fetch/$s_!Unj6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Unj6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png" width="1456" height="437" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:437,&quot;width&quot;:1456,&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;:true,&quot;topImage&quot;:false,&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_!Unj6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png 424w, https://substackcdn.com/image/fetch/$s_!Unj6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png 848w, https://substackcdn.com/image/fetch/$s_!Unj6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png 1272w, https://substackcdn.com/image/fetch/$s_!Unj6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F862f3bc2-4eba-4ec5-a024-be0d7cd79301_1458x438.png 1456w" sizes="100vw" loading="lazy"></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 role="img" 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><title></title><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><pre><code><code>A 10 character short code would make collision very unlikely. I'd prefer smaller, so let's go with 8 chars. It's unlikely enough for normal traffic. We don't expect a 10x spike every day for 10 years.</code></code></pre><blockquote><p>Thank you for providing the updated information and the calculations. I apologize for any confusion caused by the previous responses. </p></blockquote><div><hr></div><p>Yes, I cheated and asked ChatGPT 3.5&#8217;s more intelligent cousin, ChatGPT 4. But it did not take it hard; it ignored this and accepted the answer with an apology.</p><p>Now that the calculations are out of the way, we can do work that ChatGPT 3.5 is better suited for.</p><pre><code><code>This discussion implied some new functional and non-functional requirements. What are they?</code></code></pre><blockquote><p>Functional Requirements:</p><ol><li><p>Generate Unique Short Codes: The system should generate unique short codes for each long URL to avoid collisions and ensure uniqueness within the desired time frame.</p></li><li><p>Store URLs for a Limited Duration: URLs should be stored in memory for a maximum duration of 24 hours, aligning with the temporary nature of the service.</p></li><li><p>Remove Expired URLs: The system should automatically remove expired URLs from storage after the designated 24-hour period.</p></li><li><p>Handle 10x Traffic Spike: The system should be able to handle a spike in traffic up to 10 times the normal volume to accommodate occasional high-demand periods.</p></li><li><p>Redirect to Long URLs: When a short URL is accessed, the system should redirect users to the corresponding long URL.</p></li></ol><p>Non-Functional Requirements:</p><ol><li><p>Collision Probability: The system should have a low collision probability for generated short codes, ensuring that the likelihood of duplicate codes is statistically unlikely.</p></li><li><p>Compact Short Codes: The short codes should be reasonably short in length, striking a balance between compactness and collision avoidance.</p></li></ol></blockquote><div><hr></div><p>We carry on like this back and forth on several topics:</p><ul><li><p>What is the next step in our process?</p></li><li><p>Okay, let's move on to the data model. What do we need to store?</p></li><li><p>For the use case "User submits the same long URL multiple times and receives the same short URL within the 24-hour duration.", we will need to store additional data.</p></li><li><p>This will add some additional storage for each URL. Considering the two mappings in our data model, how much will each URL take in space?</p></li><li><p>What do you think the API should be?</p></li><li><p>etc</p></li></ul><p>I have to remind it:</p><pre><code><code>Don't be so apologetic. We're working on this together.</code></code></pre><blockquote><p>Thank you for your understanding and kind words! I appreciate your collaborative approach, and I'm here to assist you throughout the process. If you have any more questions, need further clarification, or require assistance with any aspect of the design, please don't hesitate to let me know. Let's continue working together to create a successful URL shortening service design.</p></blockquote><div><hr></div><p>You can see this is a conversation. ChatGPT and I are designing together. ChatGPT is informing me, and I&#8217;m making the decisions. Using the <a href="https://blog.devdetails.com/p/adopting-daci">DACI model</a>, I would be the Driver and the Approver, and ChatGPT would be a Contributor. </p><p>We went back and forth, converging on a design. If you&#8217;re interested, <a href="https://chat.openai.com/share/8090f59f-23ce-420b-b6b7-316973f314f9">view the whole interaction</a>.</p><p>And here&#8217;s a snippet of the design we came up with. We&#8217;ll use it in Part 3 and beyond.</p><pre><code># URL Shortening Service

## Context

This service provides APIs that take long URLs and provide a short URL suitable for easy sharing.

## Functional Requirements

- The JSON API should allow users to submit a long URL and receive a shortened URL in return.
- When visiting the shortened URL, the visitor will be redirected to the long URL.
- When visiting a short URL that is not found or has expired, the response should be an HTML error page with an appropriate HTTP status code and an error message. The error page should provide a user-friendly display.
- Short URLs are only valid for 24 hours. After the 24-hour validity window, a new short URL should be generated for the same long URL.

[truncated]

## Non-functional requirements

- Be able to handle generating and storing ~200,000 short URLs a day and up to 2,000,000 short URLs in a day during a 10x spike in URL generation.
- Use minimal memory, up to 2GB.

[truncated]

## Use Cases

- User submits a long URL and receives a short URL in response.
- User visits the short URL and gets redirected to the original long URL.
- User attempts to access an expired short URL and receives an appropriate response.
- User submits an invalid long URL and gets an error response.

[truncated]</code></pre><div><hr></div><p>You can <a href="https://github.com/dev-details/ai-code-example/blob/main/design.md">view the complete design document</a>.</p><p>We can now use this design document to generate some code.</p><div><hr></div><h2>Next</h2><p>Head to Part 3. <a href="https://blog.devdetails.com/p/diagrams-and-api-design-with-ai">Continue the journey.</a></p><ul><li><p><a href="https://blog.devdetails.com/p/a-practical-example-of-using-ai-for">Part 1: Setup and Process</a></p></li><li><p>Part 2: Design &#8592; YOU ARE HERE</p></li><li><p><a href="https://blog.devdetails.com/p/diagrams-and-api-design-with-ai">Part 3: Sequence diagram and API specification</a></p></li><li><p>Part 4: Generating tests</p></li><li><p>Part 5: Generating the application and making it work</p></li></ul><p></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[A practical example of using AI for coding]]></title><description><![CDATA[An end-to-end walkthrough of designing, developing, and testing a simple application with the help of AI.]]></description><link>https://blog.devdetails.com/p/a-practical-example-of-using-ai-for</link><guid isPermaLink="false">https://blog.devdetails.com/p/a-practical-example-of-using-ai-for</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Wed, 14 Jun 2023 03:34:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kDgo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>ChatGPT and other LLMs have impressive coding capabilities. However, the obvious way to use it is like driving a race car on square wheels &#8212; inefficient, teeth-rattling, and headache-inducing.</p><p>I've developed some techniques for working with AI coding tools that get good results. Here, I'll focus on how you can add generative AI to your workflow.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kDgo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kDgo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kDgo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kDgo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kDgo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kDgo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg" width="1456" height="1456" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1456,&quot;width&quot;:1456,&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_!kDgo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kDgo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kDgo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kDgo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe0e23d2-5ec3-4c6a-b3aa-92a5aa8c763f_2048x2048.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 role="img" 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><title></title><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>I've done this exercise as a live demo before. Showing someone how to do something opens doors to many previously unthought possibilities.</p><p>Let me give you the details.</p><p>But first, let's discuss the question I'm asked most often when I demo:&nbsp;</p><h2>Will AI replace software developers?</h2><p>Everyone has been talking about generative AI for development, but I have yet to see practical examples of its use. Many posts say how AI will replace all of us developers. Many posts show examples of generated code doing simple things -- often incorrectly. A few have come to the same conclusion as I have:&nbsp;</p><blockquote><p><em>AI won't replace developers; developers that use AI will replace those who don't.&nbsp;&nbsp;</em></p></blockquote><p>At least in the short term.&nbsp;</p><ul><li><p><strong>Eventually</strong>, AI may replace software developers.&nbsp;</p></li><li><p><strong>In the meantime</strong>, I'm embracing it and figuring out how it can make me more efficient.</p></li></ul><h2>It's dangerous to go alone!</h2><ul><li><p><strong>Treat the AI like a coding companion</strong>&nbsp;-- you are pair programming. It has access to a lot of knowledge and can put it to use quickly. You are a reasoning being and have insight that the AI doesn't. Do what you do best and let it do what it does best.&nbsp;</p></li><li><p><strong>Be specific; be precise</strong>. AI is not omniscient. It can't read your mind (*yet). A fun way to ask AI to teach you something complex: "Explain X like I'm 10" or "Explain X in layman's terms." Do the reverse. Explain what you want in exacting detail; otherwise, the AI will make assumptions or make stuff up.&nbsp;<strong>Pro tip:</strong>&nbsp;Tell it to ask clarifying questions.&nbsp;</p></li><li><p><strong>You must already know what you're doing</strong>, or you won't know if the AI is right<strong>.</strong>&nbsp;Only do this for languages and libraries you are intimately familiar with. At the very least, you should know the language well and be willing to learn the library instead of just copy-pasting whatever the AI generates. You are the editor. You need to understand what it is generating.</p></li><li><p><strong>Be fully engaged</strong>. The goal is to speed up your development -- not have the AI do all the work.</p></li></ul><p>You might see a common theme with these tips. The experience is very much like pair programming. Consider it like you're the lead on a project pairing with a junior developer. A junior developer that just so happens to know most of the internet before September 2021.&nbsp;</p><h2>Take this</h2><p>No one AI tool does everything. I've tried several; for this example, we'll keep it simple.</p><ul><li><p><strong><a href="https://chat.openai.com/">ChatGPT</a>&nbsp;will do the bulk of the generating.</strong>&nbsp;You could do this with GPT 3.5 or 4. I find 4 much better at generating code and understanding context. But GPT 4 is limited to 25 messages every 3 hours and requires ChatGPT Plus. I'll give more tips on how to make the most of those 25 messages later.</p></li><li><p><strong><a href="https://aws.amazon.com/codewhisperer/">CodeWhisperer</a>&nbsp;will handle auto-complete.</strong>&nbsp;I'm currently using this over&nbsp;<a href="https://github.com/features/copilot">Copilot</a>&nbsp;because I like its PyCharm plugin better.</p></li><li><p><strong><a href="https://plugins.jetbrains.com/plugin/21056-codegpt">CodeGPT plugin</a>&nbsp;will let our IDE talk to ChatGPT</strong>&nbsp;(but not that&nbsp;<a href="https://codegpt.co/">CodeGPT</a>). I use the IntelliJ plugin. I have yet to try the unrelated CodeGPT service, which only provides a VSCode plugin. The goal here is to have ChatGPT integrated into the IDE. Some of these don't have GPT 4 access, so we still need to use the standalone ChatGPT if we want to use that.</p></li></ul><p>ChatGPT is not the only tool. Whatever you're trying to do,&nbsp;<a href="https://theresanaiforthat.com/">there's an AI for that</a>. For this example, though, let's stick to the basics (he says about an AI that has transformed the world).</p><h2>Hold up</h2><p>We can't just jump straight into coding. We wouldn't be very good project leads if we did.</p><p>For the best results, work with the AI in multiple, discrete steps and sessions:</p><ol><li><p><strong>Design a solution</strong>&nbsp;through conversation. Effective software development&nbsp;<a href="https://blog.devdetails.com/p/autonomy-for-software-architecture">starts with a design</a>. AI is great for bouncing ideas off of and helping you think out loud.</p></li><li><p><strong>Implement tests</strong>&nbsp;based on business cases. I usually write tests during coding -- interwoven with my coding. In this case, I'm generating tests first, then using a different AI to write code to demonstrate the use cases of multiple AIs &#8212; also, because test-first development.</p></li><li><p><strong>Write code</strong>&nbsp;in the IDE with AI plugins. We'll do this in an interesting way. I promise.</p></li><li><p><strong>Fix the code</strong>&nbsp;by using the tests.&nbsp;<em>Yes</em>, you will&nbsp;<em>need</em>&nbsp;to fix the code.&nbsp;</p></li></ol><p>There's another reason to break this into multiple steps:</p><div class="pullquote"><p><em>GPT 4 is way better at everything compared to GPT 3.5. But it costs money, is relatively slow, and has a message limit.&nbsp;</em></p></div><p>If you don't have GPT 4 access, 3.5 will work with more guidance from you.</p><p>To get the most out of GPT 4, split the load.&nbsp;</p><ul><li><p><strong>Use GPT 3.5 to help design and GPT 4 to generate code.&nbsp;</strong>GPT 3.5 is generally good enough at software design to tease out the details needed for a good design. If you can coach GPT 3.5 to develop a good design, you understand the problem well enough.</p></li><li><p><strong>Use GPT 4 to coach</strong>&nbsp;if you are working on your design skills, and then use GPT 3.5 for code.</p></li><li><p><strong>Split GPT 4 sessions</strong>&nbsp;to be able to use more than 25 messages. Handle design in one session and coding in another.&nbsp;</p></li><li><p><strong>Ask ChatGPT to generate prompts</strong>&nbsp;to use with other AIs or AI sessions. For example, "generate a prompt to tell another AI what we just discussed."</p></li></ul><h2>Onward</h2><p>This is the process we&#8217;ll follow:</p><ol><li><p><strong>Consult with ChatGPT to design a solution</strong> and generate a lightweight design document. We will use this as input for all the other steps.</p></li><li><p><strong>ChatGPT will generate a PlantUML diagram</strong> from the design specification. This gives us a nice visual to put in our design document and lets us verify ChatGPT understands our design (us too).</p></li><li><p><strong>ChatGPT will generate an OpenAPI spec</strong> from the design specification. We&#8217;ll feed this into other design components. Also, I like API-first development.</p></li><li><p><strong>ChatGPT will generate tests</strong> from the design specification. It helps to pair this with the design document because good tests describe the business use cases of your software.</p></li><li><p>Switch to IDE.</p></li><li><p><strong>CodeGPT will generate application code</strong> from the tests. Test-first development &#8212; this is the stuff of science fiction!</p></li><li><p><strong>Pair with CodeGPT and CodeWhisperer</strong> to ensure the tests pass and verify the correct functionality.</p></li><li><p><strong>Profit.</strong></p></li></ol><p>For the best results, don&#8217;t just say, &#8220;Write me code that does X&#8221;; use a prompt that:</p><ul><li><p><strong>Clearly defines roles</strong>&nbsp;for you and the AI: "You and I are software engineers. We will use pair development."</p></li><li><p><strong>Sets a goal:</strong>&nbsp;"Our goal is to craft the best possible application to satisfy the design."</p></li><li><p><strong>Defines a process</strong>&nbsp;to follow: "We will follow this process: {bullet list of process}"</p></li><li><p><strong>Lets the AI ask questions: "</strong>You will ask me questions about assumptions until all your questions are answered."</p></li></ul><p>Prompt frameworks make AI interactions more effective. They ensure clearer, relevant responses and save time. Frameworks maintain consistency, facilitate more straightforward data interpretation, and encourage effective learning. The #prompt-library channel in the&nbsp;<a href="https://discord.com/invite/openai">OpenAPI Discord</a>&nbsp;is a top resource.</p><p>Let&#8217;s move on to designing with AI.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>The Scenario</h2><p>We need an example to work with. AI is pretty great at leet code examples. I am not. Also, I said this would be a practical example. Leet code is not indicative of real-life work.&nbsp;</p><p>For practical examples, it helps to use something similar to real-life work.&nbsp;</p><ul><li><p><a href="https://codingchallenges.fyi/">Coding Challenges</a>&nbsp;is an excellent resource for building real-world applications.&nbsp;</p></li><li><p>A&nbsp;<a href="https://codingchallenges.fyi/challenges/challenge-url-shortener/">URL Shortener Challenge</a>&nbsp;looks like a good, practical example to work with.</p></li></ul><div><hr></div><h2>Next</h2><p>Head to Part 2: <a href="https://blog.devdetails.com/p/designing-software-with-ai">Continue the journey.</a></p><ul><li><p>Part 1: Setup and Process &#8592; YOU ARE HERE</p></li><li><p><a href="https://blog.devdetails.com/p/designing-software-with-ai">Part 2: Design</a></p></li><li><p>Part 3: Sequence diagram and API specification</p></li><li><p>Part 4: Generating tests</p></li><li><p>Part 5: Generating the application and making it work</p><p></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Adopting DACI]]></title><description><![CDATA[An ADR for Streamline Decision Making]]></description><link>https://blog.devdetails.com/p/adopting-daci</link><guid isPermaLink="false">https://blog.devdetails.com/p/adopting-daci</guid><dc:creator><![CDATA[Mike]]></dc:creator><pubDate>Tue, 23 May 2023 20:40:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!8n7r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In software development, we make decisions at a rapid pace. These decisions, especially architecture decisions, have long-term consequences, yet are often made in a rush, undocumented, and without an effective process. The following Any Decision Record (ADR) introduces a robust approach to guide smart decision-making.</p><p>I've briefly mentioned ADRs before. They are great for maintaining transparency and intent by capturing the "who," "what," and "why" of decisions. Refer to the <a href="https://blog.devdetails.com/p/autonomy-for-software-architecture">initial article</a> for a deeper understanding of ADRs and their role in an autonomous architecture design framework.</p><p>I&#8217;ve set up an <a href="https://github.com/dev-details/adr-library">ADR Library</a> to make it easier for everyone to adopt ADRs. This library of ADR templates can be used as a basis for your own decision records.</p><p>I will let the ADR below speak for itself on why a decision-making process is valuable and why to choose this one. Feel free to use this ADR as a template for adopting it with your team.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8n7r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8n7r!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!8n7r!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!8n7r!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!8n7r!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8n7r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:96026,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8n7r!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!8n7r!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!8n7r!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!8n7r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f10e72a-14d4-49aa-8c12-12bcda80f4f2_1024x1024.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 role="img" 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><title></title><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>Below is the rendered version of the ADR. You can get the Markdown source for it and more in the <a href="https://github.com/dev-details/adr-library">ADR Library</a>. </p><div><hr></div><h1><strong>DACI for Decision-Making Process</strong></h1><ul><li><p>Status: accepted</p></li><li><p>Driver: {who drives the decision}</p></li><li><p>Approvers: {who approves the decision}</p></li><li><p>Contributors: {whose input is sought (two-way communication)}</p></li><li><p>Informed: {who is kept up-to-date on progress (one-way communication)}</p></li></ul><h1><strong>DACI for Decision-Making Process</strong></h1><h2><strong>Context and Problem Statement</strong></h2><p>Our team is continuously seeking ways to refine our decision-making processes. We believe clearer roles and responsibilities in this process will enhance efficiency, minimize misunderstandings, and foster collaboration.</p><h2><strong>Decision Drivers</strong></h2><ul><li><p>Clarity of roles -- who is involved in making decisions and who is impacted.</p></li><li><p>Simple -- must be easy to explain and understand.</p></li></ul><h2><strong>Considered Options</strong></h2><ul><li><p>DACI</p></li><li><p>RACI</p></li><li><p>RAPID</p></li></ul><h2><strong>Decision Outcome</strong></h2><p>We will adopt the <a href="https://www.productplan.com/glossary/daci/">DACI</a> framework for our decision-making process. DACI stands for:</p><ul><li><p><strong>D</strong>river: Person driving the project and responsible for the decision-making process. This person should understand the project and facilitate communication among stakeholders.</p></li><li><p><strong>A</strong>pprovers: Individual(s) with the final say. Typically, individuals in this role possess the authority to make decisions.</p></li><li><p><strong>C</strong>ontributors: Those providing valuable input to the decision. Contributors can be anyone with relevant information or expertise.</p></li><li><p><strong>I</strong>nformed: People who need to be aware of the decision once made. These could be team members impacted by the decision or other stakeholders.</p></li></ul><p>At a minimum, we will apply DACI to:</p><ol><li><p>Design Documents: To decide on the best design approach.</p></li><li><p>Any/Architectural Decision Records (ADRs): To drive decision-making for system-wide changes.</p></li></ol><h2><strong>Pros and Cons of the Options</strong></h2><h3><strong>RACI</strong></h3><p><a href="https://en.wikipedia.org/wiki/Responsibility_assignment_matrix">RACI</a> stands for Responsible, Accountable, Consulted, and Informed. While it provides a similar structure to DACI, the difference in terms can sometimes lead to ambiguity, such as distinguishing between "Responsible" and "Accountable".</p><h3><strong>RAPID</strong></h3><p><a href="https://www.bridgespan.org/insights/rapid-decision-making">RAPID</a> stands for Recommend, Agree, Perform, Input, and Decide. This model emphasizes decision execution but can be overly complex, especially for smaller teams and less hierarchical organizations.</p><h2><strong>Consequences</strong></h2><p>Adopting DACI is expected to enhance our decision-making process, promoting clarity and efficiency. It requires a learning period and may necessitate adjustments in our workflows. Ultimately, it's anticipated to cultivate a more transparent and efficient environment.</p><h2><strong>More Information</strong></h2><h3><strong>Suggestions for Adoption</strong></h3><p>To migrate to DACI, we can:</p><ol><li><p><strong>Present</strong>: Conduct sessions to familiarize the team with DACI.</p></li><li><p><strong>Implement Incrementally</strong>: Begin with one project and gradually expand its usage.</p></li><li><p><strong>Regular Reviews</strong>: Schedule reviews to assess DACI effectiveness and make adjustments.</p></li></ol><div><hr></div><p>The Markdown source for this particular ADR is available <a href="https://github.com/dev-details/adr-library/blob/main/decision-templates/20230522-daci-for-decision-making-process.md">here</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devdetails.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dev Details is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>