<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Pavel Fokin on Medium]]></title>
        <description><![CDATA[Stories by Pavel Fokin on Medium]]></description>
        <link>https://medium.com/@pavelfokin?source=rss-9fdf1cfd850------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*orvPJloY7BeFGFCPUKC_Ww@2x.jpeg</url>
            <title>Stories by Pavel Fokin on Medium</title>
            <link>https://medium.com/@pavelfokin?source=rss-9fdf1cfd850------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 19:46:11 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@pavelfokin/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[The four constraints of the engineering mind]]></title>
            <link>https://medium.com/@pavelfokin/the-four-constraints-of-the-engineering-mind-6c47a1a274d0?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/6c47a1a274d0</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[psychology]]></category>
            <category><![CDATA[leadership]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Thu, 16 Apr 2026 00:00:30 GMT</pubDate>
            <atom:updated>2026-04-21T09:53:55.709Z</atom:updated>
            <content:encoded><![CDATA[<h4>Cognitive-First Engineering</h4><h4>Three constraints inside one mind. One between minds.</h4><figure><img alt="A yellowed index card with a typewritten pre-flight checklist rests on a dark wooden surface." src="https://cdn-images-1.medium.com/max/1024/1*ygR_LpI95U1T7IgcjEkUGQ.jpeg" /><figcaption><em>The checklist pilots invented after the 1935 Boeing Model 299 crash. One index card that offloaded memory, enforced sequence, and carried knowledge from one cockpit to the next.</em></figcaption></figure><p>On October 30, 1935, Boeing’s Model 299 crashed on a test flight. It was the most advanced bomber at the time. And it wasn’t a mechanical failure.</p><p>Ployer Peter Hill was the pilot. He had tested nearly every military aircraft of the era as the Army’s chief of flight testing.</p><p>The investigation found nothing wrong with the aircraft. It was Hill’s first flight on this machine, and he had forgotten to release a mechanism that secured the elevator and rudder controls while the plane was parked. One step, missed in a sequence of more than thirty.</p><p>The press called the Model 299 “too much airplane for one man to fly.”</p><p>The Army gave the contract to Douglas. Boeing nearly went bankrupt.</p><h3>The mind behind every system</h3><p>Human inventions have come a long way. But every system we build still depends on the same instrument. A brain that has not changed in tens of thousands of years.</p><p>The human mind is powerful, but constrained. It has a narrow window of active focus. It handles complex work mostly in sequence. It loses what it does not revisit. And when understanding moves between people, it is not copied intact. It is reconstructed.</p><p>These are structural properties of human cognition.</p><p>Over the past century, cognitive psychology has studied these properties with increasing precision. The following four constraints are my attempt to distill that research into a minimal and orthogonal set.</p><p>Three describe the limits of a single mind. The fourth describes what happens at the boundary between minds.</p><h3>1. Cognitive capacity is structurally bounded</h3><p>Your mind can hold a small number of items in active focus. The exact number depends on conditions and on what counts as an “item”, but the constraint is stable. Cognitive capacity is narrow. And it does not double because the person is senior. [1]</p><p>Experience helps, but not by removing the limit. It helps by compressing more into each slot.</p><p>A junior developer sees 50 lines of code. A senior developer recognizes a Circuit Break pattern. An architect sees an availability constraint. A CTO sees a team that reliably handles incidents.</p><p>We compress the meaning of many details into a single object that lets us understand, predict and act. The capacity does not change. What fits inside does.</p><p>Cognitive capacity matters because many engineering failures happen not when a person knows nothing, but when too many things must be held in mind at once.</p><p>A service looks manageable until a deployment depends on one feature flag, two downstream consumers, a migration path, and an undocumented operational exception.</p><p>A planning session looks straightforward until the team must juggle business intent, technical debt, ownership boundaries, and half-resolved decisions from last week.</p><p>At that point, the problem is not intelligence. The system has exceeded cognitive capacity.</p><h3>2. Cognitive processing is serial and consumes energy</h3><p>Human reasoning is not a wide parallel pipeline.</p><p>You don’t process a complex procedure in parallel. You inspect one assumption, then the next. You trace one dependency, then another. You compare two interpretations of a requirement. Even when several thoughts feel present at once, careful reasoning still has to move through them in sequence.</p><p>That sequence is fragile.</p><p>Interruptions do not simply pause thought. They break its continuity. The person loses the place. The question is no longer only “what was I doing?” but “where in the reasoning was I?” Rebuilding that sequence takes effort. [2]</p><p>This is why modern engineering work is more exhausting than it often looks from the outside.</p><p>The task may be to write code. The real work is holding a chain of reasoning together while Slack interrupts, meetings split the day, CI fails for an unrelated reason, and someone asks for a quick answer that is not quick at all.</p><p>We often treat this as a time-management problem. But a system that constantly fragments attention is not just slowing people down. It is repeatedly forcing them to restart the same reasoning from partial state. That is expensive work.</p><h3>3. Cognitive structures degrade over time</h3><p>Understanding isn’t stored the way a file is stored. It decays when it is not reinforced.</p><p>People forget details. More importantly, they lose structure: why a decision was made, which tradeoff mattered, what exception broke the original rule, what assumptions were made. Without reuse or reinforcement, those structures fade. [3]</p><p>A team says, “we already aligned on this.” What they often mean is that the topic was discussed once. Two weeks later, one person remembers the conclusion, another remembers the concern, and a third remembers only that the issue felt resolved.</p><p>The same thing happens in codebases.</p><p>An engineer who has touched a service every week can navigate it quickly because the mental model is alive. Another engineer opening the same service after six months is not “being slow.” They are rebuilding a model that has decayed through disuse.</p><p>This is also why documentation disappoints so often. The problem is not that writing things down is useless. The problem is that static documents do not preserve live understanding by themselves. They help, but only if the surrounding system keeps the knowledge active, revisited, and connected to real decisions.</p><p>Knowledge decays. Shared understanding decays faster.</p><h3>4. Cognitive transfer between agents is lossy and reconstructive</h3><p>The first three constraints describe a single mind. The fourth appears when understanding has to cross into another.</p><p>A product manager explains a goal to an engineering manager. The engineering manager reframes it for a team lead. The team lead turns it into technical tasks. A senior engineer explains edge cases to another engineer in a hurried call. Notes are added. Tickets are updated. A PR description fills in some of the missing context.</p><p>The receiving mind does not get a clean copy of the sender’s model. It builds a new model from language, artifacts, prior experience, missing details, and local assumptions. That reconstructed model may be close enough to act on, but it is almost never identical. [4]</p><p>And the loss increases quickly with every additional boundary.</p><p>Add one more team, one more approval layer, one more handoff, one more dependency on “just ask John, he knows how this works,” and the problem is no longer only complexity in the system. It is complexity in the transfer of reasoning.</p><h3>Now look at the crash again</h3><p>Let’s go back to the Model 299 crash with these constraints in mind.</p><p><strong>Bounded.</strong> Hill understood every system on the plane. But the Model 299 demanded more realtime coordination than one person could reliably hold in focus on a first flight.</p><p><strong>Serial.</strong> Hill could not run thirty pre-flight steps in parallel. He had to walk through them in order, under the load of a machine he had never flown.</p><p><strong>Degraded.</strong> This was the first flight in type. Procedures had been studied, not reinforced through repetition. Under pressure, unpracticed steps are the first to go.</p><p><strong>Lossy.</strong> Hill was not alone in the cockpit. Les Tower, Boeing’s chief test pilot who had helped design the aircraft, was on board. The knowledge existed in the aircraft. It simply did not cross from one mind to another in time to matter.</p><p>The crash makes the constraints visible in a single event. The question was what to do about them.</p><p>A group of test pilots refused to accept that the airplane itself was unmanageable. They made a checklist — a single index card that walked the crew through every step before takeoff. One small artifact that lowered the load, enforced the sequence, resisted decay, and carried the model from one cockpit to the next.</p><p>The B-17 went on to fly thousands of hours without a major accident. Over 12,000 were built.</p><h3>The same constraints, still ignored</h3><p>Over twenty years in engineering, I keep seeing the same cognitive failures. Not because people are careless, but because the systems they work in exceed what a human mind can reliably handle.</p><p>The industry is not blind to this. Many established practices — small pull requests, bounded contexts, runbooks, on-call rotations — already work by reducing cognitive load. But they are usually framed as craft wisdom or team habits, not as responses to specific, measurable constraints.</p><p>In the <a href="https://pavelfokin.dev/writing/2026/the-cognitive-gap/">previous article</a>, I described the widening gap between system complexity and human cognitive capacity — the Cognitive Gap. The place where cognitive debt accumulates and failures cluster.</p><p>These four constraints are the next step: making the limits explicit and actionable. Not new rules, but a foundation that explains why the good practices work — and predicts where they’ll fail.</p><p>The next article will translate them into design principles.</p><h3>References</h3><ol><li>Cowan, N. (2001). <em>The magical number 4 in short-term memory: A reconsideration of mental storage capacity.</em> Behavioral and Brain Sciences, 24(1), 87–114.</li><li>Altmann, E. M., Trafton, J. G., &amp; Hambrick, D. Z. (2014). <em>Momentary interruptions can derail the train of thought.</em> Journal of Experimental Psychology: General, 143(1), 215–226.</li><li>Ebbinghaus, H. (1885). <em>Über das Gedächtnis</em>; Murre, J. M. J., &amp; Dros, J. (2015). <em>Replication and analysis of Ebbinghaus’ forgetting curve.</em> PLOS ONE, 10(7).</li><li>Clark, H. H. (1996). <em>Using Language.</em> Cambridge University Press.</li></ol><p><em>Originally published at </em><a href="https://pavelfokin.dev/writing/2026/the-four-cognitive-constraints/"><em>https://pavelfokin.dev</em></a><em> on April 16, 2026.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6c47a1a274d0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Cognitive Gap: you’re optimizing the wrong resource]]></title>
            <link>https://medium.com/@pavelfokin/the-cognitive-gap-youre-optimizing-the-wrong-resource-f9014e7f6b59?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/f9014e7f6b59</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[cognitive-science]]></category>
            <category><![CDATA[engineering-management]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Wed, 01 Apr 2026 00:00:06 GMT</pubDate>
            <atom:updated>2026-04-07T10:04:03.538Z</atom:updated>
            <content:encoded><![CDATA[<h4>Cognitive-First Engineering</h4><h4>Complexity scales. Your brain doesn’t.</h4><figure><img alt="Martec’s Law diagram by Scott Brinker: technology changes exponentially while organizations change logarithmically, with the gap between them representing the challenge of technology management" src="https://cdn-images-1.medium.com/max/1024/1*_boJ3wfBUbWF_XkUn0x9kQ.png" /></figure><p>At 2:32 PM on a Thursday, a senior engineer clicks Merge. His commit takes down billing for half your users.</p><p>When the CTO reads the postmortem, it says “human error.” The action item is to add more tests.</p><p>What the document won’t mention: at 2:20 PM he was pulled into a quick sync. At 2:25, he was tagged in a Slack thread. At 2:31 PM, a notification about a failing test in another branch. And his attention was already holding three conflicting requirements of the next feature.</p><p>It wasn’t a careless mistake. The engineer was operating in a system that exhausted his attention before he clicked the button.</p><p>I’ve seen the same patterns in every engineering organization I’ve worked with over the past twenty years. Different stacks, different cultures. The same failures.</p><h3>The third line</h3><p>In 2013, Scott Brinker described what he called Martec’s Law: technology changes exponentially, organizations change logarithmically. [1]</p><figure><img alt="Martec’s Law diagram by Scott Brinker: technology changes exponentially while organizations change logarithmically, with the gap between them representing the challenge of technology management" src="https://cdn-images-1.medium.com/max/600/1*uhIVc2oSiifB9xHql_7Dvw.png" /></figure><p>Brinker’s two curves describe how organizations fall behind technology. The growing space between those curves is the source of that feeling that your team is always behind. But both curves assume the people inside those organizations can keep up. They can’t.</p><p>There’s a line underneath both curves that nobody draws.</p><p>For the last hundred thousand years, the human cognitive ability didn’t grow logarithmically. It didn’t grow at all. We’re operating in different environments and thinking about different things. But the number of items a person can hold in mind, the depth of focus they can sustain, the quality of decisions they can make before fatigue — didn’t change.</p><p>Technology scales. Organizations adapt slowly. Cognitive capacity stays the same.</p><ul><li>Working memory holds about four items at a time (Cowan, 2001). [2]</li><li>The brain processes information at about 10 bits per second when thinking carefully (Zheng &amp; Meister, 2024). [3]</li><li>A single interruption costs roughly 23 minutes of full focus recovery (Mark, 2008). [4]</li></ul><p>These numbers are the same for the intern and the CTO.</p><p>The space between exponential complexity and fixed human capacity is what I call the Cognitive Gap. It widens every year, in every engineering organization, regardless of headcount or tooling budget. This is the space where the cognitive debt accumulates.</p><p>The Cognitive Gap is not an abstraction. As the gap widens, cognitive debt accumulates: decisions made with incomplete context, knowledge locked in one person’s head, reasoning outsourced to meetings. The usual fixes make it worse. That’s the trap.</p><h3>How we experience the gap</h3><p>The Cognitive Gap doesn’t show up as one dramatic failure. It shows up as a series of everyday frictions that everyone accepts as the cost of doing work.</p><p>You hired a senior engineer to think. The system doesn’t give them the chance. No clear ownership, tangled dependencies, four approvals for what one person already reasoned through. That’s cognitive waste. Scale that across the org and the problem compounds.</p><p>Every company has that one engineer who “just knows how things work.” They answer the Slack questions nobody else can. Important decisions wait for their input. You think they’re your strongest engineer. But it’s the reasoning bottleneck. Remove that person from the room and the problem becomes visible.</p><p>Or watch a planning session. The team juggles the latest refactoring, three unresolved dependencies, and half-remembered conversations from last week. They produce an estimate. Two months later it’s off by 3x. And they’ll keep estimating with the same confidence. Not because they’re bad at their job, but because that’s how human decision-making works.</p><p>For years I treated these as separate problems. Until I realized they have the same root — the system exceeds what people can reliably think.</p><h3>Why the best practices miss</h3><p>It’s always easy to prescribe the best practices.</p><p>Knowledge stuck in one person’s head? Write more documentation. But nobody has the cognitive bandwidth to read it, or keep it current.</p><p>Estimates are off? Add more detail to requirements. But the team was already at capacity when they sat down to plan.</p><p>These interventions aim at behavior. The root cause is structural — how the system is designed.</p><p>Your engineers aren’t failing to write good docs. They’re failing to write docs that survive under interrupted, time-pressured, context-switching conditions.</p><p>Your meetings aren’t replacing thinking because the team is lazy, but because the system never made thinking cheap enough to happen in other way.</p><p>This isn’t a culture problem. It’s a resource management failure — for the one resource nobody manages.</p><h3>The question that changes everything</h3><p>We keep asking: “Why is the team slow?”</p><p>This leads to predictable answers — not enough process, not enough people, not enough skill. So we hire, train, add process. And the team gets slower, because every new addition increases cognitive load on an already overloaded system.</p><p>There’s a better question: “What is consuming their thinking budget right now?”</p><p>The team isn’t slow. The team is at cognitive capacity inside a system that demands more than biology allows. You can’t change the hardware. You can only design around it.</p><p>The brain is the platform. Everything else is built on top of it. That’s the constraint.</p><p>Cognitive-First Engineering is the design response. In the next part, we’ll look at its foundations.</p><h3>References</h3><ol><li><a href="https://chiefmartec.com/2013/06/martecs-law-technology-changes-exponentially-organizations-change-logarithmically/">Martec’s Law: Technology changes exponentially, organizations change logarithmically</a></li><li>Cowan, N. (2001). The magical number 4 in short-term memory: A reconsideration of mental storage capacity. Behavioral and Brain Sciences, 24(1), 87–114.</li><li>Zheng, J., &amp; Meister, M. (2024). The unbearable slowness of being: Why do we live at 10 bits/s. Neuron, 112(3), 1–18.</li><li>Mark, G., Gudith, D., &amp; Klocke, U. (2008). The cost of interrupted work: More speed and stress. Proceedings of the SIGCHI Conference on Human Factors in Computing Systems, 107–110.</li></ol><p><em>Originally published at </em><a href="https://pavelfokin.dev/writing/2026/the-cognitive-gap/"><em>https://pavelfokin.dev</em></a><em> on April 1, 2026.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f9014e7f6b59" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What is Technology Strategy? (And How to Create One That Works)]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@pavelfokin/what-is-technology-strategy-and-how-to-create-one-that-works-3db760c9f5a8?source=rss-9fdf1cfd850------2"><img src="https://cdn-images-1.medium.com/max/2600/0*tJU8Knp4KVbyjkjo" width="4600"></a></p><p class="medium-feed-snippet">A no-nonsense guide to creating a technology strategy that works</p><p class="medium-feed-link"><a href="https://medium.com/@pavelfokin/what-is-technology-strategy-and-how-to-create-one-that-works-3db760c9f5a8?source=rss-9fdf1cfd850------2">Continue reading on Medium »</a></p></div>]]></description>
            <link>https://medium.com/@pavelfokin/what-is-technology-strategy-and-how-to-create-one-that-works-3db760c9f5a8?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/3db760c9f5a8</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Sun, 24 Nov 2024 21:43:18 GMT</pubDate>
            <atom:updated>2024-11-25T07:42:13.524Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[How to Implement Functional Options in Go]]></title>
            <link>https://medium.com/@pavelfokin/how-to-implement-functional-options-in-go-3049f4598c06?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/3049f4598c06</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[go]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Sat, 04 Feb 2023 16:03:56 GMT</pubDate>
            <atom:updated>2023-02-04T16:03:56.017Z</atom:updated>
            <content:encoded><![CDATA[<h4>On Coding Well</h4><h4>Functional Options is a “gem” among Go patterns</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UOVKddKF2BfwogJdIau08w.png" /><figcaption>Functional Option in Go</figcaption></figure><p>There are a few patterns that feel native in Go. The reason for that is that Go is quite limited in implementing abstractions. And it’s been made with a reason. The reason is to make code more maintainable and easy to read.</p><p>That’s why the <strong>Functional Options</strong> pattern is one of the <strong>gems</strong> in the Go arsenal.</p><h3>History</h3><p>Rob Pike proposed using self-referential functions as options in his blog post in 2014 [1]. Dave Cheney explained a bit more of the motivation for this pattern in his post [2]. The goal was to find the way of creating an extensible and clear API to configure options and not overload the constructor with arguments.</p><h3>Service</h3><p>Our example will be a <strong>Service</strong> struct that has two options host and port. And we want to configure these options with an extensible API.</p><h3>Structs</h3><p>Let’s start with defining basic <strong>structs</strong>.</p><ul><li>Service is a main struct that we need to configure.</li><li>Options is a struct that keeps all options you are interested in.</li></ul><pre>type Options struct {<br>  Host string<br>  Port int<br>}<br><br>type Service struct {<br>  options *Options<br>}</pre><h3><strong>Setters</strong></h3><p>Next, we will need the Setter type. A <strong>type</strong> of function that is responsible for configuring specific options.</p><pre>type Setter func(*Options)<br><br>func WithHost(host string) Setter {<br>  return func(opts *Options) {<br>    opts.Host = host<br>  }<br>}<br><br>func WithPort(port int) Setter {<br>  return func(opts *Options) {<br>    opts.Port = port<br>  }<br>}</pre><h3>Constructor</h3><p>Then let’s implement a function that will initialize a Service structure.</p><pre>func New(setters ...Setter) *Service {<br>  // Here we can have default values<br>  options := &amp;Options{<br>    Host: &quot;url&quot;,<br>    Port: 8080,<br>  }<br><br>  for _, set := range setters {<br>    set(options)<br>  }<br><br>  return &amp;Service{<br>    options: options,<br>  }<br>}</pre><h3>Usage</h3><p>Now, we gather all pieces together to see how it works.</p><pre>func main() {<br>  fmt.Println(&quot;Functional Patterns&quot;)<br>  service := New(<br>    WithHost(&quot;127.0.0.1&quot;),<br>    WithPort(5000),<br>  )<br>  fmt.Printf(<br>    &quot;%s:%d\n&quot;,<br>    service.options.Host,<br>    service.options.Port,<br>  )<br>}</pre><p>And output will be:</p><pre>➜  go-patterns git:(main) ✗ go run ./basics/funcitonaloptions/.<br>Functional Patterns<br>127.0.0.1:5000</pre><h3><strong>Conclusion</strong></h3><p>At first sight, it looks overkill, but it really just a few extra lines for each new option. And it adds extensibility to your configuration API.</p><ul><li>Let you write APIs that can grow with time.</li><li>Make the default options use case to be the simplest.</li><li>Provide meaningful configuration parameters.</li></ul><p>Happy coding!</p><p>Full code you can find in my GitHub repo <a href="https://github.com/pavel-fokin/go-patterns/tree/main/basics/funcitonaloptions"><strong>pavel-fokin/go-patterns/basics/funcitonaloptions</strong></a>.</p><p><strong>Thank you for reading! Share you thoughts with me on </strong><a href="https://www.linkedin.com/in/pavel-fokin/"><strong>LinkedIn</strong></a><strong> or </strong><a href="https://twitter.com/pavelfokin_"><strong>Twitter</strong></a><strong>.</strong></p><h3>Further readings</h3><p>If you like this article you can be interested in the following.</p><ul><li><a href="https://medium.com/@pavelfokin/how-to-build-a-minimal-golang-docker-image-b4a1e51b03c8">How to Build a Minimal Golang Docker Image</a></li><li><a href="https://medium.com/@pavelfokin/what-are-the-limits-of-go-channels-378e412d685d">What are the limits of Go channels?</a></li></ul><h3>References</h3><ol><li>Rob Pike. Self-referential functions and the design of options. <a href="https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html">https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html</a></li><li>Dave Cheney. Functional options for friendly APIs. <a href="https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis">https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3049f4598c06" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Build a Minimal Golang Docker Image]]></title>
            <link>https://medium.com/@pavelfokin/how-to-build-a-minimal-golang-docker-image-b4a1e51b03c8?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/b4a1e51b03c8</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[go]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Sun, 07 Aug 2022 20:23:44 GMT</pubDate>
            <atom:updated>2022-08-07T20:23:44.893Z</atom:updated>
            <content:encoded><![CDATA[<h4>Go Ways</h4><h4>Make Docker image less than 10MB</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*I3Ltwi3Gdqj3l4ZRnHzyqw.png" /><figcaption>Minimal Golang Docker Image</figcaption></figure><p>Having an image container that keeps precisely what you need is always considered a best practice. We want to have only our application and dependencies that are required for its runtime.</p><p>Why we would do this?</p><ul><li>Small size image reduces the risk of vulnerabilities.</li><li>It will improve the deployment process improve perfomance and reduce size</li></ul><h3>Minimal Project</h3><p>I’ll be using a simple HelloWorld webservice to build a <strong>Docker</strong> image.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5gYTwPob0C-X2QqPQ-NTZg.png" /><figcaption>HelloWorld webservice</figcaption></figure><h3>Using alpine image</h3><h4><strong>01. Dockerfile</strong></h4><p>Let’s write a <strong>Dockerfile</strong> with using an alpine <strong>distro</strong> as an image.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*scDndn8OyKUzTT9jPS6KgA.png" /><figcaption>Docker.large</figcaption></figure><h4>02. Docker build</h4><p>After building this <strong>Dockerfile</strong> we will get a <strong>350MB</strong> image.</p><pre>➜  minimal-docker git:(main) ✗ docker build -t helloworld-large -f Dockerfile.large .<br>[+] Building 7.1s (12/12) FINISHED<br>...<br>...<br>... </pre><pre>➜  minimal-docker git:(main) ✗ docker image ls helloworld-large<br>REPOSITORY         TAG       IMAGE ID       CREATED          SIZE<br>helloworld-large   latest    678f9303af18   10 seconds ago   350MB</pre><pre>➜  minimal-docker git:(main) ✗ docker run -ti -p 8000:8000 helloworld-large:latest<br>Server listen 8000...</pre><p>Can we do better? Yes, we can!</p><h3>Using distroless image</h3><h4>01. Dockerfile</h4><p>For the next Dockerfile we will use <strong>multistage</strong> approach and <a href="https://github.com/GoogleContainerTools/distroless"><strong>distroless</strong></a> image by Google.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cExKnAmj8qwpIH4PhdUmKg.png" /><figcaption>Docker.small</figcaption></figure><h4>02. Docker build</h4><p>Voila! After building we get only <strong>8.6MB</strong> image size.</p><pre>➜  minimal-docker git:(main) ✗ docker build -t helloworld-small -f Dockerfile.small .<br>[+] Building 8.0s (14/14) FINISHED<br>...<br>...<br>...</pre><pre>➜  minimal-docker git:(main) ✗ docker image ls helloworld-small<br>REPOSITORY         TAG       IMAGE ID       CREATED         SIZE<br>helloworld-small   latest    3b035dc2c7e4   5 seconds ago   8.6MB</pre><pre>➜  minimal-docker git:(main) ✗ docker run -ti -p 8000:8000 helloworld-small:latest<br>Server listen 8000...</pre><p>Can we do better? Yes, we can!</p><h3>Using scratch image</h3><h4>01. Dockerfile</h4><p>We even can go smaller, for this we can use <strong>scratch</strong> image. But as this is a <strong>super slim</strong> image we will need to add some extra things as <strong>timezones</strong> or <strong>ssl certificates</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MzSKpdW3ReYNPev5n3E56A.png" /><figcaption>Docker.xsmall</figcaption></figure><h4>02. Docker build</h4><p>And we get <strong>7.59MB</strong> image.</p><pre>➜  minimal-docker git:(main) ✗ docker build -t helloworld-xsmall -f Dockerfile.xsmall .<br>...<br>...</pre><pre>➜  minimal-docker git:(main) ✗ docker image ls helloworld-xsmall<br>REPOSITORY          TAG       IMAGE ID       CREATED          SIZE<br>helloworld-xsmall   latest    b7b554ac46c9   21 minutes ago   7.59MB</pre><p>Full code you can find in my GitHub repo <a href="https://github.com/pavel-fokin/go-patterns/tree/main/minimal-docker"><strong>pave-fokin/go-patterns/minimal-docker.</strong></a></p><p>Happy coding!</p><p><strong>Thank you for reading! Share you thoughts with me on </strong><a href="https://www.linkedin.com/in/pavel-fokin/"><strong>LinkedIn</strong></a><strong> or </strong><a href="https://twitter.com/pavelfokin_"><strong>Twitter</strong></a><strong>.</strong></p><h3>Further readings</h3><p>If you like this article you can be interested in the following.</p><ul><li><a href="https://medium.com/@pavelfokin/how-to-embed-react-app-into-go-binary-12905d5963f0">How to Embed React App into Go Binary</a></li><li><a href="https://medium.com/@pavelfokin/what-are-the-limits-of-go-channels-378e412d685d">What are the limits of Go channels?</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b4a1e51b03c8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Embed React App into Go Binary]]></title>
            <link>https://medium.com/@pavelfokin/how-to-embed-react-app-into-go-binary-12905d5963f0?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/12905d5963f0</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[go]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Sat, 23 Jul 2022 15:28:58 GMT</pubDate>
            <atom:updated>2022-07-24T07:32:23.412Z</atom:updated>
            <content:encoded><![CDATA[<h4>Go Ways</h4><h4>All that is mine I carry with me</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*ssMEla6jgXqgEisX9K33Gg.png" /><figcaption>Go + React</figcaption></figure><p>Image that you have an amazing project with <strong>React</strong> app, and you want to distribute and deploy it along with you <strong>Go</strong> application.</p><p>Let’s say that it is a super cool<strong> LikeIt! </strong>project, and it allows to like a page ¯\_(ツ)_/¯.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*D3RzhPw_og5iFABEOSs6jw.gif" /><figcaption>Like It!</figcaption></figure><h3><strong>01 Project structure</strong></h3><p>First, lets review the project structure.</p><p>In the root of the project we have the <strong>main.go </strong>file. This is the entry point and keeps all the go code.</p><ul><li><strong>main.go</strong> — is in the root of the project and this is an entry point for our <strong>Go</strong> app.</li><li><strong>/web </strong>—<strong> </strong>directory keeps code and assets for the <strong>React</strong> app.</li><li><strong>/web/dist </strong>—<strong> </strong>is an empty directory that will keep built web assets.</li></ul><p>For this example I‘m using <a href="https://parceljs.org/"><strong>Parcel</strong></a> to build a web part.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kes4TIcQ99_VgbiEyTmo7w.png" /><figcaption>Project structure</figcaption></figure><h3>02 Go “embed” package</h3><p>Since <strong>go-1.16</strong> standard library includes <strong>embed</strong> package. This package provides access to files embedded in the running Go program.</p><p>With the usage of //go:embed directive, we can initialize a variable of type <strong>string</strong>, <strong>[]byte</strong>, or <strong>FS</strong>. A variable can keep content of the file or the whole directory.</p><p>For more examples check the package <a href="https://pkg.go.dev/embed">documentation</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YotdAUI-8dW2ffNjmvlhIw.png" /><figcaption>Embed package</figcaption></figure><h3><strong>03 How to serve static files</strong></h3><p><strong>Embed</strong> package implements <strong>FS</strong> interface, so it can be used with any package that understands file systems, including <strong>net/http</strong>, <strong>text/template</strong>, and <strong>html/template</strong>.</p><p>That means that we can use built-in <strong>http.FileServer </strong>to serve our embedded files.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6hnrqpGCKuzKXyso_wMvVg.png" /></figure><h3>04 Results</h3><p>As the result we can build a <strong>Go </strong>binary that keeps all our static files.</p><pre>➜  likeit git:(main) ✗ go build -o bin/likeit main.go<br>➜  likeit git:(main) ✗ ls -lh bin/likeit<br>-rwxr-xr-x  1 pavel-fokin staff   6.6M Jul 23 16:48 bin/likeit</pre><p>And it can be deployed as heroku app -&gt; <a href="https://likeit-click.herokuapp.com/"><strong>likeit-click</strong></a><strong>.</strong></p><p>Full code you can find in my GitHub repo <a href="https://github.com/pavel-fokin/likeit"><strong>pavel-fokin/likeit</strong></a><strong>.</strong></p><p><strong>Thank you for reading! Share you thoughts with me on </strong><a href="https://www.linkedin.com/in/pavel-fokin/"><strong>LinkedIn</strong></a><strong> or </strong><a href="https://twitter.com/pavelfokin_"><strong>Twitter</strong></a><strong>.</strong></p><h3>Further readings</h3><p>If you like this article you can be interested in the following.</p><ul><li><a href="https://medium.com/@pavelfokin/what-are-the-limits-of-go-channels-378e412d685d">What are the limits of Go channels?</a></li><li><a href="https://betterprogramming.pub/why-do-programming-languages-have-types-c9346faf9559">Why Do Programming Languages Have Types?</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=12905d5963f0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What are the limits of Go channels?]]></title>
            <link>https://medium.com/@pavelfokin/what-are-the-limits-of-go-channels-378e412d685d?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/378e412d685d</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[go]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Sun, 26 Jun 2022 09:44:44 GMT</pubDate>
            <atom:updated>2022-08-03T06:59:04.964Z</atom:updated>
            <content:encoded><![CDATA[<h4>Go Internals</h4><h4>By the message size, maximum allocation, and performance</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*FB9HsT-qAiycomsJYvlH1Q.png" /><figcaption>What are the limits of Go channels?</figcaption></figure><p>Did you ever think about the limits of Go channels? I decided to look into the <a href="https://github.com/golang/go">golang repo</a> to find out how channels are created.</p><p>Here is what I found out.</p><h3>Making a channel</h3><p>I started by looking for the code of the function that creates a channel. Not surprisingly I could find it in the runtime/chan.go file.</p><p>Function makechannel has the following signature.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ghwXWNshiY4xNLH8Gg5pjw.png" /><figcaption>makechan function</figcaption></figure><p>Then let’s review what are the chantype and hchan types.</p><h3>Channel types</h3><p>A chantype is a wrapper for a _type struct.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fvRECuaVJPpNEpZm118Wug.png" /><figcaption>chantype struct</figcaption></figure><p>A _type type is an underlying struct for any go type, and it looks as follows.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Bknm_9USyy7oGyXk79y8-A.png" /><figcaption>_type struct</figcaption></figure><p>Then let’s take a look on the hchan type.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8RGEuwm4uXn5LgrX7QSLhg.png" /><figcaption>hchan struct</figcaption></figure><p>Let’s move forward and look into the makechan function.</p><h3>Message size</h3><p>When we start from the beginning of the makechan function. We can see that it checks for a <strong>size</strong> of the future <strong>channel’s message</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_0ZFPGSuIGdT6e0m2ubbUg.png" /><figcaption>Maximum message size</figcaption></figure><p>And the maximum message size is <strong>2¹⁶ bytes</strong>, or <strong>64 kilobytes</strong>.</p><h3>Maximum allocation</h3><p>The next step is to check the size of the memory that can be allocated for a new channel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ofjbcbERDgu7sBzL4gkgQw.png" /><figcaption>memory allocation</figcaption></figure><p>What is the maxAlloc size?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*odO5FN_f99XBMOWSNVNrrg.png" /><figcaption>maxAlloc</figcaption></figure><p>The maxAlloc determines the maximum memory size that is theoretically allowed. On the <strong>64-bit</strong> Unix-like systems this is <strong>2⁴⁷ bytes </strong>(~140 Terabytes).</p><p>Though, it allows allocating up to<strong> 140 Terabytes</strong>. You will meet the memory issues if you will try to do so 😄.</p><h3>Performance</h3><p>By the following <strong>naive benchmark</strong>, we can measure the upper limits for the <strong>send/receive operations</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LUj4t5p-I_RHQDdFxXXboA.png" /><figcaption>Naive channels benchmark</figcaption></figure><p>The <strong>send</strong> and <strong>receive</strong> operations are mainly spending time in the <strong>goroutine’s context</strong> switching. On my machine, this number is stably <strong>&lt;100 ns</strong>.</p><pre>➜  channels git:(main) ✗ go test -bench=.<br>goos: darwin<br>goarch: arm64<br>pkg: pavel-fokin/go-patterns/concurrency/channels<br>BenchmarkUnbufferedChannelInt-8         11091662               107.5 ns/op<br>BenchmarkBufferedChannelInt-8           15082126                80.11 ns/op<br>PASS<br>ok      pavel-fokin/go-patterns/concurrency/channels    7.021s</pre><h3>Final thoughts</h3><p>Looking into the Go internals is definitively worth it. You not only can see the details of implementation but also learn best practices.</p><p>Happy coding!</p><h3>Further readings</h3><p>If you like this article you can be interested in the following.</p><ul><li><a href="https://medium.com/@pavelfokin/how-to-implement-mediator-pattern-in-go-ad10ce2c4082">How to Implement Mediator Pattern in Go</a></li><li><a href="https://betterprogramming.pub/why-do-programming-languages-have-types-c9346faf9559">Why Do Programming Languages Have Types?</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=378e412d685d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Implement Mediator Pattern in Go]]></title>
            <link>https://medium.com/@pavelfokin/how-to-implement-mediator-pattern-in-go-ad10ce2c4082?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/ad10ce2c4082</guid>
            <category><![CDATA[go]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Mon, 06 Jun 2022 12:42:24 GMT</pubDate>
            <atom:updated>2022-06-06T12:47:42.684Z</atom:updated>
            <content:encoded><![CDATA[<h4>Go Patterns</h4><h4>Behavioral Design Patterns in Go</h4><figure><img alt="Mediator Pattern in Go" src="https://cdn-images-1.medium.com/max/700/1*QsV4r_fnaxnGmrmqxVH93g.png" /><figcaption>Mediator Pattern in Go</figcaption></figure><p>Sometimes we have a bunch of objects that need to interact with each other. A number of objects can be large and their interactions can have complex logic.</p><p><strong>Mediator pattern</strong> helps to organize such cases.</p><ul><li><strong>Mediator</strong> lets keep loose coupling and don’t let objects have direct communication.</li><li><strong>Mediator</strong> keeps the interaction logic and allows to change it independently.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/760/0*2qDdW0FlPfq8PJGX.png" /></figure><p>Let’s look for an example!</p><h3>A chat</h3><p>For example, we have a bunch of Users and they want to interact with each other.</p><ul><li>A User can send a message to another User.</li><li>A User can send a message to all Users.</li><li>Some Users can be unavailable for messaging.</li></ul><p>So we introduce a Chat object that keeps this logic and organizes communication.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/760/0*XsLyj3x4BfrQt7e0.png" /><figcaption>Gophers chat</figcaption></figure><h3>User type</h3><p>Firstly, we will introduce a User type. It will have a Name and store Messages.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*hNQjAOjvdaHe2DLB6r7RYg.png" /><figcaption>User type</figcaption></figure><h3>Chat type</h3><p>Then we need a Chat type. It will have a method to Add a User and keep information about Users in the Chat. This is our Mediator.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*T2015fuMhk4DUhBlvkh_jA.png" /><figcaption>Chat type</figcaption></figure><h3>Interaction logic</h3><p>Now, let’s extend our <strong>Chat</strong> with interaction logic.</p><ul><li>Say(to User, msg string) - sends a message to the specific User and handles an error if the User is not in the Chat.</li><li>SayAll(msg string) - sends a message to the all available Users.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*ELH8V-kP0Ve34KmTyvhR_A.png" /><figcaption>Interaction logic</figcaption></figure><h3>Usage Example</h3><p>Now, we gather all pieces together to see how it works.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1010/1*am1NWf-jzc93lQcgyExjCw.png" /><figcaption>Main function</figcaption></figure><h3>Conclusion</h3><p><strong>Mediator</strong> pattern is a good example of encapsulation logic into separate entity. It’s a complement to the <strong>Observer</strong> pattern. In real world applications though the logic can grow a lot, and turn this into <strong>God object</strong> antipattern.</p><p>Happy coding!</p><p>Code examples can be found in my GitHub repo <a href="https://github.com/pavel-fokin/go-patterns"><strong>pavel-fokin/go-patterns</strong></a>.</p><h3>More reading</h3><p>If you like this article you can be interested in the following.</p><ul><li><a href="https://betterprogramming.pub/why-do-programming-languages-have-types-c9346faf9559">Why Do Programming Languages Have Types?</a></li><li><a href="https://medium.com/@pavelfokin/how-to-implement-memento-pattern-in-go-b7fcb91b5f99">How to Implement Memento Pattern in Go</a></li></ul><p><em>Originally published at </em><a href="https://pavelfokin.dev/blog/mediator-pattern-in-go"><em>https://pavelfokin.dev</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ad10ce2c4082" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Implement Memento Pattern in Go]]></title>
            <link>https://medium.com/@pavelfokin/how-to-implement-memento-pattern-in-go-b7fcb91b5f99?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/b7fcb91b5f99</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[go]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Mon, 16 May 2022 14:27:07 GMT</pubDate>
            <atom:updated>2022-06-07T20:52:19.759Z</atom:updated>
            <content:encoded><![CDATA[<h4>Go Patterns</h4><h4>Behavioral Design Pattern in Go</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/0*FPOMavLUREou1EMK.png" /><figcaption>Memento Pattern in Go</figcaption></figure><p>Let’s take a look at the problem. We have some object and we want to be able to save and restore its state. And we want to have a good design for it.</p><ul><li>We want to have a <strong>separation of concerns</strong>, different logic has to have different owners.</li><li>We don’t want to break an <strong>encapsulation</strong> of the object and hide direct access to its state.</li></ul><p>The <strong>Memento</strong> pattern is for the rescue!</p><h3>Tasks</h3><p>For example, we have a type that keeps a list of Tasks. We don&#39;t have direct access to the list of tasks, and we have implemented the Add method.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*stb_M7oPVGNVQu34S_90Kg.png" /><figcaption>Tasks</figcaption></figure><h3>Memento</h3><p>As the first step, we will introduce a new type — Memento. This is the box that can keep a list of tasks. This list is also <strong>private</strong> and we have a specific method to access it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f96g9f-6NlI0D_W4ul1CIA.png" /><figcaption>Memento</figcaption></figure><p>The Memento object has to be as simple as possible and it doesn&#39;t have any other logic.</p><h3>Improve Tasks</h3><p>The next step will be improving the Tasks object. We&#39;ll need to implement two additional methods.</p><ul><li>Memento() - it creates a Memento instance that keeps the current Tasks state.</li><li>Restore(m Memento) - this method can restore a Tasks&#39; state from a Memento instance</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WxRNZpagHbS_UVzSxMlqaw.png" /><figcaption>Improve Tasks</figcaption></figure><h3>History of Changes</h3><p>The next object we implement will be a History type. This type keeps a stack of Memento objects.</p><p>Implementing this type is not required by the classical <strong>Memento</strong> pattern. But I think it’s good to have it for a cleaner example.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jSwm6PqlRXkMRUfK3JDPMw.png" /><figcaption>History</figcaption></figure><h3>Usage Example</h3><p>In this example, the main function knows why and when the Tasks need to save and restore itself.</p><p>In the general case, it can be an additional <strong>type</strong> that keeps that logic.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nQpgM1tMy7b1Xh1hsALrnA.png" /></figure><p>And output will be</p><pre># Output<br>➜  go-patterns git:(main) go run ./behavioral/memento<br>[Task 1 Task 2]<br>[Task 1]<br>[]</pre><h3>Conclusion</h3><p>Implementation of a basic <strong>Memento Pattern</strong> is a good example of <strong>separation of concerns</strong>. It keeps <strong>encapsulation</strong> of the initial object and extends its functionality with new logic.</p><p>Happy coding!</p><p>Code examples can be found in my GitHub repo <a href="https://github.com/pavel-fokin/go-patterns"><strong>pavel-fokin/go-patterns</strong></a>.</p><h3>More reading</h3><p>If you like this article you can be interested in the following.</p><ul><li><a href="https://medium.com/@pavelfokin/how-to-implement-mediator-pattern-in-go-ad10ce2c4082">How to Implement Mediator Pattern in Go</a></li><li><a href="https://medium.com/mindware-engineering/how-to-implement-observer-pattern-in-go-621365ae8d03">How to Implement Observer Pattern in Go</a></li><li><a href="https://betterprogramming.pub/why-do-programming-languages-have-types-c9346faf9559">Why Do Programming Languages Have Types?</a></li></ul><p><em>Originally published at </em><a href="https://pavelfokin.dev/blog/how-to-implement-memento-pattern-in-go"><em>https://pavelfokin.dev</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b7fcb91b5f99" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What are SLIs, SLOs, and SLAs?]]></title>
            <link>https://medium.com/mindware-engineering/what-are-slis-slos-and-slas-2ab8362bd628?source=rss-9fdf1cfd850------2</link>
            <guid isPermaLink="false">https://medium.com/p/2ab8362bd628</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Pavel Fokin]]></dc:creator>
            <pubDate>Wed, 11 May 2022 15:02:21 GMT</pubDate>
            <atom:updated>2022-05-11T15:02:21.984Z</atom:updated>
            <content:encoded><![CDATA[<h4>Mindware Engineering</h4><h4>A way to reason about software quality</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*2n09M9si7PNW8WWWyBCpdA.png" /><figcaption>What are SLIs, SLOs, and SLAs?</figcaption></figure><p>When we start to develop software, we usually care about its quality.</p><p>Software quality is often divided into <strong>Functional</strong> and <strong>Non-functional</strong>.</p><p><strong>Functional</strong> quality is what software can do for its users.</p><p><strong>Non-functional</strong> is everything else that helps the software to serve its functions. And it includes a lot of things. Among them are the code quality, maintainability, how easy we can deploy software, how secure it is, and much more.</p><p>When we think about <strong>quality</strong>, we want to have some measurable characteristics. This gives us ability to make reasonable and data-driven decisions.</p><h3>Availability</h3><p>Let’s look at availability. This is the fraction of the time when service is usable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/760/0*rBpOkX7hdJvSXohQ.png" /><figcaption>Availability Formula</figcaption></figure><p>For example, we can find it for a web service as the ration of successful requests to the all requests. By successful requests we mean requests that are not 5xx.</p><p>Well, what these numbers can give us?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/701/0*5YtM42ls9Enu8oEv.png" /><figcaption>Availability with time</figcaption></figure><h4>When we design a solution.</h4><p>When we are discussing system design. We can make choices about the components for our systems.</p><p>For example, we can check that droplets in Digital Ocean have <strong>99.99%</strong> SLO, or that single instance of Google Compute Engine has low bound <strong>99.5%</strong> availability in a month.</p><p>Basically, we can check availability for different cloud components in <strong>AWS</strong> or <strong>Google Cloud</strong>. We can ask how many users will be effected if we will be unavailable for <strong>10 minutes</strong> each week.</p><h4>When we maintain a system.</h4><ul><li>We can improve our strategies with deployments. We will have metric for this.</li><li>We can have a focus on the critical parts of the system with higher availability.</li><li>We can change our technical solution to complain with required availability.</li></ul><h3>SLI</h3><p>An <strong>SLI</strong> is a service level indicator — a measurable metric of some aspect of service.</p><p>The measurements are often aggregated: raw data is collected over a time window and turned into a rate, average, or percentile.</p><p>Examples:</p><ul><li><strong>Availability</strong> is the fraction of the time that a service is usable.</li><li><strong>Request latency</strong> — how long it takes to return a response to a request. 99th percentile for <strong>latency</strong> will be example of such indicator.</li></ul><h3>SLO</h3><p>An <strong>SLO</strong> is a service level objective is a target value for a service level that is measured by an <strong>SLI</strong>.</p><p>For example:</p><ul><li>30 days availability ≤ 99.9%</li><li>P99 Latency for 99.9% of requests &lt; 1 sec</li></ul><h3>SLA</h3><p>An <strong>SLA</strong> is a service level agreement is a contract with your users that includes consequences of meeting (or missing) the <strong>SLOs</strong>.</p><p>An easy way to tell the difference between an <strong>SLO</strong> and an <strong>SLA</strong> is to ask <em>“What happens if the SLOs aren’t met?”</em>.</p><p>The consequences are most easily recognized when they are financial — a <strong>rebate</strong> or a <strong>penalty</strong>.</p><p>But also it can be internal policies. For instance, a team can freeze implementation of the new features until <strong>availability</strong> will be fixed.</p><h3>Final thoughts</h3><p><strong>SLIs</strong>, <strong>SLOs</strong>, and <strong>SLAs</strong> are the great tools that allow us to work with quality of service.</p><ul><li>Solid SLOs helps us to design better system.</li><li>Right SLOs gives a team confidence that a service is healthy.</li><li>Choosing appropriate SLOs helps to make the right action if something goes wrong.</li></ul><p><strong>Thank you for reading! Share you thoughts with me on </strong><a href="https://www.linkedin.com/in/pavel-fokin/"><strong>LinkedIn</strong></a><strong> or </strong><a href="https://twitter.com/pavelfokin_"><strong>Twitter</strong></a><strong>.</strong></p><h3>Further reading</h3><p>You can find more info at this <a href="https://sre.google/workbook/implementing-slos/">article</a> from the Google SRE Engineers.</p><p><a href="https://sre.google/workbook/implementing-slos/">Google - Site Reliability Engineering</a></p><p><em>Originally published at </em><a href="https://pavelfokin.dev/blog/what-are-slis-slos-slas/"><em>https://pavelfokin.dev</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2ab8362bd628" width="1" height="1" alt=""><hr><p><a href="https://medium.com/mindware-engineering/what-are-slis-slos-and-slas-2ab8362bd628">What are SLIs, SLOs, and SLAs?</a> was originally published in <a href="https://medium.com/mindware-engineering">Mindware Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>