<?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[DevTower]]></title><description><![CDATA[Tech partnership in the startup world]]></description><link>https://blog.devtower.io</link><image><url>https://substackcdn.com/image/fetch/$s_!hCM1!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23b6de6-1727-4c91-8e64-18bf186739d7_178x178.png</url><title>DevTower</title><link>https://blog.devtower.io</link></image><generator>Substack</generator><lastBuildDate>Wed, 29 Apr 2026 20:58:35 GMT</lastBuildDate><atom:link href="https://blog.devtower.io/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[DEVTOWER LTD]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[ivan@devtower.io]]></webMaster><itunes:owner><itunes:email><![CDATA[ivan@devtower.io]]></itunes:email><itunes:name><![CDATA[Ivan Osipov]]></itunes:name></itunes:owner><itunes:author><![CDATA[Ivan Osipov]]></itunes:author><googleplay:owner><![CDATA[ivan@devtower.io]]></googleplay:owner><googleplay:email><![CDATA[ivan@devtower.io]]></googleplay:email><googleplay:author><![CDATA[Ivan Osipov]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[#28: Meeting Transcription Is a Trap]]></title><description><![CDATA[The problem was never the recording.]]></description><link>https://blog.devtower.io/p/28-meeting-transcription-is-dead</link><guid isPermaLink="false">https://blog.devtower.io/p/28-meeting-transcription-is-dead</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Fri, 03 Apr 2026 10:54:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!wBlQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>The problem was never the recording. It was the gap between talking and doing.</h2><p>I tried the transcription apps. The ones that record your calls, generate summaries, extract action items. I believed in them for a while.</p><p>Then I stopped &#8212; not because the tools got worse, but because the entire problem they solve stopped mattering.</p><p>If you still believe recording your team meetings and processing them &#8220;somehow with AI&#8221; is the move, I have bad news: you are a couple of steps behind.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wBlQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wBlQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png 424w, https://substackcdn.com/image/fetch/$s_!wBlQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png 848w, https://substackcdn.com/image/fetch/$s_!wBlQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png 1272w, https://substackcdn.com/image/fetch/$s_!wBlQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wBlQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png" width="1456" height="711" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:711,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6814900,&quot;alt&quot;:null,&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;:&quot;https://blog.devtower.io/i/193055027?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wBlQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png 424w, https://substackcdn.com/image/fetch/$s_!wBlQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png 848w, https://substackcdn.com/image/fetch/$s_!wBlQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.png 1272w, https://substackcdn.com/image/fetch/$s_!wBlQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40389370-a2f4-44a2-9956-f963cee30ec1_3386x1654.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></figure></div><h2>The action problem</h2><p>Think about what happens after a typical meeting. Someone says &#8220;I added that to my notes.&#8221; Someone else says &#8220;I&#8217;ll schedule a follow-up.&#8221; You nod. The call ends.</p><p>Sometimes you return to those notes. Often you don&#8217;t. When you do, the context is gone &#8212; you remember the words but not the energy behind the decision, not the nuance that made it feel urgent in the moment. The organizational machinery stutters, but everyone accepts it because that is just how meetings work.</p><p>Every time, action is postponed. Postponed means delayed. Delayed means something is lost.</p><p>Transcription does not fix this. It makes the record more accurate, but the gap between &#8220;we discussed it&#8221; and &#8220;it is done&#8221; stays wide open.</p><p>Now compare that to what happens when your team works with AI agents in real time. You do not say &#8220;I will update the spec&#8221; &#8212; you say &#8220;I am currently updating the spec.&#8221; You do not say &#8220;I added that to my notes&#8221; &#8212; you say &#8220;I have already launched the change; as soon as it is implemented, you will be notified.&#8221;</p><p>The meeting itself becomes the execution environment. Not a better transcript -- a fundamentally different kind of meeting.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>The privacy problem</h2><p>There is a second reason transcription was always fragile, and most people avoid saying it out loud: recording changes how people behave.</p><p>When a meeting is recorded by default, everything someone says can be used as evidence later. People know this. Some are fine being wrong in front of others &#8212; they say something half-formed, get corrected, and move on. But others start filtering themselves. They feel exposed. Less professional. And you will never fully fix that dynamic, because leaders are not personal therapists. You work with humans as they are, not as you wish they were.</p><p>Now push it further. Even if your team is comfortable with group recordings &#8212; would they accept you transcribing one-on-one meetings? Every phrase. Every word. Would they truly be comfortable sharing something private, something vulnerable, knowing it is captured forever?</p><p>I asked managers about this directly. About nine months ago I posted in r/managers asking if people struggle with 1-on-1s. The responses confirmed what I suspected: the managers who cared the most about building trust were the ones most opposed to transcription. One put it simply &#8212; 1-on-1s are for talking to <em>the person</em>, not the title, not the role. That space only works when it feels safe. Another described action items from 1-on-1s sitting in shared docs going nowhere: &#8220;Nothing moves forward. It feels like a broken process, with missing pieces in the puzzle&#8221;. The community was fragmented across dozens of note-taking tools, all solving the wrong problem. Nobody had solved action-closing.</p><p>This is a problem you cannot fix with better transcription tools. And honestly, you probably should not try.</p><p>As AI-native collaboration reshapes how teams work together, this tension dissolves on its own. When agents handle execution during the meeting, there is less need to capture what was said &#8212; because what was said has already become what was done.</p><h2>The shift</h2><p>I have started paying attention to something small that changed how I think about all of this. Every time I get the automatic feeling &#8220;I need to note this down&#8221;, I pause &#8212; because I now recognize that instinct as a failure signal. It means something should have been acted on and was not. So instead of writing it down, I ask myself: why do I want to record this? Why is there no simple action to fix this right now? That one question, applied consistently, has gradually shifted how my team communicates. Less note-taking. More architecting. From people who document intentions to people who execute them.</p><p>The collaboration changes happening right now are enormous. Human-agent-human interactions bring challenges no one has playbooks for yet &#8212; and they make the old ones, like &#8220;how do we extract value from a meeting recording,&#8221; irrelevant.</p><p>That transformation deserves its own post. For today, one takeaway:</p><p><strong>You have to finish meetings with ready-to-use results. Planned meetings. Launched changes. Not notes about what to do</strong>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading the blog! Subscribe for free to receive new posts and support my work.</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>]]></content:encoded></item><item><title><![CDATA[#27: The Belief System Shift No One Wants to Talk About]]></title><description><![CDATA[I wrote recently about AI transformation &#8212; about how most companies are doing it wrong, pushing water through pipes instead of redesigning the pipes themselves.]]></description><link>https://blog.devtower.io/p/27-the-belief-system-shift-no-one</link><guid isPermaLink="false">https://blog.devtower.io/p/27-the-belief-system-shift-no-one</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Mon, 30 Mar 2026 15:33:48 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!qKYT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I wrote recently about AI transformation &#8212; about <a href="https://blog.devtower.io/p/why-youre-doing-ai-transformation">how most companies are doing it wrong</a>, pushing water through pipes instead of redesigning the pipes themselves. Since then, I&#8217;ve watched dozens of teams try to adopt AI. And what I see now goes deeper than strategy or tooling. What I see is a belief system problem.</p><p>The shift we&#8217;re living through is not &#8220;use AI to do your work faster.&#8221; It&#8217;s &#8220;teach systems to do the work on your behalf.&#8221; That sounds like a small distinction. It&#8217;s not. It&#8217;s the difference between running harder and building something that runs without you.</p><p>We used to write code. We used to test it. We used to deploy it, monitor it, fix it, repeat. That was the job. Now the job is different &#8212; not in degree, but in kind. The people and companies who figure out how to teach programs to do this work, who find more efficient ways to drive value through their systems, win. Those who don&#8217;t lose the competition. And when systems lose, the people who depend on them lose with them.</p><p>So why isn&#8217;t everyone sprinting toward this? Because it triggers something primal.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qKYT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qKYT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png 424w, https://substackcdn.com/image/fetch/$s_!qKYT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png 848w, https://substackcdn.com/image/fetch/$s_!qKYT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!qKYT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qKYT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png" width="1456" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8556118,&quot;alt&quot;:null,&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;:&quot;https://blog.devtower.io/i/192601083?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qKYT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png 424w, https://substackcdn.com/image/fetch/$s_!qKYT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png 848w, https://substackcdn.com/image/fetch/$s_!qKYT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!qKYT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a10ab89-3fa1-484c-b29e-11b7cfdaf141_2914x1440.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></figure></div><h2>The Fear Underneath</h2><p>Our deep fear of becoming redundant shifts our focus from the productive path &#8212; teaching, architecting, designing systems of work &#8212; to the unproductive one: clinging to manual control. We don&#8217;t adopt AI poorly because we lack intelligence. We adopt it poorly because we&#8217;re terrified of what full adoption implies about our role.</p><p>If you&#8217;ve ever watched a brilliant individual contributor get promoted to manager, you&#8217;ve seen this movie before. The best ICs often make the worst new managers, and the reason is always the same: they can&#8217;t stop doing the work themselves. They micro-manage. They rewrite their reports&#8217; code. They hover. Not because micro-management is effective &#8212; anyone with experience knows its scope of application is vanishingly small &#8212; but because letting go of the work feels like letting go of their identity. Their value was in *doing*. Now their value is in *enabling*. Yes, it&#8217;s a process change &#8212; but the identity impact is what makes it so hard.</p><p>This is exactly the struggle we&#8217;re seeing now, but at civilizational scale. Millions of knowledge workers built their professional identity around execution &#8212; writing, coding, analyzing, designing. AI doesn&#8217;t just offer to help with that execution. It offers to *replace* it. And our instinct, predictably, is to grab the wheel tighter.</p><h2>The Squirrel in the Wheel</h2><p>We even invented a term that reveals the dysfunction: **human-in-the-loop**. Think about what that phrase actually means. You are the squirrel in the wheel, and you&#8217;ve committed to running at whatever speed the wheel spins. As AI accelerates, you accelerate &#8212; or you fall. That&#8217;s not a collaboration model. That&#8217;s a treadmill with no off switch.</p><p>Human-in-the-loop sounds responsible. It sounds like oversight. But in practice, it means you&#8217;ve embedded yourself inside a system that will only get faster, and you&#8217;ve made yourself the bottleneck. Every output waits for your review. Every decision routes through your judgment. You feel essential &#8212; and you are, in the worst possible way. You&#8217;re essential the way a toll booth is essential on a highway: everything still flows, just slower, because of you.</p><p>The reframe I keep coming back to is this: **move from human-in-the-loop to human-at-the-boundary.**</p><h2>Human at the Boundary</h2><p>The difference is fundamental. A human in the loop operates inside the system &#8212; reviewing, approving, correcting, running alongside the machine at machine speed. A human at the boundary operates outside the system &#8212; defining what it should do, setting the constraints it must respect, architecting how value flows through it, and intervening only when the system encounters something beyond its boundaries.</p><p>The human at the boundary doesn&#8217;t review every pull request. They design the testing framework, the guardrails, the acceptance criteria &#8212; and then they let the system run. They don&#8217;t approve every marketing email. They define the voice, the rules, the audience parameters &#8212; and then they audit outcomes at the edges, where the interesting failures happen.</p><p>This is what it means to build systems of autonomous value delivery. Not &#8220;AI does everything unsupervised.&#8221; Not recklessness. But a fundamentally different relationship with work, where your job is to architect the system&#8217;s intelligence rather than substitute for it.</p><p>Those who build these systems &#8212; who design their work as autonomous pipelines with human judgment at the boundaries, not embedded in every step &#8212; are the cohort that will survive and succeed. Everyone else will eventually learn from them. But that learning will come with a collision with ground truth: the single certainty right now is uncertainty, and the people who build adaptive systems will navigate it better than the people white-knuckling their way through every task.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>Redundancy Is the Point</h2><p>Here&#8217;s the part nobody wants to hear: redundancy is not the threat. Redundancy is the goal.</p><p>Every time you make yourself redundant in one area of work, you free yourself to operate at a higher level. The IC who becomes redundant as a coder becomes available as an architect. The manager who becomes redundant as a task-assigner becomes available as a strategist. This has always been how careers advance &#8212; you outgrow the work, hand it off, and move to the harder, more leveraged problem above it.</p><p>AI just compressed the timeline. What used to take years of gradual delegation now happens in months. The IC doesn&#8217;t slowly hand off coding to junior developers over a decade. They hand it to AI next quarter. That speed is disorienting. It feels like loss. But the opportunity on the other side is enormous &#8212; not despite the redundancy, but because of it.</p><p>As soon as you stop fighting redundancy and start embracing it, the opportunity space explodes. There is more work to do than ever before &#8212; it&#8217;s just different work. Higher-leverage work. The work of teaching, designing, architecting, and steering systems that deliver value at a scale no individual human ever could.</p><p>The belief system shift is simple to state and brutal to internalize: your value is no longer in what you do. It&#8217;s in what you enable. The sooner you make peace with that, the sooner you start building.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/27-the-belief-system-shift-no-one?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">Thanks for reading DevTower! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/27-the-belief-system-shift-no-one?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.devtower.io/p/27-the-belief-system-shift-no-one?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p></p>]]></content:encoded></item><item><title><![CDATA[#26: Why you're doing AI transformation wrong]]></title><description><![CDATA[We believe that AI is changing the world, the economy, how we work &#8212; everything.]]></description><link>https://blog.devtower.io/p/why-youre-doing-ai-transformation</link><guid isPermaLink="false">https://blog.devtower.io/p/why-youre-doing-ai-transformation</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Mon, 16 Mar 2026 23:28:52 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!O9ou!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We believe that AI is changing the world, the economy, how we work &#8212; everything. And most of us want to be part of this transformation because we hope it will bring more efficiency. But there is a problem. The way most of these transformations are running is deeply wrong from almost every possible perspective. Here is why and how to fix it.</p><h2>Wrong and naive idea of transformation</h2><p>The frictionless way to transform one business process to another is by giving AI &#8220;superpowers&#8221; to every employee. It is exactly what we see around: &#8220;everyone uses AI,&#8221; &#8220;ask ChatGPT about this problem!,&#8221; &#8220;there is a new AI tool that solves your problem.&#8221; We empower employees with AI while expecting them to perform better &#8212; otherwise they will be &#8220;not good enough,&#8221; &#8220;not adaptive enough,&#8221; and eventually fired. Meanwhile, these are quite challenging times for every regular worker. Most &#8220;knowledge workers&#8221; (those who usually do knowledge in -&gt; knowledge out kind of work) are scared about their jobs or at least feel uncertain. Those who cope with the emotions eventually get overwhelmed and exhausted by the permanent bombing of new tools and &#8220;AIs.&#8221; A massive pandemic of burnout is coming just because people try to do their best, but the maximum they can achieve is a 3x result compared to others &#8212; in exchange for overloaded context in their minds. 3x does not come for free. It gradually burns everyone.</p><h2>The right way of transformation</h2><p>We needed systems and processes to organize different people and design businesses to deliver value despite circumstances. Now those people have to move out of the value delivery chain and start looking from the outside of the value stream by designing it &#8212; actually doing proper piping instead of managing water inside the tube.</p><p>Take a software engineer as an example. The wrong transformation: give them GitHub Copilot and expect twice the output. What actually happens &#8212; they write more code, review more code, ship more bugs, and burn out faster. The intensity just went up. The right transformation: the engineer stops writing code manually altogether. Instead, every time a new task arrives, their job is to help AI understand the context, navigate the codebase, and produce better output than last time. They become the architect of AI&#8217;s understanding &#8212; not a faster AI tools orchestrator. The pipe gets smarter. The engineer gets leverage.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>Founder, AI, and other human relations</h2><p>This same principle &#8212; designing the pipe instead of pushing water through it &#8212; applies way beyond engineering. It applies to everyone steering a company.</p><p>In earlier times, the speed of change was slower; light steering brought you to the right result. Now times are different. With great power comes great responsibility. If you harness AI properly, your speed will be significantly higher &#8212; and it comes with higher risk because wrong steering will hit hard (think leaked data only because AI generated your MVP and security was not one of your concerns).</p><p>Take a founder as an example. <strong>The wrong transformation:</strong> use AI to ship everything faster &#8212; landing pages, pitch decks, product MVPs, legal docs &#8212; all generated in a weekend. Feels like a superpower. What actually happens &#8212; you ship fast with zero guardrails. AI hallucinates a privacy policy that doesn&#8217;t cover your actual data flows. Your MVP stores user credentials in plain text because nobody reviewed the architecture. You move at 10x speed straight into a wall. <strong>The right transformation:</strong> the founder doesn&#8217;t just use AI &#8212; they surround themselves with the right people who know where AI cuts corners. A security-minded engineer who reviews what AI generates. An advisor who flags regulatory blind spots before they become lawsuits. The founder&#8217;s job is not to do everything with AI. It is to build the team and the structure that makes AI safe to use at speed. The harness matters more than the horsepower.</p><p>Having the right people who help you build a good harness is the key. Speed without structure is just a faster way to fail.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!O9ou!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!O9ou!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png 424w, https://substackcdn.com/image/fetch/$s_!O9ou!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png 848w, https://substackcdn.com/image/fetch/$s_!O9ou!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png 1272w, https://substackcdn.com/image/fetch/$s_!O9ou!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!O9ou!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png" width="1456" height="795" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:795,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2775485,&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;:&quot;https://blog.devtower.io/i/191192356?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!O9ou!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png 424w, https://substackcdn.com/image/fetch/$s_!O9ou!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png 848w, https://substackcdn.com/image/fetch/$s_!O9ou!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.png 1272w, https://substackcdn.com/image/fetch/$s_!O9ou!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ee56e02-313e-4fcb-8179-fe788c8b21be_2048x1118.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.devtower.io/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">Thanks for reading DevTower! Subscribe for free to receive new posts and support my work.</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[#25: 8 Essential Laws of Systems]]></title><description><![CDATA[A simple one-pager summary to remember]]></description><link>https://blog.devtower.io/p/25-8-essential-laws-of-systems</link><guid isPermaLink="false">https://blog.devtower.io/p/25-8-essential-laws-of-systems</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Mon, 04 Nov 2024 00:57:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!2ISM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve just collected 8 essential laws of systems. We fractionally hear about them from different sources but I think that&#8217;s might be valuable to get one simple page, print it and do not forget</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2ISM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2ISM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png 424w, https://substackcdn.com/image/fetch/$s_!2ISM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png 848w, https://substackcdn.com/image/fetch/$s_!2ISM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png 1272w, https://substackcdn.com/image/fetch/$s_!2ISM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2ISM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png" width="1456" height="2060" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2060,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:396047,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!2ISM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png 424w, https://substackcdn.com/image/fetch/$s_!2ISM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png 848w, https://substackcdn.com/image/fetch/$s_!2ISM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.png 1272w, https://substackcdn.com/image/fetch/$s_!2ISM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93202521-1620-42d9-93e0-51f9f0d27530_2380x3368.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></figure></div><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><p>Especially for subscribers &lt;3 I also attach the version for printing</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-default" src="https://substackcdn.com/image/fetch/$s_!0Cy0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack.com%2Fimg%2Fattachment_icon.svg"></image><div class="file-embed-details"><div class="file-embed-details-h1">8 Essential Laws Of Systems (for Printing)</div><div class="file-embed-details-h2">684KB &#8729; PDF file</div></div><a class="file-embed-button wide" href="https://devtower.io/api/v1/file/8055a2a1-0f6d-43e6-9f35-0d6d3ef3ad60.pdf"><span class="file-embed-button-text">Download</span></a></div><a class="file-embed-button narrow" href="https://devtower.io/api/v1/file/8055a2a1-0f6d-43e6-9f35-0d6d3ef3ad60.pdf"><span class="file-embed-button-text">Download</span></a></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[#24: Fix It Already!]]></title><description><![CDATA[Time to reflex]]></description><link>https://blog.devtower.io/p/24-fix-it-already</link><guid isPermaLink="false">https://blog.devtower.io/p/24-fix-it-already</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Thu, 31 Oct 2024 02:50:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!n3x4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are certain problems that prevent us from solving other issues. At first glance, they don&#8217;t offer functional improvements and thus seem insignificant to the client. In reality, these are the kinds of problems that require effort to articulate their value, and the difficulty in expressing this value doesn&#8217;t imply its absence or insignificance.</p><p>In professional jargon, this is often called technical debt. But how would you name it  in everyday life? A loose electrical outlet that&#8217;s dangerous to plug a laptop charger into but seems to work for now; a broken lock on a door through which family or neighbours frequently enter and distract you just when you&#8217;ve achieved flow state; dim lighting from a lamp that gradually strains your eyes and accelerates fatigue&#8212;the list could go on. Is that already a good moment of time to fix something or not yet?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!n3x4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!n3x4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic 424w, https://substackcdn.com/image/fetch/$s_!n3x4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic 848w, https://substackcdn.com/image/fetch/$s_!n3x4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic 1272w, https://substackcdn.com/image/fetch/$s_!n3x4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!n3x4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1017613,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/heic&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_!n3x4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic 424w, https://substackcdn.com/image/fetch/$s_!n3x4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic 848w, https://substackcdn.com/image/fetch/$s_!n3x4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic 1272w, https://substackcdn.com/image/fetch/$s_!n3x4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff545169a-1049-4970-b262-72c00447b3f5_4032x2268.heic 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><p>To find an answer, let&#8217;s ask another question first. How does one assess the importance of a developer not having a laptop? It sounds quite critical; they cannot perform the function that the team, as a cohesive unit producing software applications, is supposed to include.</p><p>What about an uncomfortable chair? It doesn&#8217;t seem as obvious. But if a bad chair leads to a person&#8217;s irritability, worsens communication, makes the team less effective as a unified group, and slows down the delivery of results to the client, it becomes significant.</p><p>One might say, &#8220;Ignore that. The impact is negligible. Even if a developer loses 0.05% of productivity due to a bad chair or a faulty office lock, it&#8217;s nothing&#8212;they take longer to drink coffee.&#8221; To this, one could respond that, firstly, this figure can be multiplied by the number of developers, and secondly, by the average number of everyday problems. Thus, because no one fixes "not important problems&#8221; (even in personal life), everyone else indirectly suffers, resulting in lost productivity.</p><p>Here is just one of billions of stories.</p><p>Today, I fixed the lock in my home office. It was initially installed by someone else as a placeholder for another lock (presumably by previous occupants). We didn&#8217;t have any keys for it, and it didn&#8217;t function properly. I purchased a rim cylinder with keys (the component where you insert the key to turn the locking mechanism), a metal hacksaw, and a chisel (I needed to move the lock lower to have both parts on the wall and on the door aligned horizontally to make it functioning)&#8212;all just <strong>to be able to close the door when necessary </strong>(value by itself or an opportunity to make some other value, for example, keep important communications focused<strong>)</strong>. I spent about <strong>5-6 hours</strong> over several days (cost), but I was not only <strong>pleased</strong> with the result but also <strong>inspired</strong> (side value).</p><p>Perhaps there are tasks YOU have been meaning to tackle for a long time&#8212;issues lingering in your daily life. Consider what those tasks are and what value (and to whom) will be gained once you finally address them.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[#23: Embedded reasoning for ChatGPT]]></title><description><![CDATA[Knock-knock.]]></description><link>https://blog.devtower.io/p/23-embedded-reasoning-for-chatgpt</link><guid isPermaLink="false">https://blog.devtower.io/p/23-embedded-reasoning-for-chatgpt</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Thu, 12 Sep 2024 23:38:33 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!hCM1!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23b6de6-1727-4c91-8e64-18bf186739d7_178x178.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Knock-knock. Good morning. Here comes another AI breakthrough.</p><p>So, OpenAI has released O1 preview and mini, and in short, I&#8217;m thrilled. The model "thinks" before responding and solves complex tasks significantly better than previous models.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_UkG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_UkG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png 424w, https://substackcdn.com/image/fetch/$s_!_UkG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png 848w, https://substackcdn.com/image/fetch/$s_!_UkG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png 1272w, https://substackcdn.com/image/fetch/$s_!_UkG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_UkG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png" width="978" height="196" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:196,&quot;width&quot;:978,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29032,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!_UkG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png 424w, https://substackcdn.com/image/fetch/$s_!_UkG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png 848w, https://substackcdn.com/image/fetch/$s_!_UkG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png 1272w, https://substackcdn.com/image/fetch/$s_!_UkG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4183af91-531b-4ac6-98e3-5cf3a3e4dcd6_978x196.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><p>Last night, I decided to test it by writing a service in Go with its help, which collects statistical metrics from GitLab. The model succeeded. More precisely, it first built the project structure, filled in the files with content it suggested, and left placeholders where it couldn't write. Then, I iteratively asked it to handle each metric individually. No issues at all. Some work had to be done manually (like copying content between files), but it was very straightforward.</p><p>I specifically chose Go, a language I know little about, so I wouldn&#8217;t interfere with the model&#8217;s process using my own experience on how things should be written, focusing purely on "I can read the code in any language," while the model should write it itself.</p><p>How does it work? According to the documentation, OpenAI first trained an internal reasoning model using reinforcement learning (where the model succeeds or makes mistakes, receives feedback, and adjusts its weights). The internal model is designed to output reasoning tokens based on input tokens (essentially a preliminary response in the form of reasoning about the query, an embedded chain of thoughts). Then, the input plus reasoning generate output tokens. Tokens from previous reasoning aren&#8217;t involved in further communication to avoid overcomplicating things.</p><p>It&#8217;s already available for those with a subscription, and I highly recommend giving it a try. There are limits, but mini should be enough for writing code (limit of 50 messages), while preview has a limit of 30.</p><p>For general users: <a href="https://openai.com/index/introducing-openai-o1-preview/">https://openai.com/index/introducing-openai-o1-preview/</a></p><p>For tech enthusiasts: <a href="https://platform.openai.com/docs/guides/reasoning">https://platform.openai.com/docs/guides/reasoning</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading DevTower! Subscribe for free to receive new posts and support my work.</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>]]></content:encoded></item><item><title><![CDATA[#22: I celebrate the first decade of my career. Here are 10 of the most impactful insights I've got.]]></title><description><![CDATA[I spent 10 years in software engineering and here are 10 important things I learned.]]></description><link>https://blog.devtower.io/p/21-i-celebrate-the-first-decade-of</link><guid isPermaLink="false">https://blog.devtower.io/p/21-i-celebrate-the-first-decade-of</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Fri, 09 Aug 2024 18:13:25 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/43cae573-a99e-44d3-b0ed-e042cfa87fa8_815x822.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I spent 10 years in software engineering and here are 10 important things I learned.</p><p>Today I celebrate the first decade of my career. On this path, I've been exploring more and more, diving deeper and deeper, getting wider and wider perspectives, and here are 10 of the most impactful insights I've got.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading DevTower! Subscribe for free to receive new posts and support my work.</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>1. The team is the driver. A strong team can make everything you can imagine but a strong team is not just a set of strong individuals, it is also strong relationships and a healthy atmosphere of cooperation.</p><p>2. Sustainable development is a result of evolution. Over this decade I've seen many examples when people (including me) overthink a problem, trying to find a silver bullet via creating a complex solution expecting that a simple task will transform into a much more complex one but this does not happen. This statement is not only about coding but also about every area where you can apply an engineering approach (including development process improvement).</p><p>3. Success is a result of meeting expectations. The single definition of success that makes sense to me is meeting the expectations of those who are interested in the result. If you create a boat that should be perfect from a transferring perspective for those who want to cross the river, they won't care that you forgot a figurehead.</p><p>4. A consistent model of the world in your head is truth. If you have a consistent model in your mind that explains why you should do X but not Y and nobody can break it, you must trust yourself.</p><p>5. Inclusivity brings efficiency. Practically speaking, all people have good ideas that help to identify alternative POVs on the problem. But not everyone is bold enough to speak loudly. You might have a diverse team but if you do not help them to be included in discussions you lose all the benefits.</p><p>6. Feedback Cycles is a source of improvements. Do you want to improve something? Create a feedback cycle. Period. And don't forget to measure to verify the progress. Period Period.</p><p>7. Creative ideation requires freedom. If you apply too many constraints and limitations, if you create too tough processes, this might damage creativity because when people strictly follow rules it is harder to apply critical thinking and identify alternatives</p><p>8. Listen, not speak. Rapid reaction to something you hear often will bring wrong outcomes because to solve a problem you have to understand it, to understand it, especially, the root cause of it you have to listen. Listen a lot.</p><p>9. Startup needs speed, enterprise needs quality. Speed vs Quality is one of the most dramatic trade-offs I have ever seen. Those who spend too much on quality on early stages just don't survive because speed is not enough to achieve results and get first clients, those who ignore quality because of high pace start loosing their clients.</p><p>10. Purpose brings motivation. Not money, not impressive speeches, not authority but answer on the question "why" brings long-term motivation</p><p>11. You are able.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bj1Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bj1Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Bj1Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Bj1Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Bj1Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bj1Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg" width="1456" height="72" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:72,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:74700,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&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_!Bj1Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Bj1Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Bj1Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Bj1Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F646722c5-fc3c-4c9a-9a13-85a087c33ab9_1627x81.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[#21: Why "work hour rate-based decisions" in personal life is a bad idea]]></title><description><![CDATA[Articles]]></description><link>https://blog.devtower.io/p/21-why-work-hour-rate-based-decisions</link><guid isPermaLink="false">https://blog.devtower.io/p/21-why-work-hour-rate-based-decisions</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 01 Oct 2023 13:02:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!EGik!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Some time ago, I heard from some colleagues that hour rate-based decisions would simplify your life, so if you have to do something, compare your hourly rate with the rate of a professional in that field. In this issue, I&#8217;d like to explain what is wrong with that approach and where you should focus.</p><p>As you might know, I&#8217;m from software engineering, so my hourly rate is relatively higher than many other jobs. A conjunction of that with the rule &#8220;pay if someone&#8217;s time is cheaper than yours&#8221; brings many issues and eventually brings unhappiness. Let me explain</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EGik!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EGik!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png 424w, https://substackcdn.com/image/fetch/$s_!EGik!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png 848w, https://substackcdn.com/image/fetch/$s_!EGik!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png 1272w, https://substackcdn.com/image/fetch/$s_!EGik!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EGik!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png" width="1456" height="310" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:310,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:181016,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!EGik!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png 424w, https://substackcdn.com/image/fetch/$s_!EGik!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png 848w, https://substackcdn.com/image/fetch/$s_!EGik!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png 1272w, https://substackcdn.com/image/fetch/$s_!EGik!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81b74f82-d4c6-41f3-a216-44411a339ed8_4331x923.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><blockquote><p>After the first 20 issues and ~4.5 months of doing this weekly I see that to growth a list of subscribers it is still the requirement to actively promote the weekly on other platforms. At the same time it is a pretty strong commitment for volantaury activity. So I decided to not put it on schedule but rather publish on demand and use rather as a platform for long posts.</p><p>I also invite you to join <strong>DevTower</strong> telegram <a href="https://t.me/+K4kiT1YDIJ5lZDgy">channel</a> for more frequent updates and collaboration. See you there</p></blockquote><h3>Logical consequence &#8220;Do it by yourself if your time is cheaper&#8221; does not work</h3><p>Plenty of different areas like legal, medicine, and accounting are nearly impossible to do by yourself, even if your time is cheaper. So, it requires a ton of extra education, so we have a steep learning curve. These exclusions highlight that the rule does not work perfectly well.</p><h3>One-time job activities</h3><p>Sometimes, deep extra expertise is not required, or there is a shallow learning curve, but the job has to be done only once. It is impossible to reuse the experience and accumulated knowledge. For example, if you have a good public profile, you could try to apply for UK&#8217;s Global Talent Visa. That will require highlighting the most critical aspects of your work relevant to this particular type of visa.  This is a one-time job. You won&#8217;t apply for GTV after success again because it does not make sense. At the same time, building your submission properly will require 2-3+ months. </p><p>On the other hand, some services lead you by the hand through this submission, but the cost is 5 000 GBP (~6 000 USD). You might have a relatively smaller income, so self-submission of documents sounds fine. Or not?</p><p>Do not underestimate lost opportunities and knowledge because you were busy for long months deep-diving into processes that will never repeat.</p><h3>Correlation between rest and hour rate</h3><p>Usually, you get paid with an implicit contract that the other part of your time you should get recovery to produce the same result predictably.</p><p>Using your hourly rate to make decisions regarding personal activities assumes that you work all your non-sleeping time. But if you spread your hourly rate on all your time, you would also see that your recovery time is paid, not extra work time.</p><p>So, if there is no recovery, what will happen to your efficiency and results? How does your focus keep strong? How long will you keep the same hourly rate, at least?</p><h3>Satisfaction impacts motivation</h3><p>You likely prefer doing something you like rather than something you don&#8217;t. That is obvious. I believe that doing your favorite things gives you a much higher probability of success than otherwise. So why should you base your decisions on short-term money profit but not long-term success?</p><h3>Conclusion</h3><p>The hourly rate does not work as a criterion for personal decisions. Here are a few arguments that I rely on. Are there any doubts? I invite you to join our <a href="https://t.me/+QyaW25-AJyE1Y2Uy">community</a> and discuss or subscribe to <a href="https://t.me/+K4kiT1YDIJ5lZDgy">the channel</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading DevTower's Articles! Subscribe for free to receive new posts and support my work.</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[#20: Why are CDNs so quick?]]></title><description><![CDATA[DevTower Weekly]]></description><link>https://blog.devtower.io/p/20-why-cdns-are-so-quick</link><guid isPermaLink="false">https://blog.devtower.io/p/20-why-cdns-are-so-quick</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 24 Sep 2023 13:00:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!uzd6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You have probably already heard that CDN (Content Delivery Network) speeds up your statics delivery due to a distributed system of caches. But how does this work? In this issue, we try to navigate through this topic.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uzd6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uzd6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png 424w, https://substackcdn.com/image/fetch/$s_!uzd6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png 848w, https://substackcdn.com/image/fetch/$s_!uzd6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png 1272w, https://substackcdn.com/image/fetch/$s_!uzd6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uzd6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png" width="1456" height="874" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:874,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:283669,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!uzd6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png 424w, https://substackcdn.com/image/fetch/$s_!uzd6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png 848w, https://substackcdn.com/image/fetch/$s_!uzd6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.png 1272w, https://substackcdn.com/image/fetch/$s_!uzd6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2775ed0c-c1dd-4587-817a-82ab5d3709b2_2581x1549.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></figure></div><p>The main idea behind CDN is that to make our system more reliable and performant for distributed loading, we introduce a distributed proxy &amp; cache that hides the original application. In doing that, we add a DNS record that points to the IP addresses of CDN. Under the hood, a CDN proxy node requests to our origin server and caches results. If an origin server outage is in place, our static data might still work due to edge-caching. So the next question how to find the best CDN edge node?</p><h3>Round-robin DNS</h3><p>Thanks to <a href="https://www.cloudflare.com/learning/dns/glossary/round-robin-dns/">round-robin DNS</a> and redundancy, we distribute loading between IP adresses of CDN (not necessarily evenly), but those IP addresses are the same for every region. Does not seem distributed? That is because round-robin DNS does not care about geographical distance. Anycast comes to our aid here.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h3>Anycast</h3><p><a href="https://www.imperva.com/learn/performance/anycast/">Anycast DNS</a> is a traffic routing algorithm that allows to assign one IP address to many nodes. The approach has helpful advantages:</p><ul><li><p>high availability thanks to multiple nodes with redundancy sharing the same IP address</p></li><li><p>lower latency because traffic is routed to the geographically nearest server</p></li><li><p>scaling via adding of new nodes</p></li></ul><p>As an alternative for finding the closest destination for a request, it is worth mentioning GeoDNS, but it is out of the scope of today's issue.</p><p>This is still unclear how does this guarantee we do not go across the world to find the closest node? IXP will help us to answer how to avoid <a href="https://blog.telegeography.com/what-is-the-trombone-effect">The Trombone Effect</a> (inefficient network path of queries).</p><h2>IXP</h2><p><a href="https://www.cloudflare.com/learning/cdn/glossary/internet-exchange-point-ixp">Internet Exchange Point</a> (IXP) is a physical location. Internet Service Providers and CDN providers share infrastructure there to establish the most efficient cross-network communication. IXP is presented as one or more physical buildings and depending on a particular demand it is helpful to connect networks either for free or some members might charge for their service. So, clients ISP has its edge node in the closest to a particular client IXP which is well-connected with other networks and especially with CDN providers. A map of IXP can be found <a href="https://www.internetexchangemap.com/">right there</a>.</p><h2>Batumi meetup</h2><p>One week ago, I had a chance to speak at IT Meetup Batumi about &#8220;Practical Evolution of a Distributed System&#8221;. Watch the recording on their channel (click on the picture)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://www.youtube.com/live/da_dEOVklOI?si=0r32QMfuHncfxn_0&amp;t=2550" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LbHH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.png 424w, https://substackcdn.com/image/fetch/$s_!LbHH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.png 848w, https://substackcdn.com/image/fetch/$s_!LbHH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.png 1272w, https://substackcdn.com/image/fetch/$s_!LbHH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LbHH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.png" width="1456" height="993" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:993,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3523850,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://www.youtube.com/live/da_dEOVklOI?si=0r32QMfuHncfxn_0&amp;t=2550&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_!LbHH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.png 424w, https://substackcdn.com/image/fetch/$s_!LbHH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.png 848w, https://substackcdn.com/image/fetch/$s_!LbHH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.png 1272w, https://substackcdn.com/image/fetch/$s_!LbHH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0722398c-84ef-408c-b0d8-493dc32107c2_2628x1792.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-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/20-why-cdns-are-so-quick?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 DevTower Weekly. This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/20-why-cdns-are-so-quick?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.devtower.io/p/20-why-cdns-are-so-quick?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div>]]></content:encoded></item><item><title><![CDATA[#19: 30 things I learned before turning 30]]></title><description><![CDATA[DevTower Weekly]]></description><link>https://blog.devtower.io/p/19-30-things-i-learned-before-turning</link><guid isPermaLink="false">https://blog.devtower.io/p/19-30-things-i-learned-before-turning</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 17 Sep 2023 13:00:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Tqsc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today, I&#8217;m celebrating my 30th birthday. That is a great point of time to summarize what I learned. In this issue, you will find a compilation of the most impactful lessons I learned.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Tqsc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Tqsc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!Tqsc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!Tqsc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!Tqsc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Tqsc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:183347,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!Tqsc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!Tqsc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!Tqsc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!Tqsc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0e513dc3-f6d4-41fc-85b9-c817956273d3_1920x1080.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></figure></div><ol><li><p>Understanding your mission and long-term goals simplifies most of your choices</p></li><li><p>The younger your children, the more they need you</p></li><li><p>Give preference to those decisions that keep more opportunities and flexibility</p></li><li><p>Give preference to experience and opportunities instead of money</p></li><li><p>Raise yourself, not your children. They will learn from you</p></li><li><p>Responsibilities come before the reward</p></li><li><p>The well-known reward is limited</p></li><li><p>Understanding your and others' needs is the key to strong relationships</p></li><li><p>Compound interest works for your public activities (and other investments into yourself) in the same way as for regular investments</p></li><li><p>An emergency fund can save your nerves and mental health in critical moments</p></li><li><p>If high-risk investments are made, and there is a profit, take the size of the investments + 30% and play with the rest</p></li><li><p>Any risk (high/low) is acceptable but depends on % of capital under this risk</p></li><li><p>Make investments for the long term if this is not your day-to-day work (otherwise, name it trading and do not deceive yourself)</p></li><li><p>The more time you have, the more risk you can accept</p></li><li><p>Geopolitical risks exist</p></li><li><p>Work at places where you can impact the direction of movement in a certain amount at least relevant to your role</p></li><li><p>Even not accurate long-term planning makes more realistic short-term achievements</p></li><li><p>Think about Products, not Projects</p></li><li><p>Openness is the key to communication</p></li><li><p>Complex solutions must require motivation behind the complexity. Otherwise, prefer simple ones (even if they are not so beautiful)</p></li><li><p>All people have those who would like to read them</p></li><li><p>Before investments in the public market, try to find opportunities for investments in knowledge or skills to extend your space of opportunities</p></li><li><p>Build processes, hire, and delegate</p></li><li><p>As soon as you create an ad-hoc solution, start thinking about a systematic solution</p></li><li><p>IT does not exist without business behind</p></li><li><p>Soft skills are much harder to develop than hard skills</p></li><li><p>Make decisions on time but not too early, especially if they introduce limitations for you</p></li><li><p>Happiness can be felt only if you try unhappiness</p></li><li><p>Altercation is not as scary as ignoring needs</p></li><li><p>Life is not only about the past and future but also about the moment</p><p> </p></li></ol><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading DevTower Weekly! Subscribe for free to receive new posts and support my work.</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[#18: Evolutionary everything (including architecture)]]></title><description><![CDATA[DevTower Weekly]]></description><link>https://blog.devtower.io/p/18-evolutionary-everything-including</link><guid isPermaLink="false">https://blog.devtower.io/p/18-evolutionary-everything-including</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 10 Sep 2023 11:30:48 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!jID7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>About 6 years ago, I joined a project where my main responsibility was to create a scheduler for cab routing in the UK. The task was challenging, but my background in a scientific company and education helped me to find a solution even when I had just a few years of experience. I tried a genetic algorithm.</p><p>A generic algorithm is one of the metaheuristics evolutionary algorithms that mainly simulate generic NP-complex problem-solving in the form of evolution and tries to find quasi-optimal solutions. Possible solutions are individuals. Their properties are abstracted as chromosomes and genes. All the surviving solutions in each generation constitute the population. Individuals are comparable via fitness function (objective function). On every iteration, the algorithm performs selection, mutation, and crossover. Amazing! Isn&#8217;t it?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jID7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jID7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png 424w, https://substackcdn.com/image/fetch/$s_!jID7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png 848w, https://substackcdn.com/image/fetch/$s_!jID7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png 1272w, https://substackcdn.com/image/fetch/$s_!jID7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jID7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png" width="1456" height="1338" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1338,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;undefined&quot;,&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="undefined" title="undefined" srcset="https://substackcdn.com/image/fetch/$s_!jID7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png 424w, https://substackcdn.com/image/fetch/$s_!jID7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png 848w, https://substackcdn.com/image/fetch/$s_!jID7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.png 1272w, https://substackcdn.com/image/fetch/$s_!jID7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a4890b-521e-42f2-b860-9f1549c8dee9_2560x2353.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></figure></div><p>The more tech progress moves forward, the more I come across options to leverage the idea of evolution. So, evolution moves from nature to digital in the context where our technologies evolve more quickly than we do. Can you imagine how I rejoiced when I realized that the same idea is applied in software architecture? Look at this <a href="https://evolutionaryarchitecture.com/">evolutionaryarchitecture.com</a>.</p><p>Evolutionary architecture has some perfect matching with reality and common sense as well as with my feeling that an iterative approach is the key. Neal Ford, Rebecca Parsons, and Patrick Kua wrote a book about that.</p><p>Your fitness function includes technical and business parameters. Automation is crucial here to control the level of fitness. Architecture incrementally moves forward alongside context updates.</p><p>I have not read the book yet, but it is already on my reading list.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading DevTower Weekly! Subscribe for free to receive new posts and support my work.</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>Learn with me</h2><p>Whenever I hear about NP-hardness, I google it because I cannot remember the meaning. Seems I found a good video that explains the concept.</p><div id="youtube2-AgtOCNCejQ8" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;AgtOCNCejQ8&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/AgtOCNCejQ8?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[#17: The Ultimate Repository Configuration]]></title><description><![CDATA[DevTower Weekly]]></description><link>https://blog.devtower.io/p/17-the-ultimate-repository-configuration</link><guid isPermaLink="false">https://blog.devtower.io/p/17-the-ultimate-repository-configuration</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 03 Sep 2023 13:00:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!s8Ob!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Just renamed From Junior to CTO Weekly Thoughts to DevTower Weekly</p><p>fjtc.substack.com &#8594; devtower.substack.com</p></blockquote><p>The Ultimate Software Engineering requires us to follow some rules, and leaving their maintenance without control will lead to increasing entropy. The more rules we define, the more difficult it is to support them manually. In this issue, we will summarize the configuration to maintain already known pieces of the ultimate software engineering and automation of that maintenance.</p><p>As before, my experience mainly relates to Gitlab, so some things might not work on other platforms.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s8Ob!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s8Ob!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png 424w, https://substackcdn.com/image/fetch/$s_!s8Ob!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png 848w, https://substackcdn.com/image/fetch/$s_!s8Ob!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png 1272w, https://substackcdn.com/image/fetch/$s_!s8Ob!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s8Ob!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png" width="1456" height="773" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:773,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:207358,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!s8Ob!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png 424w, https://substackcdn.com/image/fetch/$s_!s8Ob!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png 848w, https://substackcdn.com/image/fetch/$s_!s8Ob!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.png 1272w, https://substackcdn.com/image/fetch/$s_!s8Ob!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27728d3f-1926-4394-a855-c177401e88fe_1992x1058.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></figure></div><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>How Gitlab helps to configure</h2><p><a href="https://devtower.substack.com/p/10-the-ultimate-commit">The Ultimate Commit</a>, <a href="https://devtower.substack.com/p/13-the-ultimate-contribution">The Ultimate Contribution</a>, and <a href="https://devtower.substack.com/p/14-the-ultimate-code-review">The Ultimate Code Review</a> require you to form your commit messages according to Conventional Commits spec. Additionally, branches should be named after tickets, approvals must be given before merging, etc.  So many rules. Let&#8217;s check what opportunities we have to manage these constraints.</p><p>It is highly recommended to read the mentioned posts before this one.</p><h3>Push rules</h3><p>It is important to say that even though push rules are amazing, they are available only on the Premium Gitlab subscription. I won&#8217;t sell GitLab here, but this advantage makes sense.</p><p>I&#8217;ve already described push rules usage before in <strong>The Ultimate Contribution</strong> post. So, read it <a href="https://devtower.substack.com/i/135542769/automation-of-dod-compiance-check">there</a>. You can also review the docs available <a href="https://docs.gitlab.com/ee/user/project/repository/push_rules.html">here</a>.</p><h3>Approval Process</h3><p>An approval process is available in all versions of GitLab, but for the free one, it is not flexible. Greater plans <a href="https://docs.gitlab.com/ee/user/project/merge_requests/approvals/index.html">provide the opportunity</a> to use code owners or manually configure approvers.</p><p>Another important setting available for approvals is Settings &gt; Merge requests &gt; Merge request approvals &gt; Approval settings &gt; [Unset] Remove all approvals. <a href="https://devtower.substack.com/i/135682580/resolve-reviewer-comments-only-with-their-permission">In The Ultimate Code Review</a> I described why it is important to improve collaboration.</p><p>Additionally, you could disable emojis because the approval process is in place, but it is not necessary (Settings / General / Visibility, project features, permissions)</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!B4CS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!B4CS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png 424w, https://substackcdn.com/image/fetch/$s_!B4CS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png 848w, https://substackcdn.com/image/fetch/$s_!B4CS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png 1272w, https://substackcdn.com/image/fetch/$s_!B4CS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!B4CS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png" width="760" height="76" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:76,&quot;width&quot;:760,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15979,&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_!B4CS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png 424w, https://substackcdn.com/image/fetch/$s_!B4CS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png 848w, https://substackcdn.com/image/fetch/$s_!B4CS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png 1272w, https://substackcdn.com/image/fetch/$s_!B4CS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc83359d5-460d-4b37-8b0c-8a579c777d68_760x76.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Repository Restrictions</h3><p>Protected branches do not allow you to push changes directly. That is a great constraint that simplifies the process and does not allow unexpected changes to be delivered. The default branch is used as a default target for Merge Requests. Use the following sections to manage:</p><blockquote><p>Settings / Respository / Branch defaults</p><p>Settings / Respository / Protected branches</p></blockquote><h3>Merge Requests</h3><p>To get a properly working git history, it is important to configure merge requests. You can find settings at:</p><blockquote><p>Settings / Merge Requests</p></blockquote><p>Configure the merge method. We discussed that merge commit gives you more flexibility than fast-forward or semi-linear. There is a property in place.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MFri!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MFri!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png 424w, https://substackcdn.com/image/fetch/$s_!MFri!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png 848w, https://substackcdn.com/image/fetch/$s_!MFri!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png 1272w, https://substackcdn.com/image/fetch/$s_!MFri!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MFri!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png" width="1440" height="550" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:550,&quot;width&quot;:1440,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:141519,&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_!MFri!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png 424w, https://substackcdn.com/image/fetch/$s_!MFri!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png 848w, https://substackcdn.com/image/fetch/$s_!MFri!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.png 1272w, https://substackcdn.com/image/fetch/$s_!MFri!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9dd42475-bbfb-42e4-a5b3-f992d626b8f8_1440x550.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>Thanks to conventional commits spec, every commit matters, so you should disable squashing as a possible action via UI. If developers decide to squash some commits because of the wrong decomposition, they should do it manually.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vhhy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vhhy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png 424w, https://substackcdn.com/image/fetch/$s_!vhhy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png 848w, https://substackcdn.com/image/fetch/$s_!vhhy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png 1272w, https://substackcdn.com/image/fetch/$s_!vhhy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vhhy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png" width="1456" height="376" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:376,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:130918,&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_!vhhy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png 424w, https://substackcdn.com/image/fetch/$s_!vhhy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png 848w, https://substackcdn.com/image/fetch/$s_!vhhy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.png 1272w, https://substackcdn.com/image/fetch/$s_!vhhy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5c96ae6-4e16-41c3-95b2-1e5b76122c2e_1930x498.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>Threads help to control how many open questions there are. You can have an agreement with your team that a developer resolves threads only if a reviewer explicitly asks them on the last comments. Otherwise, merge requests cannot be finished. Something similar we have for pipelines. If your pipeline doesn&#8217;t work, it likely won&#8217;t work on the default branch. So, protect yourself and do not allow merge unsuccessful pipelines.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5x9V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5x9V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png 424w, https://substackcdn.com/image/fetch/$s_!5x9V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png 848w, https://substackcdn.com/image/fetch/$s_!5x9V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png 1272w, https://substackcdn.com/image/fetch/$s_!5x9V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5x9V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png" width="1300" height="380" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:380,&quot;width&quot;:1300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84434,&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_!5x9V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png 424w, https://substackcdn.com/image/fetch/$s_!5x9V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png 848w, https://substackcdn.com/image/fetch/$s_!5x9V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.png 1272w, https://substackcdn.com/image/fetch/$s_!5x9V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8493a4cc-fbb9-4ccc-a4f1-52891585edd4_1300x380.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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/17-the-ultimate-repository-configuration?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.devtower.io/p/17-the-ultimate-repository-configuration?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2>Configuration as a Code</h2><p>Maintenance of all these configurations is pretty hard everywhere. Otherwise, it is not guaranteed that these rules are satisfied. In my practice, I saw how teams created their own job that ensures configuration according to the committed config, but instead of writing your custom job that works with GitLab API, you could try:</p><p><a href="https://gitlabform.github.io/gitlabform/">https://gitlabform.github.io/gitlabform/</a></p><p>I did not use this tool, but it looks similar to our in-house solution.</p><h2>Conclusion</h2><p>Simple rules should be satisfied to make the development process solid and reliable. Modern VCS hosting helps to control these rules, but that might require advanced plans. You can avoid manually maintaining these options by using configuration as a code solution.</p><h2>The Ultimate Software Engineering Series</h2><p>The Ultimate Software Engineering topic is not exhausted yet. I need to summarise some ideas to accurately deliver them as well as publish already described ones wider. So, the next issue won&#8217;t be dedicated to another topic inside the idea but rather some other considerations, practices, and practical advice. Subscribe so as not to miss</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading From Junior to CTO Weekly Thoughts! Subscribe for free to receive new posts and support my work.</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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lpCG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lpCG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png 424w, https://substackcdn.com/image/fetch/$s_!lpCG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png 848w, https://substackcdn.com/image/fetch/$s_!lpCG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!lpCG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lpCG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png" width="1456" height="789" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:789,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:216630,&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_!lpCG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png 424w, https://substackcdn.com/image/fetch/$s_!lpCG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png 848w, https://substackcdn.com/image/fetch/$s_!lpCG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!lpCG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9085a5f-c202-4a2b-a426-dd59e963ed2e_1994x1080.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></p><h2>Learn with me (ex. The Video of The Week)</h2><div id="youtube2-wnydtt2lTQk" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;wnydtt2lTQk&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/wnydtt2lTQk?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[#16: The Ultimate Branching Strategy]]></title><description><![CDATA[From Junior to CTO Weekly Thoughts]]></description><link>https://blog.devtower.io/p/16-the-ultimate-branching-strategy</link><guid isPermaLink="false">https://blog.devtower.io/p/16-the-ultimate-branching-strategy</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 27 Aug 2023 13:03:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7UqL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are many strategies for managing branches in your software development process. In <a href="https://fjtc.substack.com/p/13-the-ultimate-contribution">The Ultimate Contribution</a> post, I mentioned branches and merge requests, which explain a single contribution but not a collaboration between many developers. Collaboration can be organized with different branching strategies. The best one for you depends on certain aspects of your context. In this issue, we will discuss when to apply which one.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7UqL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7UqL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png 424w, https://substackcdn.com/image/fetch/$s_!7UqL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png 848w, https://substackcdn.com/image/fetch/$s_!7UqL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png 1272w, https://substackcdn.com/image/fetch/$s_!7UqL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7UqL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png" width="1456" height="763" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:763,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:221089,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!7UqL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png 424w, https://substackcdn.com/image/fetch/$s_!7UqL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png 848w, https://substackcdn.com/image/fetch/$s_!7UqL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.png 1272w, https://substackcdn.com/image/fetch/$s_!7UqL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5a12f77f-e901-4fe1-8ef1-fa0d550d9cff_2056x1078.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></figure></div><p>As before, my experience is mainly related to Git, so you can try to map some ideas to another VCS, but I didn&#8217;t have the intention to make it compatible.</p><h2>Overview</h2><p>There are no best or worst options, but there are more appropriate ones for your case.</p><p>First of all, let&#8217;s name what options are widely used:</p><ul><li><p>Git Flow</p></li><li><p>Trunk-based Flow + Feature Flags</p></li><li><p>GitHub Flow</p></li><li><p>Gitlab Flow</p></li><li><p>One Flow</p></li></ul><p>You might find other strategies, but I want to show you a framework for choosing the best from the available options.</p><p>We will compare and find the right place for these strategies, but first, let&#8217;s formulate properties for atoms of these approaches: Commit, Branch, Tag.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>Atoms</h2><h3>Commit</h3><p>An immutable state of the repository. The key properties of any commit:</p><ul><li><p>uniquely identifies a change and state of the repository since the change is applied</p></li><li><p>immutable state</p></li></ul><h3>Branch</h3><p>Dynamic pointer to a commit that isolates and tracks a set of changes. The key properties of any branch:</p><ul><li><p>dynamically identifies a set of changes</p></li><li><p>simplifies work with an isolated set of changes</p></li></ul><h3>Tag</h3><p>Static pointer to a commit that simplifies the detection of a particular state. The key properties of any tag:</p><ul><li><p>names a state</p></li><li><p>manage static identification. For example, 1.0.0 statically identifies sources for a particular version of the component.</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_!dbIs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dbIs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png 424w, https://substackcdn.com/image/fetch/$s_!dbIs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png 848w, https://substackcdn.com/image/fetch/$s_!dbIs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png 1272w, https://substackcdn.com/image/fetch/$s_!dbIs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dbIs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png" width="1456" height="1135" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1135,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:198719,&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_!dbIs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png 424w, https://substackcdn.com/image/fetch/$s_!dbIs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png 848w, https://substackcdn.com/image/fetch/$s_!dbIs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.png 1272w, https://substackcdn.com/image/fetch/$s_!dbIs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7445eaba-50eb-47ab-832d-12bb900c281a_1604x1250.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>Before diving deep into strategies, let&#8217;s understand what properties will impact choosing the most appropriate one.</p><h2>Properties that impact strategy choice</h2><p>The branching strategy is a living organism that should adapt to your current context. </p><h3>Team size</h3><p>Adaptation means starting from the simplest option for a single developer (if that is your case) and, evolutionary, coming to the best option for a team.</p><h3>Team skills</h3><p>Your team's skill level impacts the choice because some strategies protect you more from beginner&#8217;s mistakes than others.</p><h3>Code organization strategy</h3><p>The more projects are stored inside the same repository, the more people collaborate and resolve conflicts - the more important it is to consider options that minimize conflict rate and improve continuous integration. At the same time, if you can avoid complexity because there is no collaboration, why not?</p><h3>Desired frequency of delivery</h3><p>Do you want to deliver every single feature available immediately and turn them on/off via feature flags, or you do mostly not care about granular feature tuning? This matters.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>Strategies</h2><p>Common practice is that a feature branch is short-living, so since the feature is merged, you should remove a feature branch, but at the same time, if release branches exist, they should be removed only if your context allows that.</p><h3>Git Flow</h3><p>There is a chance that the quantity of articles about Git Flow is more than the quantity of atoms in the Universe. The strategy is pretty mature, but the disadvantages of it are well-discovered as well.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IT1i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IT1i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg 424w, https://substackcdn.com/image/fetch/$s_!IT1i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg 848w, https://substackcdn.com/image/fetch/$s_!IT1i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!IT1i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IT1i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg" width="1456" height="377" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:377,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:228736,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&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_!IT1i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg 424w, https://substackcdn.com/image/fetch/$s_!IT1i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg 848w, https://substackcdn.com/image/fetch/$s_!IT1i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!IT1i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77e653b1-6fb7-487f-b63e-3396a9bfa4e5_3931x1017.jpeg 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>This approach is generally good, but there is a place for some redundancy and potential inconsistency.</p><ul><li><p>Every next merge will require a run of the CI Pipeline, which means that if you checked something manually, it is not guaranteed to have the same on production because, after your check, the artifact will be rebuilt again (on release &#8594; main merge) so something might go wrong.</p></li><li><p>You have two long-living branches main &amp; develop. That potentially might introduce inconsistency, for example, because you might forget to merge back your fixes from the release branch</p></li></ul><p><strong>Team size:</strong> works for any team size, but it is overkill for a team of one</p><p><strong>Team skills</strong>: if you have fewer QA resources than needed, a low level of QA automation, and some developers have junior-level</p><p><strong>Code Organization Strategy: </strong>a single main branch might sound uncomfortable for mono repositories with many teams</p><p><strong>Desired frequency of delivery</strong>: at max once a few weeks</p><h3>Trunk-based Flow + Feature Flags</h3><p>The trunk is your main branch (whatever you name it), a place of <strong>Continuous Integration</strong>. Developers commit their changes as early as possible and create not feature branches but branches by abstractions, using feature flags to manage what is enabled in production. Merges should happen every day to guarantee a high level of continuous integration. Watch <em><strong>the video of the week</strong></em> at the end of the issue to get more 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_!jGsu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jGsu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png 424w, https://substackcdn.com/image/fetch/$s_!jGsu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png 848w, https://substackcdn.com/image/fetch/$s_!jGsu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png 1272w, https://substackcdn.com/image/fetch/$s_!jGsu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jGsu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png" width="1456" height="792" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:792,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:265833,&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_!jGsu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png 424w, https://substackcdn.com/image/fetch/$s_!jGsu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png 848w, https://substackcdn.com/image/fetch/$s_!jGsu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.png 1272w, https://substackcdn.com/image/fetch/$s_!jGsu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335e99a7-5af2-4643-8c9c-0458cf73dca6_2450x1332.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>The approach is super simple but requires more effort and cost to implement. Feature flags require extra infrastructure, feature flags need to be maintained, feature flag cleanup process should be in place. At the same time, you get an opportunity to perform A/B testing for free.</p><p><strong>Team size:</strong> works for any team size (the simplest option for one developer)</p><p><strong>Team skills</strong>: a highly skilled team and a high level of QA automation. Developers have a strong understanding of how to manage abstractions with feature flags</p><p><strong>Code Organization Strategy: </strong>You get the most profits from mono repositories because all the code is integrated as quickly as possible. But in general both ways are fine.</p><p><strong>Desired frequency of delivery</strong>: as soon as abstraction is available in the main branch, it should be delivered. This is the fastest strategy of delivery.</p><h3>GitHub Flow</h3><p>This flow looks pretty similar to trunk-based approach. But the difference is that it doesn&#8217;t require daily merges.</p><p><strong>Team size:</strong> works for any team size (the simplest option for one developer)</p><p><strong>Team skills</strong>: mixed team with different levels, QA resources are enough to guarantee feature quality</p><p><strong>Code Organization Strategy: </strong>you get the most profits from mono repositories because all the code is integrated as quickly as possible.</p><p><strong>Desired frequency of delivery</strong>: as soon as a feature is available in the main  branch, it is deployable.</p><h3>GitLab Flow</h3><p>GitLab transforms the idea of branches into subsequent pipelines of changes. You merge feature branches to the main branch (for GitLab Flow it is the main long-living development branch), but you can also introduce any other branches you need, like &#8220;production&#8221;, &#8220;pre-production&#8221;, etc. The problem of inconsistency here is presented as well but in another form because you have long living branches for main and production.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y-Cb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y-Cb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png 424w, https://substackcdn.com/image/fetch/$s_!Y-Cb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png 848w, https://substackcdn.com/image/fetch/$s_!Y-Cb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png 1272w, https://substackcdn.com/image/fetch/$s_!Y-Cb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y-Cb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png" width="1456" height="826" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:826,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:143286,&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_!Y-Cb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png 424w, https://substackcdn.com/image/fetch/$s_!Y-Cb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png 848w, https://substackcdn.com/image/fetch/$s_!Y-Cb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.png 1272w, https://substackcdn.com/image/fetch/$s_!Y-Cb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3e106749-c769-4a9e-8d0a-8a51740c9493_1900x1078.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><strong>Team size:</strong> works for any team size (but overkill for a team of one)</p><p><strong>Team skills</strong>: mixed team with different levels, QA resources are enough to guarantee feature quality</p><p><strong>Code Organization Strategy: </strong>does not work if many projects stored in the same repository</p><p><strong>Desired frequency of delivery</strong>: at max once a few weeks, not more often</p><h3>One Flow</h3><p>This approach has some variations, and I really recommend you spend some time on <a href="https://www.endoflineblog.com/oneflow-a-git-branching-model-and-workflow">the original article</a>. The main idea is that you still have only one long-living branch and use another one only if you want to simplify navigation for bug fixes. The approach is pretty flexible and can be constructed according to your requirements</p><p><strong>Team size:</strong> works for any team size (moderate complexity for one developer)</p><p><strong>Team skills</strong>: mixed team with different levels, QA resources are enough to guarantee feature quality</p><p><strong>Code Organization Strategy: </strong>appropriate for both mono/micro repositories</p><p><strong>Desired frequency of delivery</strong>: release complexity is not high, but I&#8217;d say that it is designed for at max once a few weeks</p><h2>Conclusion</h2><p>Let&#8217;s review a few cases:</p><p><strong>The best for one developer and moderate QA automation</strong>: GitHub Flow</p><p><strong>The best for skilled teams and high QA automation</strong>: Trunk-based Flow</p><p><strong>The best for moderately skilled teams, low QA automation, and complex release acceptance process</strong>: GitLab Flow</p><p><strong>The best for moderately skilled teams, low QA automation, and simple release acceptance process</strong>: One Flow</p><p>There is no &#8220;the best strategy&#8221; because the most appropriate depends on your case. GitFlow is generally outdated because there are other simpler options to achieve the same results. Since you have this knowledge, you can choose or even design the most appropriate one. In the next issue, we will talk about <strong>The Ultimate Repository Configuration</strong> and get a better understanding of how to manage all these guides<strong>.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zz6z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zz6z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png 424w, https://substackcdn.com/image/fetch/$s_!zz6z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png 848w, https://substackcdn.com/image/fetch/$s_!zz6z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png 1272w, https://substackcdn.com/image/fetch/$s_!zz6z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zz6z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png" width="1456" height="788" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:788,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:216104,&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_!zz6z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png 424w, https://substackcdn.com/image/fetch/$s_!zz6z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png 848w, https://substackcdn.com/image/fetch/$s_!zz6z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.png 1272w, https://substackcdn.com/image/fetch/$s_!zz6z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56882539-27a2-4ba1-8309-7312cc4ea681_1982x1072.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-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/16-the-ultimate-branching-strategy?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 From Junior to CTO Weekly Thoughts. This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/16-the-ultimate-branching-strategy?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.devtower.io/p/16-the-ultimate-branching-strategy?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><h2>The Video Of The Week</h2><div id="youtube2-lqRQYEHAtpk" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;lqRQYEHAtpk&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/lqRQYEHAtpk?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3>Resources</h3><p><strong>Trunk-based development</strong></p><p>https://trunkbaseddevelopment.com/</p><p><strong>GitHub Flow</strong></p><p>https://githubflow.github.io/</p><p><strong>GitLab Flow</strong></p><p>https://about.gitlab.com/topics/version-control/what-is-gitlab-flow/</p><p><strong>One Flow</strong></p><p>https://www.endoflineblog.com/oneflow-a-git-branching-model-and-workflow</p>]]></content:encoded></item><item><title><![CDATA[#15: The Ultimate Approval Process]]></title><description><![CDATA[From Junior to CTO Weekly Thoughts]]></description><link>https://blog.devtower.io/p/15-the-ultimate-approval-process</link><guid isPermaLink="false">https://blog.devtower.io/p/15-the-ultimate-approval-process</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 20 Aug 2023 13:00:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!twhp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The result of the software engineering process is an application that fits business requirements. So, how to guarantee the shippable code makes sense for business and does not violate any rules? In this issue, we discuss how different aspects impact <strong>The Ultimate Approval Process</strong> which is usually initiated by <a href="https://fjtc.substack.com/p/13-the-ultimate-contribution">The Ultimate Merge Request</a> but goes beyond. So let&#8217;s understand how to build the best fit for you.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!twhp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!twhp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png 424w, https://substackcdn.com/image/fetch/$s_!twhp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png 848w, https://substackcdn.com/image/fetch/$s_!twhp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png 1272w, https://substackcdn.com/image/fetch/$s_!twhp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!twhp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png" width="1456" height="623" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/570c42be-a969-4131-a324-4e0085fc227b_2276x974.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:623,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:200806,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!twhp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png 424w, https://substackcdn.com/image/fetch/$s_!twhp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png 848w, https://substackcdn.com/image/fetch/$s_!twhp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.png 1272w, https://substackcdn.com/image/fetch/$s_!twhp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F570c42be-a969-4131-a324-4e0085fc227b_2276x974.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></figure></div><p></p><p>From time to time, we put different aspects at the forefront. For some businesses, functional requirements are more critical than non-functional ones (they just need to get results asap, ignoring security/performance/maintenance and other stuff). For others, balance is important. For some of them approval process is overkill for others it is a crucial point of control. So let&#8217;s first clarify why we need <em><strong>The Ultimate Approval Process</strong></em>.</p><h3><strong>Motivation</strong></h3><p>Any process consists of steps that should be done to complete the entire process. The quality of every step impacts the final result. Software development is not an exclusion. Here we have the same rules that external quality control (by another actor) helps to improve the quality of results and reduce risks significantly. <a href="https://www.unido.org/overview/member-states/change-management/faq/what-four-eyes-principle">4 eyes principle</a> says that at least 2 people should review results. But why is this not a cargo cult? Why should we keep it as a part of <em><strong>The Ultimate Software Engineering</strong></em>? The essence of the answer is <strong>failure</strong>.</p><p>We live in a world where people make mistakes. It is impossible to avoid them fully, but we can minimize the risk in the places where it is important. I have already mentioned in <em><strong><a href="https://fjtc.substack.com/p/14-the-ultimate-code-review">The Ultimate Code Review</a></strong></em> you SHOULD NOT review and comment on stylistic mistakes, and it is more important to focus on such hard things to change later. For example, a badly designed API will keep client dependencies and limit your move forward, or wrong business logic can break data that might have a cost-sensitive impact on your business and waste your time on careful bug fixes in already working functionality. The cost of failure is the key motivation to set up your approval process. Applying the right people at the right time in your approval process makes your business less error-prone and more efficient. Let&#8217;s clarify who are &#8220;the right people&#8221;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h3>Who</h3><p>First of all, let&#8217;s clarify the features of the right approver. He or she:</p><ul><li><p>must be in the context of the change or at least must have access to the requirements</p></li><li><p>has expertise in the area of change or is going to get this expertise</p></li></ul><p>The right choice makes any review meaningful for approvers and brings motivation. Approvers might be not only other engineers, tech-lead, or qa. <em><strong>The Ultimate Approval Process</strong></em> reflects your business needs so this might include lawyers, security engineers, and even clients in some cases.</p><h3>What</h3><p>An approval process is not only about pure code reviews. It validates all different aspects of functional and non-functional requirements. Try to answer the following questions to find the best defaults for your approval process:</p><ul><li><p>does this change require a state update and zero-downtime at the same time? Does this make sense to request reviews from well-experienced teammates?</p></li><li><p>does this change have infrastructure changes and request review by infrastructure engineers?</p></li><li><p>does this change require compliance review and validation with lawyers? (GDPR, CCPA, etc.)</p></li><li><p>should we document changes in any form and validate them with an architect? (technical documentation, ADRs, etc.)</p></li><li><p>should we revalidate that we have a budget for this change run because we know the implementation details?</p></li><li><p>should performance engineers have a closer look at that change?</p></li></ul><p>Some of these practices can require activities from time to time but not by default. It means that someone needs to decide when to request extra approval. If you want to answer YES everywhere, please remember that you have to balance between time/money and scope of work.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rwmE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rwmE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png 424w, https://substackcdn.com/image/fetch/$s_!rwmE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png 848w, https://substackcdn.com/image/fetch/$s_!rwmE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png 1272w, https://substackcdn.com/image/fetch/$s_!rwmE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rwmE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png" width="1234" height="1132" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1132,&quot;width&quot;:1234,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:152313,&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_!rwmE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png 424w, https://substackcdn.com/image/fetch/$s_!rwmE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png 848w, https://substackcdn.com/image/fetch/$s_!rwmE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.png 1272w, https://substackcdn.com/image/fetch/$s_!rwmE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe83edd49-8a3a-4ca1-9154-06d4f9ba188e_1234x1132.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" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sINh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sINh!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif 424w, https://substackcdn.com/image/fetch/$s_!sINh!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif 848w, https://substackcdn.com/image/fetch/$s_!sINh!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif 1272w, https://substackcdn.com/image/fetch/$s_!sINh!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sINh!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:6695828,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&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_!sINh!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif 424w, https://substackcdn.com/image/fetch/$s_!sINh!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif 848w, https://substackcdn.com/image/fetch/$s_!sINh!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif 1272w, https://substackcdn.com/image/fetch/$s_!sINh!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd81fc74a-6ba8-45a3-9400-da4c45fe1fc6_1270x1152.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h3>When</h3><p>Now we know the right people to approve, but it still might not be clear when they could control the results. Some practices like Shift Left move the review stage early, but they might be overkill in the beginning. So I recommend just starting reviewing incrementally do the left shift as much as possible. The bigger your team's scale and your product's complexity, the more important to move all such activities to the earliest possible time. For example, you should review and approve architecture before implementation, but you can approve the final implementation only when dedicated merge requests appear.</p><h3>Where</h3><p>This is one of the challenging questions because, due to the diversity of roles needed for the approval process, just a regular gitlab/github might not work. It depends on your company culture. Lawyers usually do not have gitlab accounts. So I&#8217;d say that if you are a small startup with a few components or bigger but do not have any approval process, start with approval process management embedded into your VCS hosting. Iteratively, retrospective-based, while your team/company is growing, consider what other approvals might be required and try to find common ground. For example, Jira has approval process management as well.</p><h3>How</h3><p>All good. People know what they should review and approve, where to do it, and when exactly, but how to organize the right people in the right place? The simpler system, the better, so formal approvals will be required not immediately from the beginning. When it is time to set approval rules, consider the following options:</p><ul><li><p>semi-automated approvers choice</p><ul><li><p>define <a href="https://docs.gitlab.com/ee/user/project/codeowners/">code owners</a></p></li><li><p>manually choose others who will positively impact change confidence</p></li><li><p>manual reassignment - assign a lead software engineer / qa engineer / &#8230; by default to guarantee either own review and informed choice</p></li><li><p>I&#8217;d not recommend assigning random people and explaining it in &#8220;Who&#8221; section above</p></li><li><p>you also might apply predefined approval rules, but they are less flexible than code owners</p></li></ul></li><li><p>the full intersection of expertise must cover the entire change. For example, if you had a review from QA and the security team but no other developers looked at the change - this breaks the process</p></li></ul><ul><li><p>on the first iteration</p><ul><li><p>send a message to a chat because notifications might not work as you expected for some people</p></li><li><p>grow a culture of proactive reviews</p></li></ul></li><li><p>every next iteration</p><ul><li><p>should happen until approvals obtained</p></li><li><p>use the &#8220;reviewers&#8221; section to resend for the next iteration (at least GitLab supports that)</p></li></ul></li><li><p>every chosen reviewer</p><ul><li><p>must approve</p></li><li><p>approval means that the reviewer thinks that even if you introduce another change, it doesn&#8217;t require another review (it depends on your business and the criticality of changes, so that might be replaced with the necessity of repeated review)</p></li></ul></li></ul><p>These rules might look like reviewers will be a bottleneck, so I recommend reading <em><strong><a href="https://fjtc.substack.com/p/14-the-ultimate-code-review">The Ultimate Code Review</a></strong></em> to understand how to focus code reviewers only on essential things.</p><h2>Conclusion</h2><p>The approval process setup might look boring, but it protects your business from human factors. This unnecessary moderation will slow down the process in your earliest days, so be careful and choose the implementation time. In the next issue, we will discuss The Ultimate Branching Model that will help developers collaborate efficiently and ship your product without issues. Subscribe to not miss</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mCW6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mCW6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png 424w, https://substackcdn.com/image/fetch/$s_!mCW6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png 848w, https://substackcdn.com/image/fetch/$s_!mCW6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png 1272w, https://substackcdn.com/image/fetch/$s_!mCW6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mCW6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png" width="1456" height="780" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:780,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:238497,&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_!mCW6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png 424w, https://substackcdn.com/image/fetch/$s_!mCW6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png 848w, https://substackcdn.com/image/fetch/$s_!mCW6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.png 1272w, https://substackcdn.com/image/fetch/$s_!mCW6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6103df76-bfaa-4f6d-b4d9-8ef1b0ae64e6_2154x1154.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.devtower.io/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">Thanks for reading From Junior to CTO Weekly Thoughts! Subscribe for free to receive new posts and support my work.</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 Video Of The Week</h2><p>To help you assess the complexity of zero-downtime updates, look the video (primarily the first part)</p><div id="youtube2-l7A2HyZ2Gyo" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;l7A2HyZ2Gyo&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/l7A2HyZ2Gyo?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/15-the-ultimate-approval-process?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.devtower.io/p/15-the-ultimate-approval-process?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item><item><title><![CDATA[#14: The Ultimate Code Review]]></title><description><![CDATA[From Junior to CTO Weekly Thoughts]]></description><link>https://blog.devtower.io/p/14-the-ultimate-code-review</link><guid isPermaLink="false">https://blog.devtower.io/p/14-the-ultimate-code-review</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 13 Aug 2023 13:20:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QlO8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Code Review is a vital component of professional software engineering. This practice helps to find bugs early, educate and share knowledge. <a href="https://fjtc.substack.com/p/13-the-ultimate-contribution">The Ultimate Contribution</a> we discussed in the previous issue requires <strong>The Ultimate Code Review</strong> to make the contribution successful.</p><p>Code Review might include manual practices as well as automated ones. So we will talk about both. But before we start, let&#8217;s understand our motivation to think about ultimacy.</p><blockquote><p>I provide a few examples of tools in the post, motivation is just my awareness about them and this is not sponsored. Despite of this fact analyse how suitable they are for you before using.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QlO8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QlO8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg 424w, https://substackcdn.com/image/fetch/$s_!QlO8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg 848w, https://substackcdn.com/image/fetch/$s_!QlO8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!QlO8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QlO8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg" width="1456" height="1029" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1029,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:641265,&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_!QlO8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg 424w, https://substackcdn.com/image/fetch/$s_!QlO8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg 848w, https://substackcdn.com/image/fetch/$s_!QlO8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!QlO8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b19b051-b6ab-4589-bc44-b5d6caa2a9e2_4757x3363.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><strong>Motivation</strong></h2><p>Despite the rationale behind many of our decisions in IT, we still have cargo cults for some practices. So to start here, I would suggest discussing the real quantifiable answer to &#8220;Why do we need code review at all?&#8221;.</p><p>A few factors bring motivation for code review:</p><ul><li><p>There are a few actors in code writing collaboration. Those who write some particular code, other ones who do not know anything about this code or at max partially know, those who wrote this code 6 months before, and others who will maintain this code. </p></li><li><p>Developer tenure in a company might be long, but high likely <a href="https://developerpitstop.com/how-long-do-software-engineers-stay-at-a-job/#:~:text=How%20long%20do%20software%20engineers%20stay%20at%20one%20job?">~2 years on average</a>. </p></li><li><p>Program comprehension takes about <a href="https://www.sciencedirect.com/topics/computer-science/program-comprehension">50% of developer work</a>.</p></li></ul><p>Those three factors above tell us that we must collaborate and exchange knowledge to avoid expertise loss and team performance impact on time. The more people understand a particular code, the more sustainable it is.</p><h2>Properties of The Ultimate Code Review</h2><p>The Ultimate Code Review:</p><ul><li><p>is based on <a href="https://fjtc.substack.com/p/10-the-ultimate-commit">The Ultimate Commit</a></p></li><li><p>is a part of <a href="https://fjtc.substack.com/p/13-the-ultimate-contribution">The Ultimate Contribution</a></p></li><li><p>keeps a history of communication to share knowledge</p></li><li><p>guides a reviewer</p></li><li><p>focuses on business-logic and automates other aspects of the review</p></li><li><p>maintains a culture of collaboration and learning</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>Benefits of The Ultimate Code Review</h2><p>The Ultimate Code review is a part of the Ultimate Contribution. It means that atomic commits come to the code review stage. So, one of the important benefits is the opportunity to review commits individually. Imagine you separate your feature development to feature / refactoring / ci changes. Three different commits can be reviewed separately or together depending on the size of the changed code base. That drastically simplifies the review process, but at the same time, separated commits review is an optional thing.</p><p>Another important aspect is that <a href="https://fjtc.substack.com/p/11-the-ultimate-artifact">The Ultimate Artifact</a> is built for commits in merge requests (a.k.a. pull requests). It means that reviewers see the results of <a href="https://fjtc.substack.com/p/12-the-ultimate-ci-pipeline">the Ultimate CI pipeline</a> and have a wider picture of code quality metrics. Seeing not covered code lines, a reviewer can recommend changes or detect potential bugs easier. We should remember that the presence of code coverage guarantees bug detection.</p><p>Every comment of the Ultimate Code Review is an opportunity to learn and share knowledge. The fact that we store all discussion results will help developers in many years to understand the logical path of how a particular change was introduced.</p><p>The Ultimate Code Review reduces navigation complexity and repeated activities by guiding a reviewer. So the reviewer can focus on the most important 400 LOC at a time. According to research at the end of the article, this should drastically improve the defect density rate.</p><p>The right mood in code review makes relationships in the team better and creates a space for collaboration and peer support.</p><p>Some practices that help to improve code are already automated, some of them can be automated, but others are purely manual. Let&#8217;s sort through them.</p><h2>Automated practices</h2><p>I believe Software Engineering must be more creative than routine. So we must automate all the things that we can be automated.</p><h3>Code Quality</h3><p>One of the important parts of code review that requires a ton of attention is code quality checks. Modern static code analysis tools help to understand what problems exist, let&#8217;s mention a few of them:</p><ul><li><p>Language-specific linters will check guidelines compliance, for example, ktlint will help to check kotlin best practices, yamllint will validate the same way of indentation everywhere.</p></li><li><p>Static analysis tools like SonarQube will help to detect code smells and bugs, and others like Snyk will automate static security checks against known security issues.</p></li><li><p>Test coverage tools like JaCoCo in collaboration with <a href="https://docs.gitlab.com/ee/ci/testing/test_coverage_visualization.html">Gitlab Code Coverage</a> reports (via Cobertura adapters) embedded into your Merge Requests or comprehensive tools like <a href="https://about.codecov.io/">Codecov</a> will emphasize lines that might be important to review carefully (but not necessary)</p></li><li><p>Local git hooks will format your code before committing to minimize remote code updates. Technically, it is not a part of the review process but helps to avoid misunderstanding why proper formatting was not applied</p></li></ul><h3>AI Reviewer</h3><p>I have not applied modern AI reviewers in practice yet and do not consider them a comprehensive replacement for reviewers, but at the same time, they should be great reviewer assistants. The reason is pretty simple, if you can detect a problem without human attention, do that! But you have to keep in mind two risk factors:</p><ul><li><p>the most of AI review tools are cloud-based, which means that they upload your code somewhere, sometimes, models learn from your code to provide better results, so this is a potential attack vector and security breach.</p></li><li><p>the accuracy of outcomes &lt;100% so you might see &#8220;<a href="https://en.wikipedia.org/wiki/False_positives_and_false_negatives">false positives</a>&#8221;.</p></li></ul><p>The key difference between AI analyzers and code structure analyzers is accuracy. The modern AI models cannot guarantee 100% accuracy of their outcomes but can find things that are impossible to find with old-school code structure analyzers.</p><p>I heard about <a href="https://github.com/Codium-ai/pr-agent">CodiumAI</a> and <a href="https://docs.aws.amazon.com/codeguru/latest/reviewer-ug/welcome.html">CodeGuru</a> (by AWS), it is just an example, not a recommendation, and you definitely will find more.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h3>Review Tools</h3><p>Can we send the code via email to review in the form of the archive? For sure! The key question is what is the effectiveness of this process. I saw a lot of tools that help you review your code, but the best foundation is IDE, with all the well-known tools you use for program comprehension. Fortunately, <a href="https://www.jetbrains.com/help/idea/work-with-gitlab-merge-requests.html#review-merge-request">in the latest releases</a>, Intellij IDEA team informed us about their native integration with gitlab which sounds like the first great step to simplify code review.</p><h2>Manual practices</h2><h4>Strive to follow 4 eye principle</h4><p>Even if you have all possible automation, ask someone to review your code. <a href="http://openriskmanual.org/wiki/Four_Eyes_Principle">4 eyes principle</a> comes from risk management and means any important decision must be reviewed by someone else. There are possible automations to ensure that rule, for example, Gitlab allows to set a minimal set of reviewers.</p><h4>The single reason to comment on style issues</h4><p>If you comment on things like redundant blank lines, it means that you have wrongly configured / not configured the linter. Never spend your time on such things. It is extremely inefficient. But there is an exclusion - misconfiguration. Just ask the developer to update the linter config instead of fixing every occurrence of the issue</p><h4>Choose the relevant reviewers</h4><p>There are at least three options to chose relevant reviewers</p><ul><li><p>reviewers are identified as code owners</p></li><li><p>you know that the change will implicitly impact someone</p></li><li><p>you need someone with expertise</p></li></ul><p>Code Owners can be automatically assigned according to a dedicated file in the repository (<a href="https://docs.gitlab.com/ee/user/project/codeowners/">Gitlab example</a>)</p><p>Depending on the developer's experience in the project, reviewers should be chosen by their lead engineer or by them. The less experience developer has, the more important to help to choose the right people to review.</p><h4>Resolve reviewer comments only with their permission</h4><p>Three actions that a reviewer does:</p><ul><li><p>leaves a comment</p></li><li><p>resolves their comment</p></li><li><p>approves</p></li></ul><p>Sometimes comments might not be perfect, and misunderstandings might happen. So, I&#8217;d recommend using &#8220;Approval&#8221; as a sign that the reviewer is fine with the current state and any other changes, but if a developer understands that the MR (a.k.a. PR) should be reviewed again, they should request it explicitly. If a reviewer didn&#8217;t set an approval, you might consider that the reviewer wants to double-check some changes. If comments do not require a second review and are marked as optional, the developer can mark them as &#8220;resolved&#8221; themselves.</p><p><em><strong>The Ultimate Approval Process</strong></em> is out of the scope of this post, so we discuss that topic in the next issue. Subscribe not to miss</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h4>Avoid long discussions</h4><p>Sometimes people might start debates in code review format because of different opinions. If there are no objective reasons to change code immediately, postpone the discussion, schedule a meeting, or use your tech syncups to discuss in a wider quorum.</p><h4>Focus on things that are hard to change</h4><p>Some changes are pretty cheap to introduce (like code style), and others are really hard (API with external users). If you understand that it is not too expensive to change the decision later, consider postponing the discussion if it takes too much time. Try to follow <a href="https://www.sciencedirect.com/topics/computer-science/delay-design-decision">&#8220;Delay Design Decisions until they are absolutely necessary&#8221; practice</a>. But keep in mind that some decisions are important to discuss early (for example, API design, db schema, etc.)</p><h4>Include a checklist for reviewers for routine activities</h4><p>Reviewers should not care about routine activities. Just use a checklist that defines what is important to check in the context of your project. Review documentation for libraries? Exposed interfaces? Configured authorization? All the typical things that can be met in any feature should be formulated as a checklist. This is the only thing, except for automation, that can help almost to guarantee team rules satisfaction.</p><h4>Create a template for MR description (a.k.a. PR)</h4><p>A checklist is one of the other typical things for code review, so it is useful to preconfigure a template for MR that helps fill in all the details and contains everything you prefer not to forget.</p><h4>Annotate code in places where you want to get more focus</h4><p>If a developer invites someone with specific expertise to review, they should not forget to annotate important pieces (for example, with comments) to align the focus of a reviewer.</p><h4>Breakdown and order pieces of code review</h4><p>The Ultimate Commit includes Conventional Commits that define atomic commits. This is one of the most powerful tools to make reviews simpler. Depending on code review size, a reviewer can review all commits at once or slip through refactorings, style changes, and other things that might be considered unimportant. When a reviewer has a relatively small commit to review, they might simplify it even more and follow the right order, for example, following the recommendations of a developer or common sense.</p><h4>Focus on business</h4><p>This is pretty obvious, but the reviewer has to focus on the business side of changes and help to validate that the requirements were satisfied. If not, neither API nor db schema does make sense. One of the options to validate requirements is to start with tests that assert behaviors. BDD might be valuable for such things.</p><h4>Focus on things that are hard to change</h4><p>When requirements are satisfied, you can focus on the things that are hardest to change, for example:</p><ul><li><p>Sync &amp; Async APIs</p></li><li><p>DB schema</p></li><li><p>Integrations</p></li></ul><h4>Formulate a backlog for automation</h4><p>Sometimes you detect something that might be checked automatically, but at the same time, implementation is too complex for the timings of a particular feature development. So, create a backlog for automation and solve it one by one, don&#8217;t waste your time commenting if the automation is presented in the backlog. Once the automation is implemented, all occurrences will be fixed.</p><h4>A recommendation is not a dictation</h4><p>Recommend changes, not dictate. Rules, not people, manage the best systems, so if you prefer to do something in a particular way and believe it is the best one, discuss it with the team outside the MR, and formulate rules. Otherwise, it will require explaining motivation in every new MR.</p><h4>Explain motivation</h4><p>Sometimes the motivation behind your proposal for changes might not be clear. A discipline of explanation makes your opinion argumented.</p><h4>Propose options to solve</h4><p>Suppose there are a few ways to introduce some changes. Formulate and propose them. Your comparison of variants will help a developer choose the most appropriate one or even propose a better one on top of your options. If you do not know how to improve and this requires investigation, inform the developer.</p><h4>Discussions must be recorded in the form of a comment</h4><p>Sometimes changes require verbal discussions. We usually do it in person or via tools like Zoom. Results of those discussions must be saved in text in the particular merge request to share results with others.</p><h2>Conclusion</h2><p>The described practices will help your team to reach the properties of The Ultimate Code Review. Subsequently, this will introduce the mood of a collaborative and support-focused vibe. The process will become simpler, and quality will be increased.</p><p>In the next issue, we will discuss <em><strong>The Ultimate Approval Process</strong></em> as a part of <em><strong><a href="https://fjtc.substack.com/p/13-the-ultimate-contribution">The Ultimate Contribution</a></strong></em>. Subscribe not to miss.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading From Junior to CTO Weekly Thoughts! Subscribe for free to receive new posts and support my work.</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><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UQTI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UQTI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png 424w, https://substackcdn.com/image/fetch/$s_!UQTI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png 848w, https://substackcdn.com/image/fetch/$s_!UQTI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png 1272w, https://substackcdn.com/image/fetch/$s_!UQTI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UQTI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png" width="1456" height="886" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:886,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:223702,&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_!UQTI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png 424w, https://substackcdn.com/image/fetch/$s_!UQTI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png 848w, https://substackcdn.com/image/fetch/$s_!UQTI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.png 1272w, https://substackcdn.com/image/fetch/$s_!UQTI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf06420c-e961-42e9-8f00-07a63fbd29a2_1884x1146.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></p><h2>Other useful resources</h2><p>Instead of the video of the week, I&#8217;d recommend looking at the following papers:</p><p><a href="https://www.microsoft.com/en-us/research/publication/expectations-outcomes-and-challenges-of-modern-code-review/">Expectations, Outcomes, and Challenges of Modern Code Review</a></p><p><a href="https://smartbear.com/resources/ebooks/best-kept-secrets-of-code-review/">Best Kept Secrets of Peer Code Review</a></p><p><a href="https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/">Best practices for peer code review</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/14-the-ultimate-code-review?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.devtower.io/p/14-the-ultimate-code-review?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item><item><title><![CDATA[#13: The Ultimate Contribution]]></title><description><![CDATA[From Junior to CTO Weekly Thoughts]]></description><link>https://blog.devtower.io/p/13-the-ultimate-contribution</link><guid isPermaLink="false">https://blog.devtower.io/p/13-the-ultimate-contribution</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 06 Aug 2023 13:00:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5vM4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the previous issue, we discussed how <a href="https://fjtc.substack.com/p/10-the-ultimate-commit">The Ultimate Commit</a> transformed to <a href="https://fjtc.substack.com/p/11-the-ultimate-artifact">The Ultimate Artifact</a> within <a href="https://fjtc.substack.com/p/12-the-ultimate-ci-pipeline">The Ultimate CI Process</a>. But one commit is not a feature on its own, we need to have a properly formatted branch, guarantee commit shape, etc. In this issue, I&#8217;ll cover this particular topic: how to do <strong>The Ultimate Contribution</strong>.</p><p>As before, most part of my experience is based on Gitlab, so I&#8217;ll show Gitlab-based examples, but you will probably easily find replacements for your specific scenario.</p><p>Let&#8217;s clarify what the Definitions of Done for The Ultimate Contribution are.</p><h2>Definitions of Done</h2><p>Let&#8217;s formulate rules on how <strong>The Ultimate Contribution</strong> should look like:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5vM4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5vM4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png 424w, https://substackcdn.com/image/fetch/$s_!5vM4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png 848w, https://substackcdn.com/image/fetch/$s_!5vM4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png 1272w, https://substackcdn.com/image/fetch/$s_!5vM4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5vM4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png" width="1456" height="835" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:835,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:275984,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!5vM4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png 424w, https://substackcdn.com/image/fetch/$s_!5vM4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png 848w, https://substackcdn.com/image/fetch/$s_!5vM4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.png 1272w, https://substackcdn.com/image/fetch/$s_!5vM4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe20de33-8491-4b8a-aabc-061b6ffba459_2298x1318.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></figure></div><ul><li><p>every new commit should be <em><strong>The Ultimate Commit</strong></em></p></li><li><p>every contribution made with corporate&#8217;s email (if applicable)</p></li><li><p>every new branch</p><ul><li><p>should be named after the ticket code</p></li><li><p>should be merged only with The Ultimate Merge Request (a.k.a. Pull Request)</p></li><li><p>should follow <em><strong>The Ultimate Branching Model</strong></em></p></li></ul></li><li><p>every new Merge Request</p><ul><li><p>should follow <em><strong>The Ultimate Approval Process</strong></em></p></li><li><p>should pass <em><strong>The Ultimate Code Review (we will discuss this in the next issue)</strong></em></p></li><li><p>should pass <em><strong>The Ultimate Quality Review</strong></em></p></li><li><p>should contain all relevant information</p></li><li><p>should preferably be refreshed via rebase before the merge</p></li><li><p>should be merged either with fast-forward or merge commit</p></li><li><p>as a part of a bigger feature should be merged in the right order</p></li><li><p>should trigger <em><strong>The Ultimate CI Pipeline</strong></em></p></li></ul></li><li><p>squash is prohibited with exclusions</p></li><li><p>every repo configuration should follow <em><strong>The Ultimate Repository Configuration</strong></em></p></li><li><p>every contribution policy should be documented</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><p>Rules are defined. Let&#8217;s see how to ensure compliance with them.</p><h2>Automation of DoD Compiance Check</h2><h4>every new commit should be <em><strong>The Ultimate Commit</strong></em></h4><p>In <a href="https://fjtc.substack.com/p/10-the-ultimate-commit">The Ultimate Commit</a> post, I mentioned that to guarantee The Ultimate Commit structure (especially Conventional Commits), we can use githooks. Technically, it is not a strict constraint because githook could be either disabled or occasionally not enabled. So local git hooks help avoid push errors and prevent them early but do not guarantee restriction. If we want to perform strict checks we have to enable push rules (gitlab naming). </p><blockquote><p>Currently, this functionality of Gitlab is located in Group &#8594; Repository Settings &#8594; Pre-defined push rules or Repository &#8594; Repository Settings &#8594; Push rules</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ddnH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ddnH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png 424w, https://substackcdn.com/image/fetch/$s_!ddnH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png 848w, https://substackcdn.com/image/fetch/$s_!ddnH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png 1272w, https://substackcdn.com/image/fetch/$s_!ddnH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ddnH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png" width="1456" height="177" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:177,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:69668,&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_!ddnH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png 424w, https://substackcdn.com/image/fetch/$s_!ddnH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png 848w, https://substackcdn.com/image/fetch/$s_!ddnH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png 1272w, https://substackcdn.com/image/fetch/$s_!ddnH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6bfc69b4-7afb-4668-8a7e-d7256e9e1359_1808x220.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><pre><code>Pattern:
^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)</code></pre><p>Some issues with Semantic Release require Gitlab 15.10+, but generally, this functionality helps guarantee the check.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h3>every contribution made with corporate&#8217;s email (if applicable)</h3><p>The same story as for the commit format. Sometimes people might contribute from personal email with a random name config. Eventually, git history looks like a coven of daemons but not real people. To protect your team from this kind of mistake, you can just set a pattern to allow only corporate emails</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SxB3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SxB3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png 424w, https://substackcdn.com/image/fetch/$s_!SxB3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png 848w, https://substackcdn.com/image/fetch/$s_!SxB3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png 1272w, https://substackcdn.com/image/fetch/$s_!SxB3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SxB3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png" width="1456" height="181" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:181,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:47926,&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_!SxB3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png 424w, https://substackcdn.com/image/fetch/$s_!SxB3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png 848w, https://substackcdn.com/image/fetch/$s_!SxB3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png 1272w, https://substackcdn.com/image/fetch/$s_!SxB3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eb0637e-104f-4204-b1bf-375d27031b82_1786x222.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>every new branch should be named after the ticket</h3><p>Fortunately, this part is also manageable in the same place, so if you use Jira, probably, your ticket codes look like XX-1234, it means that branches should follow the same format:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e2jX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e2jX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png 424w, https://substackcdn.com/image/fetch/$s_!e2jX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png 848w, https://substackcdn.com/image/fetch/$s_!e2jX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png 1272w, https://substackcdn.com/image/fetch/$s_!e2jX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e2jX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png" width="1456" height="184" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/29b13e3c-02c0-4590-a143-532142387369_1760x222.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:184,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:41875,&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_!e2jX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png 424w, https://substackcdn.com/image/fetch/$s_!e2jX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png 848w, https://substackcdn.com/image/fetch/$s_!e2jX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png 1272w, https://substackcdn.com/image/fetch/$s_!e2jX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29b13e3c-02c0-4590-a143-532142387369_1760x222.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><pre><code>^[A-Z]+-[0-9]+$</code></pre><h3>every new branch should be merged only with The Ultimate Merge Request (a.k.a. Pull Request)</h3><p>The Ultimate Merge Request is a regular MR that must be implemented according to the rules below but it is important that contribution never should come directly to the default branch. You could reasonably argue: &#8220;There should be exclusions when you urgently need to push a fix directly to the default branch!&#8221;. Making this constraint weaker only because once per 1-2 quarters you see a use case doesn&#8217;t make sense because, at the same time you make your pushes error-prone, and occasionally, people will push directly even if they don&#8217;t want. I&#8217;d say that the negative impact of this situation is much heavier than the profits you get making the constraint weaker.</p><h3>every new Merge Request should follow <strong>The Ultimate Approval Process</strong></h3><p>First of all, approvals must be a part of your development process. Period.</p><blockquote><p>Approvals management is located in Settings / General / Merge request approvals (Gitlab, but not available for some plans, you also might use emojis). </p></blockquote><p>Code Owners is another important practice, so you must get approval from the most experienced people in a particular module/package/file. Except for Code Owners, approvals must be obtained from the most relevant people, so the team or a developer should choose if there is uncertainty. </p><p><em><strong>The Ultimate Approval Process</strong></em> is out of the scope of this issue but will be covered soon. </p><h3>every new Merge Request should pass The Ultimate Code Review</h3><p>Code Review is a vital part of contribution quality assessment. If you compare code review with feature testing, you see that developers should help to find bugs that are harder to find from outside because other developers see how the code works. Like testing, it is easy to perform Code Review badly, focusing on the wrong things. I&#8217;m going to cover this topic in the issue the next week, so subscribe not to miss</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h3>every new Merge Request should pass <em><strong>The Ultimate Quality Review</strong></em></h3><p>Quality review is another part of quality assessment. It is a comprehensive quality check for built artifacts rather than static sources. A quality review should include a run of automated e2e testing as well as manual feature testing, security check, etc.</p><h3>every new Merge Request should contain all relevant information</h3><p>Merge Request is an important point of documented collaboration between engineers. The better Merge Request is formulated, the better collaboration becomes. If this doesn&#8217;t become overcomplicated and relevant for your process, MR should contain a copy of ticket requirements not to confuse reviewers if something is changed in Jira but not in the MR yet. MR must describe the motivation for the change (context). MR description must guide a reviewer not to miss key things and contain a checklist for routine things like &#8220;permissions for new feature are configured&#8221;, &#8220;documentation is updated&#8221;, and also playing the role of reminder for the change author. Added Code Quality metrics (absolute values &amp; diff) will help display what is going on with code quality and introduce the opportunity to configure code quality gateways. </p><p>Use templates to unify MR creation:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ebLN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ebLN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png 424w, https://substackcdn.com/image/fetch/$s_!ebLN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png 848w, https://substackcdn.com/image/fetch/$s_!ebLN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png 1272w, https://substackcdn.com/image/fetch/$s_!ebLN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ebLN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png" width="1456" height="285" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/890c354c-2dde-48bc-b758-307d199f432f_1790x350.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:285,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:88742,&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_!ebLN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png 424w, https://substackcdn.com/image/fetch/$s_!ebLN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png 848w, https://substackcdn.com/image/fetch/$s_!ebLN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png 1272w, https://substackcdn.com/image/fetch/$s_!ebLN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F890c354c-2dde-48bc-b758-307d199f432f_1790x350.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Sometimes commits in Merge Requests could be discussed on calls, but the results of discussions must be documented inside a commit message body or comments in the MR.</p><h3>every new Merge Request  should preferably be refreshed via rebase before the merge</h3><p>Before we merge changes, we have to review and test them refreshed with the latest state from the default branch. There are two most popular options: rebase and back-merge. Let&#8217;s shortly compare</p><pre><code>                        | Rebase  | Back-merge
-----------------------------------------------
Clear history           |   +     |     -
No history rewrite      |   -     |     +
Confl. resolution once  |   -     |     +</code></pre><p>Do you think the best option is obvious? Not really. Weight might differ depending on your context.</p><h4>Clear history?</h4><p>Mostly about aesthetics, but if it doesn&#8217;t require extra effort and your team enjoys it, why not prefer this way? Commit graph review use case is also an argument, but honestly, ask yourself how often you look at graph? Were you really interested in graph connections or commit order after all?  Can a simple search in the history (via IDE plugin) cover your use cases?</p><h4>No history rewrite?</h4><p>If we are talking about one developer per one feature branch - the weight here is zero, so this condition doesn&#8217;t impact because history rewrite does not introduce issues of concurrent work on the same branch. Nobody pushes changes directly to the master branch. Everyone primarily pushes changes to their feature branches.</p><h4>Conflict resolution once?</h4><p>If you rebase and more than one of your atomic commits might conflict with the target branch, that is the time to think about back-merge for this particular case.</p><p>Modern IDEs that drastically simplify the process must be used in any way.</p><h4>What approach is the best?</h4><p>You could prefer to rebase from an aesthetics and graph simplification point of view. If you see potential conflicts and back-merge will save you decades of minutes - good motivation to stop rebasing for this particular feature (branch) and start back-merging because aesthetics should not impact business.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zT5R!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zT5R!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zT5R!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zT5R!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zT5R!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zT5R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg" width="1456" height="1322" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1322,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:586277,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&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_!zT5R!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zT5R!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zT5R!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zT5R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76f42221-4e52-4f97-8f04-6fc5c2dae69a_4198x3811.jpeg 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>every new Merge Request  should be merged either with fast-forward merge or merge commit</h3><p>This is pretty clear that fast-forward merges are the ultimate way of merging. No synthetic merge commits, and absolutely clear history (only one branch, finally). But! Fast-forward merges require you to rebase history, which is a strict constraint. So, that might be the main pain point if you apply <a href="https://fjtc.substack.com/p/10-the-ultimate-commit">The Ultimate Commit</a> approach. At the same time, your team might be fine with this inconvenience. Choose either fast-forward forward merge or merge commit, get an agreement with your team, and follow only one approach, do not use two approaches simultaneously because that will confuse everyone and make your collaboration more unpredictable. </p><p>You could also apply merge commit with semi-linear history to guarantee that you merge only those changes that consider the default branch's latest state. That might work perfectly in tandem with the &#8220;approval reset on a new commit&#8221; option and approval by QA Engineer and fully automated regression testing, but you introduce more bureaucracy, and that definitely will slow down your delivery (of course, quality might keep better at the same time). Choose one depending on your particular business needs.</p><p>Do not forget to reconfigure your repositories</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5VT-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5VT-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png 424w, https://substackcdn.com/image/fetch/$s_!5VT-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png 848w, https://substackcdn.com/image/fetch/$s_!5VT-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png 1272w, https://substackcdn.com/image/fetch/$s_!5VT-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5VT-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png" width="1456" height="482" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:482,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:178119,&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_!5VT-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png 424w, https://substackcdn.com/image/fetch/$s_!5VT-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png 848w, https://substackcdn.com/image/fetch/$s_!5VT-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.png 1272w, https://substackcdn.com/image/fetch/$s_!5VT-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc62e9ee1-296b-4970-87ed-cf49606eca31_1826x604.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>every new Merge Request as a part of a bigger feature should be merged in the right order</h3><p>Sometimes features consist of more than one Merge Request, and the order might be important. For example, if you implement CD practices, you must merge the backend before the frontend that uses the backend. The backend should be delivered first.</p><p>The latest Gitlab version supports Merge Trains to automate the order of merge.</p><h3>squash is prohibited with exclusions</h3><p>In the Ultimate Contribution, squash is prohibited because your commits follow The Ultimate Commit practices, and the history is a source of extremely meaningful insides. After a while since a commit was introduced, you will review why this line looks like it is. The answer will be there.</p><p>Of course, there are no strict rules without exclusions. Dummy commits that were useful when you triggered CI especially to check that CI works fine must be squashed because they are meaningless (actually, they must be eliminated). This is relevant for feature branches that have only one responsible engineer but not for shared branches like your default one.</p><p>You also can hide &#8220;squash commits&#8221; option for MR in project settings.</p><h3>every repo configuration should follow <em><strong>The Ultimate Repository Configuration</strong></em></h3><p>The more repos you have, the more complex to manage their settings manually. Especially if someone could change and forget to return them. <em><strong>The Ultimate Repository Configuration</strong></em> is out of the scope of this issue, but I&#8217;d like to emphasize that the configuration should be synced automatically and defined in a dedicated repository.</p><h3>every contribution policy should be documented</h3><p>I&#8217;m not an expert in open source, but more than once, I saw that popular open-source projects define their policies. I apply similar practices and maintain a few internal how-tos for my team that help people to align and onboard new teammates. It is important to simplify the onboarding process, create contribution guidelines considering agreed rules, and mention automation that helps inside the document. Team changes become seamless.</p><h2>Conclusion</h2><p><strong>The Ultimate Contributions</strong> defines how to introduce new changes and not forget anything; how to form merge requests, branches, and commits.</p><p>One of the crucial parts of The Ultimate Contribution is code review. In the next issue, we will discuss <strong>The Ultimate Code Review</strong> and how to make the most of it.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bnJv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bnJv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg 424w, https://substackcdn.com/image/fetch/$s_!bnJv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg 848w, https://substackcdn.com/image/fetch/$s_!bnJv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!bnJv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bnJv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg" width="1456" height="848" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:848,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:629161,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&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_!bnJv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg 424w, https://substackcdn.com/image/fetch/$s_!bnJv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg 848w, https://substackcdn.com/image/fetch/$s_!bnJv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!bnJv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a0c5845-4b1a-493d-b9b5-3175d1900889_5239x3053.jpeg 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></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/13-the-ultimate-contribution?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.devtower.io/p/13-the-ultimate-contribution?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2>The Video Of The Week</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://youtu.be/sOaS83Ir8Ck" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rqlL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.png 424w, https://substackcdn.com/image/fetch/$s_!rqlL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.png 848w, https://substackcdn.com/image/fetch/$s_!rqlL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.png 1272w, https://substackcdn.com/image/fetch/$s_!rqlL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rqlL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.png" width="1456" height="807" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:807,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1971712,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://youtu.be/sOaS83Ir8Ck&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_!rqlL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.png 424w, https://substackcdn.com/image/fetch/$s_!rqlL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.png 848w, https://substackcdn.com/image/fetch/$s_!rqlL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.png 1272w, https://substackcdn.com/image/fetch/$s_!rqlL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09560cd7-e5ee-4111-a611-75e9201e9643_3584x1986.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>`</p>]]></content:encoded></item><item><title><![CDATA[#12: The Ultimate CI Pipeline]]></title><description><![CDATA[From Junior to CTO Weekly Thoughts]]></description><link>https://blog.devtower.io/p/12-the-ultimate-ci-pipeline</link><guid isPermaLink="false">https://blog.devtower.io/p/12-the-ultimate-ci-pipeline</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 30 Jul 2023 13:00:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!zxPH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Continuous Integration (CI) is one of the most popular concepts nowadays in software engineering. CI defines how to bring your artifacts from your sources. In this issue, I&#8217;ll explain how <a href="https://fjtc.substack.com/p/11-the-ultimate-artifact">The Ultimate Artifact</a> is created for <a href="https://fjtc.substack.com/p/10-the-ultimate-commit">The Ultimate Commit</a> through <strong>The Ultimate CI Pipeline</strong>.</p><p>My experience is primarily based on Gitlab CI, so I might miss some new useful concepts in other CI tools as well as I might use unfamiliar wording for you, but I believe the key things are 100% transferable.</p><h2>Overview</h2><p>As described in <a href="https://fjtc.substack.com/p/11-the-ultimate-artifact">The Ultimate Artifact</a> post, I distinguish 3 types of artifacts: Library, Application, and Template (if you missed that post, I strongly recommend you to review it first). They all need different types of CI pipelines. Let&#8217;s declare the critical stages of continuous integration presented for almost every type:</p><ul><li><p><strong>analyzing</strong> - check the code statically: run linters (eslint, ktlint, yamllint, etc.), run code analysis tools like sonar qube</p></li><li><p><strong>compiling</strong> - compile sources to their final form, for example, .java (source code in java) files to .class files (bytecode to run on JVM). Transpilation (source code&#8594; source code) is a form of compilation, so ts &#8594; js is here as well. Documentation generation is here as well (.adoc &#8594; .pdf).</p></li><li><p><strong>testing</strong> - test compiled code (unit and integration tests, for example, with db)</p></li><li><p><strong>building</strong> - pack compiled code (.class &#8594; .jar, .js &#8594; .tar.gz), pack documentation, etc.</p></li><li><p><strong>releasing</strong> - mark sources as &#8220;released&#8221; with a tag if the pipeline is running on the default branch, also publishes built artifacts to their artifact storage (if there is something to publish).</p></li></ul><p>The Ultimate CI Pipeline defines these stages are strongly sequential. This strictness gives you the following guarantees:</p><ul><li><p>you never compile poor quality sources accidentally because they are statically analyzed first</p></li><li><p>you never test not analyzed sources, so you don&#8217;t see not existing errors related to wrongly formatted code (for example, indentations in python)</p></li><li><p>all builds have acceptable quality (it means that if it is acceptable for development to skip tests for a particular case, the Ultimate CI Pipeline doesn&#8217;t block you)</p></li><li><p>you never make accessible (publish) artifacts that were not built because of poor quality</p></li><li><p>all your artifacts satisfy your requirements formulated with tests (if you do not manually ignore ones as an exclusion)</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D_49!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D_49!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg 424w, https://substackcdn.com/image/fetch/$s_!D_49!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg 848w, https://substackcdn.com/image/fetch/$s_!D_49!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!D_49!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D_49!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg" width="1456" height="240" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:240,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:878308,&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_!D_49!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg 424w, https://substackcdn.com/image/fetch/$s_!D_49!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg 848w, https://substackcdn.com/image/fetch/$s_!D_49!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!D_49!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c3f5992-25d5-44ef-912d-cc00b061d18a_9850x1624.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><p>Different types of artifacts have some diversities among their pipelines. Different stages might also have a variety of steps/jobs/tasks.</p><h2>Pipeline Types</h2><p>I would like to logically classify ci pipelines because even if, in general, they look similar, some details might differ. The classification is based on <a href="https://fjtc.substack.com/i/135004160/classification-of-the-ultimate-artifacts">The Ultimate Artifact classification</a> presented in the last issue.</p><h3>Template Pipeline</h3><p>This might be obvious, but templates usually do not have testing, building, publishing stages because sources provide all the needed value.  So, practically, they only need the following:</p><ul><li><p>analyzing - check that a template is following common practices, style is correct, etc.</p></li><li><p>releasing - mark a template as released (with tag)</p></li></ul><p>In some cases, if it is necessary from a delivery perspective, the template might be packed, for example, to a tarball (in the building stage) and delivered to template storage (as an extended &#8220;releasing&#8221; stage). For such cases, it is better to consider the library pipeline.</p><p>Another example - Gitlab CI templates. They don&#8217;t need to be published somewhere; only tagging is needed to point to a predictable template state.</p><p>The notification about the newly released template version might be sent on releasing stage as an extra step.</p><h3>Library Pipeline</h3><p>The library pipeline fully leverages described pipeline stages. If many libraries are built in a mono repo, they all might be published. Let&#8217;s review the stages from the Library Pipeline perspective. </p><p>All the stages described above are relevant, but what is important: here, we have to consider where to publish the artifacts. It often makes sense to separate production and development storages. For example, Maven separates release repositories (static artifact versions for production) and snapshot repositories (dynamic &amp; overridable versions for development).</p><p>Another important point is that sometimes, we cannot assign aliases to libraries (technical constraint). We expect the library to be republished with the release version even if the code is unchanged.</p><h3>Application Pipeline</h3><p>The application pipeline does also require all stages. We also should analyze sources, compile them. For interpreted language, this step is not necessary, but some sources might be used for code generation. For example, request handler stubs might be generated from API schemas. Testing might include integration testing because apps might have connections with other components, unlike most libraries. </p><p>Building depends on the option of how the app will launch. If this is an old-fashioned application server, the building might look like Library. If it is an Android mobile app, you build apk file. If the app will run on OS you build native binaries. But if we are talking about modern could native development, we build docker containers, and packaging is not just packing compiled sources to a form of archive, it is about layered image building, optimized by layer change frequency (though this is a matter of another post).</p><p>In the perfect world, I&#8217;d say that we should be able to create aliases for any kind of artifacts, but the most advanced approach here is to use docker tags. We mark sources on the release stage that triggers artifact building that will help access and identify the artifact. <a href="https://fjtc.substack.com/p/11-the-ultimate-artifact">This Ultimate Artifact</a> should be additionally tagged with the version that docker does seamlessly.</p><p>The most important difference here in respect to libraries is that a successfully finished CI process should do something to motivate CD to do its work. For example, the final CI step might be to update the app's current version in the repo responsible for the integration environment.</p><h2>Considerations about Stages</h2><h4>Analyzing</h4><p>Analysis helps you to identify source issues early. Because The Ultimate Commit motivates you to commit smaller logical pieces, it becomes hard to go too far from project conventions.</p><p>Security scanners are also a part of the analysis step, so you can block any pipeline with potential security issues if you desire. </p><p><a href="https://fjtc.substack.com/p/10-the-ultimate-commit">The Ultimate Commits</a> are already published at this stage, so it is relatively late to validate how they formed. I will describe how to establish The Ultimate Contribution in the next issue. Subscribe not to miss.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h4>Compiling</h4><p>It only makes sense to separate compilation if your build system supports output caching. It means that if you can run compilation and, after that, separately run tests without recompilation, the separated compilation (as an individual step) works.</p><h4>Testing</h4><p>Should we be able to disable this stage for the sake of development speed? In the perfect world - we shouldn&#8217;t, but the reality is not perfect. <em><strong>The Ultimate Development Experience</strong></em> is another topic but briefly. Testing is crucial, the longer we don&#8217;t have testing, the more unpredictable quality we have. If we are completely sure in every commit we minimize our stress. Why do we want to disable tests? The single reason I can imagine to make deployment in development faster and avoid test fixes until the end of the feature development. We might exchange better quality for development/maintenance experience, but testing &amp; security will be impacted. I think it is better to look at solutions that just improve development experience. For cloud-native apps, you can consider the following options: local deployments, <a href="https://skaffold.dev/">scaffold</a>, <a href="https://www.telepresence.io/">telepresence</a>.</p><h4>Building</h4><p>Here we have a similar story as for the compiling stage. We must reuse the results of the previous stages to pack in the form of artifact(s). Building performance might usually be improved with different caching strategies. We pack what we already compiled, if we properly slice docker images we might reuse layers with your framework and library. We might pack only changed parts of compiled code (relevant for monorepos, but I&#8217;m not a big fan of ones for microservices)</p><h4>Releasing</h4><p>Depending on a pipeline type Releasing might include both publishing and tagging or only tagging. The same story for notification. For example, if you want to release gitlab ci template, you don&#8217;t need to publish anything but rather only tag sources.</p><p>Auto-tagging with a version is another interesting advantage of <em><strong>The Ultimate CI Pipeline</strong></em>. Because The Ultimate Commit is a foundation for the pipeline, we could compute the next artifact version from git history. For example, tools like <a href="https://github.com/semantic-release/semantic-release">Semantic Release</a>. and <a href="https://github.com/commitizen/cz-cli">Commitizen</a> will help you to compute the next version and publish it to your VCS server in the form of a tag or updated file. Let me briefly explain how it works:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zxPH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zxPH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zxPH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zxPH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zxPH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zxPH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg" width="1456" height="1263" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/befb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1263,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:519544,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&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_!zxPH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zxPH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zxPH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zxPH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbefb98a6-05e0-4557-93dc-f992d6f43ee5_4294x3725.jpeg 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>Conclusion</h2><p>The Ultimate CI Pipeline defines how to transform <a href="https://fjtc.substack.com/p/10-the-ultimate-commit">The Ultimate Commit</a> to <a href="https://fjtc.substack.com/p/11-the-ultimate-artifact">The Ultimate Artifact</a>, at the same time, they are prerequisites for The Ultimate CI Pipeline. The unified approach with some benefits helps you to not care about CI at all. It is important to answer on the question: How to guarantee compliance with conventions  on <em><strong>The Ultimate Commits</strong></em> because otherwise auto-versioning won&#8217;t work? </p><p>In the next issue, we define how to make <strong>The Ultimate Contribution</strong>, which includes <strong>The Ultimate Branch</strong>, <strong>The Ultimate Merge Request</strong> and <strong>The Ultimate Commit Push</strong> that help ensure conventions compliance. Subscribe not to miss</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>The Video of The Week</h2><div id="youtube2-OcaUQrRo7-Q" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;OcaUQrRo7-Q&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/OcaUQrRo7-Q?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/12-the-ultimate-ci-pipeline?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">Thanks for reading <strong>From Junior to CTO Weekly Thoughts</strong>! Share with your colleagues</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/12-the-ultimate-ci-pipeline?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.devtower.io/p/12-the-ultimate-ci-pipeline?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div>]]></content:encoded></item><item><title><![CDATA[#11: The Ultimate Artifact]]></title><description><![CDATA[From Junior to CTO Weekly Thoughts]]></description><link>https://blog.devtower.io/p/11-the-ultimate-artifact</link><guid isPermaLink="false">https://blog.devtower.io/p/11-the-ultimate-artifact</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 23 Jul 2023 13:01:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Oa0V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em><strong>The Ultimate Commit</strong></em>, which I described in <a href="https://fjtc.substack.com/p/10-the-ultimate-commit">the previous issue</a>, defines how to make meaningful commits that drastically improve your automation, code review, and program comprehension. A commit by its nature is just a static and identifiable representation of sources: code, API schema, and configuration files. We usually do not use sources as runnable items, to become runnable they need at least resolved and loaded dependencies, but in favor of reusability, we prefer to store only pointers to dependencies among sources (gradle files, requirement.txt, package.json, etc.). We pack artifacts that either contain dependencies or expect that they are provided. An artifact can be used simply without awareness of development specifics, but at the same time it represents the logic we describe in sources. In this weekly issue, we discuss the perfect one - <strong>The Ultimate Artifact</strong>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><p>The same as for <em><strong>The Ultimate Commit</strong></em> all my practice is based on Git as the most popular VCS, but if you do not use Git but understand how to map Git practices to your VCS, the issue might be valuable for you as well.</p><h3>Classification of The Ultimate Artifacts</h3><p>Unfortunately, we cannot define a single artifact type by saying, &#8220;Docker image is the single thing you need in any scenario,&#8221; so let&#8217;s classify artifacts first. That might be obvious, but we have to align here.</p><h4>Library</h4><p>The main motivation for this kind of artifact is to provide out-of-the-box logic for other artifacts.</p><p>The key properties:</p><ul><li><p>not executable - we cannot execute provided logic without calling code</p></li><li><p>reusable in other artifacts - there should be a way to include provided logic to another artifact</p></li></ul><p>Examples: </p><ul><li><p>.jar file</p></li><li><p>npm package</p></li><li><p>DLL file</p></li></ul><h4>Application</h4><p>Application as a term might have different meanings in different contexts. In the context of this article, we are talking about a single executable that might run as a part of a distributed system or be self-sufficient.</p><p>The topic of Application typology (wider meaning) is out of the scope of this article. I will cover this in one of the next issues. Subscribe not to miss.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><p>The key properties:</p><ul><li><p>executable - can be directly executed</p></li><li><p>might be reusable as a part of a bigger distributed system</p></li><li><p>has a single entry point or convention how to run</p></li></ul><p>Examples:</p><ul><li><p>a docker image</p></li><li><p>.jar file</p></li><li><p>.war file</p></li><li><p>grep</p></li></ul><h4>Templates</h4><p>Templates look similar to libraries, but the key difference is that users fully control them. Everyone can potentially override any piece of provided logic. Because of that property, they are distributed in the form of sources.</p><p>The key properties:</p><ul><li><p>not executable - you could create an application from a template and execute but it is impossible to execute a template directly</p></li><li><p>overridable - any piece of a template can be modified</p></li><li><p>a form of sources - usually, we can use source form only to communicate with a template user in the same language</p></li><li><p>reusable in other artifacts - the same template helps to create different artifacts</p></li><li><p>depending on implementation, it removes boilerplate or at least simplifies its creation</p></li><li><p>the way of implementation defines how complex refreshing will be</p></li></ul><p>Examples:</p><ul><li><p>website templates</p></li><li><p>CI/CD templates</p></li></ul><p>We classified artifacts, so let&#8217;s keep this in mind and proceed with the properties of the Ultimate Artifact. The first one is <strong>the</strong> <strong>Single Kind.</strong></p><h3>Properties of the Ultimate Artifact</h3><h4>The Single Kind, The Single Use Case</h4><p>The Ultimate Artifact will never mix more than one kind (Library/Application/Template). Even if it looks useful because we have one executable to run a few different things, do not mix them. Even if we ignore the fact that this approach breaks the single responsibility principle, it introduces a big confusion for a user who has a particular use case to cover. The fact that a user gets a new entry point without awareness might introduce new problems and implicitly increases the attack surface.</p><h4>Identifiable</h4><p>The Ultimate Artifact is based on The Ultimate Commit. Any Ultimate Commit might produce zero or more artifacts for different reasons:</p><ul><li><p>an artifact was not provided because logic was not changed, for example, documentation was updated only</p></li><li><p>provided separated kinds of artifacts from the same code base (API schema + server app; a few apps in monorepo)</p></li></ul><p>So we can say that desired artifact&#8217;s name, in conjunction with commit&#8217;s hash should uniquely identify the artifact (being primary identification) among others provided from the same source repository. Commit&#8217;s hash only is not enough because of potential collisions globally as well as non-unified behavior with monorepos. To provide globally unique identification, the ultimate artifact has a group name (aka namespace) at the beginning to distinguish a company or a project in the company.</p><p>This is also important to mention that a branch name of sources is not a part of primary identification as well as tags because a few branches and tags might point to the same commit, so it doesn&#8217;t make sense to choose &#8220;the best pointer&#8221;.</p><h4>Searchable</h4><p>Primary identification is not an exclusive option to search for an artifact in the artifact registry. The Ultimate Artifact uses the branch name to point to the latest artifact built on the branch. For example, if a branch name equals a feature ticket code, that helps to find the most recent changes in the development of a particular feature. This also works for a few components under development simultaneously. For example, the statement &#8220;Components A, B and C are impacted in feature XX-1234&#8221; means that to see the latest changes before release you should just deploy A, B, C components with tag XX-1234. Some artifacts support multi-tags (<a href="https://docs.docker.com/engine/reference/commandline/tag/">docker</a>), for others, only limited flexibility is available (<a href="https://maven.apache.org/guides/getting-started/index.html#what-is-a-snapshot-version">maven</a>).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Oa0V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Oa0V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png 424w, https://substackcdn.com/image/fetch/$s_!Oa0V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png 848w, https://substackcdn.com/image/fetch/$s_!Oa0V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png 1272w, https://substackcdn.com/image/fetch/$s_!Oa0V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Oa0V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png" width="1456" height="538" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:538,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:243928,&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_!Oa0V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png 424w, https://substackcdn.com/image/fetch/$s_!Oa0V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png 848w, https://substackcdn.com/image/fetch/$s_!Oa0V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.png 1272w, https://substackcdn.com/image/fetch/$s_!Oa0V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe27dffa0-73db-46c5-905f-e2c709f42c30_2688x994.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>One of the options to improve searchability is to tag commits that originated a particular artifact with environment type (production / staging) to speed up the hotfix procedure and find what exactly the state of code should be changed. This point will be covered in detail when we will discuss <em><strong>The Ultimate CD Process</strong></em>.</p><p>Searchability goes hand in hand with versioning because an artifact version is one of the options to search.</p><h4>Versionizable</h4><p>Identification is not versioning. Versioning helps to identify a particular artifact. All artifacts are identifiable but not all are versioned. For example, there are artifacts that are created during development, they require primary identification and searchability but not a real version.</p><p><a href="https://semver.org/">Semver</a> is the primary option to version The Ultimate Artifact. The importance of Semver for libraries is difficult to overestimate. Probably all users of libraries would like to know will library updates break something or only introduce new features/fixes.</p><p>Some types of artifacts (like maven) have versioning as a primary option to identify artifacts because tagging is not available. The limitation of this approach is that it is impossible to take an artifact for any commit on a feature branch, and versioning of merged changes is the single option, so you cannot choose not to version a commit.</p><p>Auto-versioning is available for The Ultimate Artifact, thanks to The Ultimate Commits. I will cover that topic in the next issue, where we will talk about <em><strong>The Ultimate CI Pipeline</strong></em>. Subscribe not to miss.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h4>Idempotent</h4><p>The same sources should not provide a new artifact. If we built a commit on a default branch and added a new tag, we should not rebuild a new artifact for the new tag. Rather, we should add a new pointer to the already-known artifact. This is one of the important motivation points to use hash-based identification in general - to not generate new artifacts for the same commit.</p><p>This also means that if you use fast-forward (FF) merge and nobody introduced changes to the default branch before you tested an artifact, you will get exactly the same one in production.</p><h4>Configurable</h4><p>The Ultimate Artifact should be configurable according to artifact usage via command line attributes / environment variables / configuration files. The Ultimate Artifacts should be ready for the fact that configuration changes in time, so if the Ultimate Artifact&#8217;s startup time is too long for some reason, the artifact should be ready to refresh values in runtime (if acceptable). Command line attributes might be used to emphasize that the value can be updated only with a restart. At the same time, it doesn&#8217;t mean that env variables cannot have immutable values.</p><h4>Environment type-independent</h4><p>The Ultimate Artifact is not relying on the environment type (production / staging / etc.). If variables should have different values depending on an environment type, this part of the configuration should be moved outside of The Ultimate Artifact.</p><h4>Deployment-independent</h4><p>The Ultimate Artifact doesn&#8217;t contain information on how to deploy the artifact. Otherwise, deployment changes will impact the artifact&#8217;s version what does not have any sense and negatively impacts the separation of concerns.</p><h4>Reusable (even partially)</h4><p>The Ultimate Artifact defines the requirements to launch/use. If requirements are satisfied, the artifact can be reused. The fewer requirements that need to satisfy, the more reusable the artifact will be.</p><p>This is important to mention that some artifacts might support partial re-usage, for example, layers in docker assist you in sorting your code in the order of increasing change probability: framework &#8594; dependencies &#8594; custom code. That allows not to update and reuse the first two layers if only custom code were updated.</p><h4>Integratable</h4><p>The Ultimate Artifact must provide UI (incl. CLI) / API or both. It is possible either to integrate seamlessly into a business process as a tool or provide a clean, standardized API that follows one consistent approach and is user-centric. The topic of <em><strong>The Ultimate API</strong></em> is out of the scope here but probably can be covered later.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h4>Static</h4><p>Versioned artifacts cannot be changed. But non-version tags can be moved. For example, if we tagged an artifact with a branch name as the latest one, a new commit to the same branch moves the tag, which should override the artifact.</p><h4>Secure</h4><p>Before The Ultimate Artifact can be used, we must perform at least a security check which confirms the artifact doesn&#8217;t have obvious leaks. Security scanners like <a href="https://snyk.io/">Snyk</a> are helpful for that purpose.</p><p>That is probably obvious but I have to mention that to guarantee that the Ultimate Artifact is the same as released, we have to sign it (<a href="https://docs.gradle.org/current/userguide/publishing_signing.html">an example for gradle</a>).</p><h4>Stack-agnostic</h4><p>The artifact is an out-of-the-box solution that you need to configure and launch. The less external awareness about the stack you have, the less attack surface you make, and readiness for evolution is practiced. This is not a strict rule but rather a recommendation.</p><p>Here are my considerations regarding the Ultimate Artifact. In the next issue, we will discuss <em><strong>The Ultimate CI Pipeline</strong></em>, an automation process that will help you convert The Ultimate Commit to The Ultimate Artifact.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/11-the-ultimate-artifact?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">Thanks for reading <strong>From Junior to CTO Weekly Thoughts</strong>! Share with your colleagues</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/p/11-the-ultimate-artifact?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.devtower.io/p/11-the-ultimate-artifact?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><h2>Video of The Week</h2><div id="youtube2-8vXoMqWgbQQ" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;8vXoMqWgbQQ&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/8vXoMqWgbQQ?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[#10: The Ultimate Commit]]></title><description><![CDATA[From Junior to CTO Weekly Thoughts]]></description><link>https://blog.devtower.io/p/10-the-ultimate-commit</link><guid isPermaLink="false">https://blog.devtower.io/p/10-the-ultimate-commit</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 16 Jul 2023 13:01:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Too_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Developers around the world commit changes every day. Does that mean this small part of every development process might have a big impact? Make history cleaner, auto-version artifacts, and simplify code reviews of complex features? In this issue, I will collect principles behind the ultimate commit to help you improve your development process and drastically reduce the complexity of collaborative development. Different version control systems exist, but these thoughts are git-based and not validated against other VCSs.</p><h2>Motivation</h2><p>It must benefit us if we apply some effort to make something perfect. If we improve our approach to commit, we must utilize these results. Otherwise, it doesn&#8217;t make sense. What utility might we achieve?</p><h4>Simplified Code Review</h4><p>Program comprehension takes <a href="https://www.researchgate.net/publication/318811113_Measuring_Program_Comprehension_A_Large-Scale_Field_Study_with_Professionals">at least half of work time</a>. Will developers be happier and more productive if code review might pass faster and smoother? We could add a bit more effort on every commit instead of huge efforts on code review. Eventually, the code reviewer doesn&#8217;t get hurt by this routine activity and keeps being motivated.</p><h4>More Practical Code Review</h4><p>Some well-known research papers say that after 200-400 LOC bug detection density is decreasing dramatically. At the same time, keeping features within such a hard limit is impossible. There should be something more atomic. Randomly reviewed files without a limited scope, mixed refactorings, and feature code might make your code review useless. A more structured approach makes the reviewer more attentive, which helps to find more problems early and saves the team&#8217;s time in total.</p><h4>Change History Analysis</h4><p>Code must be self-documented with clear variable names that explain what is inside and accurate method names that do not force you to look inside because it is obvious from the method name. That still makes sense to write comments for not obvious fixes that should not be occasionally reverted, for example, explicitly redefined transitive dependency version. But sometimes, we do not understand why some code was written in a particular way instead of an alternative one, we open history and see&#8230; nothing. The only &#8220;code review fix&#8221; or squashed &#8220;XX-1234 My amazing feature&#8221; ticket name in summary. History doesn&#8217;t really help developers to maintain existing code and this might be improved. The Ultimate Commit should give you more context of every particular change, simplify long-term work, help you in 6 months to return, and introduce some changes with minimal side-effects of missed memory pieces.</p><h4>Inferred Versioning &amp; Change Notes </h4><p>The meaning of every change must impact, this is a consistent log of code mutations that should help you to automate versioning. Because a set of commits is a set of changes, we might leverage it. I don&#8217;t call it &#8220;Release Notes&#8221; but rather &#8220;Change Notes&#8221; because developers help themself when they write commit messages, they don&#8217;t think about an end user who might read notes inferred from commits, but at the same time, other developers might be interested in what happened.</p><p>We clarified what might be improved with &#8220;the Ultimate Commit&#8221; so let&#8217;s try to make obvious properties of one.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>Critical Properties of the Ultimate Commit</h2><h4>Small</h4><p>Keeping complex structures in mind during code review and history analysis is challenging. Small limited changes are much simpler to understand. Just imagine that you review refactoring results and business code separately. Eventually, it is the same code but reviewing pieces separately, you can quickly look through refactorings or style changes and deeply review business ones that will impact your ability as a reviewer to focus on things that matter and keep high bug detection density.</p><h4>Readable</h4><p>This is obvious nowadays, but I must mention that the readability of commit messages directly impacts history analysis and program comprehension activities. If you save 1 minute instead of properly formulating a commit message today, this will chase you while the entire project lifetime until you leave the company.</p><h4>Expressive</h4><p>I often saw commits with the summary like &#8220;fix code review comments&#8221;, sometimes even repeated many times. These commits have meaningless summary because they do not explain why (even what) changes were introduced. You might object to me: but changes were introduced because the code reviewer added a comment. This is one of the most popular mistakes I&#8217;ve seen. Code Review is a tool for feedback but not a cause. The key task you solve on code review is highlighting different issues. Emphasize issues early to fix them before the root cause is merged. Expressive commit messages help you to formulate and check that you properly understand the motivation behind the comment. Is this just a style issue or a performance bug?</p><h4>Normalized</h4><p>There is no need to duplicate information. A summary of the Ultimate Commit should give you more information than you read from the inside code. For example, &#8220;add if statement&#8221; repeats the content but &#8220;handle a corner case&#8221; explains why these changes are needed.</p><h4>Structured</h4><p>There might be a few types of logical changes, so if we define the domain model, we could build automation for versioning, for example:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Too_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Too_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png 424w, https://substackcdn.com/image/fetch/$s_!Too_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png 848w, https://substackcdn.com/image/fetch/$s_!Too_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png 1272w, https://substackcdn.com/image/fetch/$s_!Too_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Too_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png" width="1456" height="1007" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0deb5324-96a2-491c-9173-285981586093_1990x1376.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1007,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:185174,&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_!Too_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png 424w, https://substackcdn.com/image/fetch/$s_!Too_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png 848w, https://substackcdn.com/image/fetch/$s_!Too_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.png 1272w, https://substackcdn.com/image/fetch/$s_!Too_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0deb5324-96a2-491c-9173-285981586093_1990x1376.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><h4>Completed</h4><p>Committing does not correlate with time, there is no sense to commit every hour or by the end of the day. At the same time, if a change takes more time than your development session or consists of a few changes, you could definitely decompose it. For example, &#8220;introduce REST API with stubs under the hood&#8221;, &#8220;improve resilience with retries for network calls&#8221;.</p><h4>Unified</h4><p>This might be inefficient to scan some changes by eyes formulated in a passive voice, and others in an active one. Some have information about the initial branch/task, others do not, or this information is added differently.</p><p>There should be one standard for every particular commit.</p><p>Small, Readable, Expressive, Normalized, Structured, Completed, and Unified. WOW! A lot of properties to satisfy, some of them fully on developer&#8217;s shoulders, but others might be controlled independently.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><h2>Practices</h2><h4>Conventional Commits</h4><p>I hope that some of you who already aware of Conventional Commits are recognized that this specification covers the major part of the Ultimate Commit properties. For others, let me explain <a href="https://www.conventionalcommits.org/en/v1.0.0/">what it is</a>.</p><p>According to the site:</p><blockquote><p>The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of. This convention dovetails with <strong><a href="http://semver.org/">SemVer</a></strong>, by describing the features, fixes, and breaking changes made in commit messages.</p></blockquote><p>If a team follows the convention, their commits get the following properties of the Ultimate Commit: small (atomic), structured, completed, and partially unified. Conventional Commits propose many standard types of commits, such as: feat, fix, chore, refactor, docs, style, test, perf (performance), ci, build, revert.</p><h4>Active voice</h4><p>Usually, there is an intention to write a commit summary in a passive voice, for example, &#8220;user API was introduced&#8221;. The problem with this approach is that passive voice is more complex to read because verbs might drastically change from their infinitive form; otherwise, the infinitive form in the present tense makes it simpler. Another motivation is that commit messages will be unified with Merge commits which start from &#8220;Merge &#8230;&#8221;</p><p>This practice helps to unify and improve the readability of commits.</p><h4>Stop squashing</h4><p>If you start with conventional commits, you must stop squashing of your commits. Now your history has been filled with information you might use, do not lose it.</p><p>Commits in history become readable and expressive. They are small, unified, and structured so you can easily understand why some changes were introduced.</p><h4>A branch name is a ticket code and placed commit message&#8217;s footer</h4><p>Identifying branches via ticket code makes everything simpler. First of all, you don&#8217;t need to think about the branch name at all. Secondly, you might add a branch name to the footer of a conventional commit, and if later you want to find all commits related to ticket XYZ-1234 you just search this code in the git history. If the branch were named after the ticket, you would save a lot of time.</p><p>It is obvious if you wanted to have exclusions from this rule, sometimes you can but keep in mind that it breaks your development traceability.</p><p>What is the best? Branch name addition is easy to automate but amend commits might be tricky.</p><h4>&#8220;Why&#8221; instead of &#8220;What&#8221;</h4><p>Your commit diff already explains what was changed. You could add more information with your commit message to explain &#8220;why&#8221;. Use commit history as a chat for communication with new developers who do not understand why a particular line was added so they will read it and not bother you repeatedly. I gave a few examples above.</p><h2>Tools</h2><h4>Creation</h4><p>IDE plugins and command line tools might help you to structurize your messages according to specifications.</p><p>Git Hooks might add a branch name to the end of every commit. There are several ways to implement git hooks, from manual git config update to build system plugin usage (<a href="https://plugins.gradle.org/search?term=git+hooks">example for gradle</a>, <a href="https://github.com/typicode/husky">example for frontend guys</a>).</p><h4>Validation</h4><p>IDE plugins also might help you to validate your commit messages.</p><p>Git Hooks can help to test commit messages against specifications and other requirements.</p><p>Git Server Hooks help to protect from occasionally violated rules.</p><h4>Version Generation</h4><p>Semantic Release is a great tool to compute the next semantic version of your artifact and publish it to git server. Commitizen is also a popular one.</p><p>The most part of conventional commit-based tools is mentioned <a href="https://www.conventionalcommits.org/en/about/#tooling-for-conventional-commits">here</a>.</p><h2>Conclusion</h2><p>The Ultimate Commits are not perfect because they require some effort, but eventually, you improve your code review, code comprehension, and, I&#8217;m not afraid to say, the culture of your development.</p><p>In one week, we will talk about &#8220;The Ultimate Artifact&#8221;, subscribe not to miss it!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading <strong>From Junior to CTO Weekly Thoughts</strong>! Subscribe to receive new posts every week.</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 Video Of The Week</h2><div id="youtube2-az-MX_M11lg" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;az-MX_M11lg&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/az-MX_M11lg?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[#9: Returning from the Cloud via Local-First Approach]]></title><description><![CDATA[From Junior to CTO Weekly Thoughts]]></description><link>https://blog.devtower.io/p/9-returning-from-the-cloud-via-local</link><guid isPermaLink="false">https://blog.devtower.io/p/9-returning-from-the-cloud-via-local</guid><dc:creator><![CDATA[Ivan Osipov]]></dc:creator><pubDate>Sun, 09 Jul 2023 13:00:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!hCM1!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23b6de6-1727-4c91-8e64-18bf186739d7_178x178.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In prehistoric times (before Clouds), people in IT interacted via whiteboards, files stored locally, and data exchanged via USB flash drives. Online collaboration is a vital component of modern business, I remember how I postponed some discussions until I returned to the office ONLY because that was not comfortable to brainstorm online. Another important aspect was ownership, you owned your files on your machine. In this issue, we will talk about local-first software, the thing that keeps collaboration and data ownership at the same time. </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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.devtower.io/subscribe?"><span>Subscribe now</span></a></p><p>Let me give you a few examples of software that we use nowadays to make online collaboration smoother.</p><ul><li><p><strong>Code with me</strong> (by Jetbrains) helps people write code together before something is committed.</p></li><li><p><strong>Figma</strong> helps designers collaborate with other designers or even developers.</p></li><li><p><strong>Miro</strong> helps to draw flow charts and even more.</p></li><li><p><strong>Jira</strong> by Atlassian nowadays are trying to build a better collaboration experience inside Agile Poker.</p></li><li><p><strong>Google Docs</strong> is a standard way to create documents, including sheets and presentations.</p></li></ul><p>Some of these guys are designed for collaboration. Others are trying to extend the experience. Cloud-based tooling is available, so what is wrong?</p><p>Another important aspect is the feeling of digital ownership that was available until we all worked locally, so work was not collaborative, but we managed ownership of our data. A document on my HDD, an exported file of my project from any tool installed on my computer, I was feeling ownership of these things.</p><p><a href="https://www.inkandswitch.com/local-first/">Local-first </a>software helps you keep both: ownership and opportunities for collaboration. There are a few principles behind local-first software:</p><ul><li><p>No spinners: your work at your fingertips (local data is primary, cloud data is secondary)</p></li><li><p>Your work is not trapped on one device (data should be synced across all devices)</p></li><li><p>The network is optional (use whenever you want)</p></li><li><p>Seamless collaboration with your colleagues</p></li><li><p>The Long Now (access the data for a long time in the future)</p></li><li><p>Security and privacy by default (you own your data, a server holds only encrypted data)</p></li><li><p>You retain ultimate ownership and control (backups on your shoulders)</p></li></ul><h3>Conclusion</h3><p>As usual, there is no silver bullet. We should find the best tool for a particular task every time. Local-first software is not a typical way to implement something with its benefits and challenges. From my perspective, this approach is feasible in private areas (not business ones) because, eventually, a company owns data but not employees.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.devtower.io/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">Thanks for reading <strong>From Junior to CTO Weekly Thoughts</strong>! Subscribe for FREE to receive new posts every week.</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>