<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Lula Leus</title>
    <description>The latest articles on Forem by Lula Leus (@lulaleus).</description>
    <link>https://forem.com/lulaleus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F904315%2Ff3b34eb4-c225-4e9d-9752-d1a6039d5766.jpeg</url>
      <title>Forem: Lula Leus</title>
      <link>https://forem.com/lulaleus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lulaleus"/>
    <language>en</language>
    <item>
      <title>An Engineer's Toolkit for continuous upskilling</title>
      <dc:creator>Lula Leus</dc:creator>
      <pubDate>Sun, 27 Aug 2023 16:50:32 +0000</pubDate>
      <link>https://forem.com/lulaleus/an-engineers-toolkit-for-continuous-upskilling-1g07</link>
      <guid>https://forem.com/lulaleus/an-engineers-toolkit-for-continuous-upskilling-1g07</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Software engineering is ever-evolving. The best practices and tools available for developers today differ from those of just 5 years ago. And they will similarly differ from what will be available in the next 5 years.&lt;/p&gt;

&lt;p&gt;In this shifting landscape, one constant is the engineers. Those that are building software today are likely to continue building software in 5 years time. In order to do so successfully, we should know the new tools and promote the usage of best practices of the day. But how can we keep our knowledge up-to-date and our skills relevant all the time? The answer is simple: we must become &lt;em&gt;"lifelong learners"&lt;/em&gt; out of necessity.&lt;/p&gt;

&lt;p&gt;In this article, I'll detail my approach to continuous learning and upskilling in software engineering. I will spotlight learning resources that I find most helpful. I'll also share a strategy to track learning progress and offer advice on how to keep going when learning doesn't have strict deadlines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Learning Materials to Use
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Newsletters
&lt;/h3&gt;

&lt;p&gt;Newsletters are curated collections of recent engineering news, articles, and open-source projects. They are great for answering the question &lt;em&gt;"What's new out there?"&lt;/em&gt;. I am a regular reader of the following three newsletters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.infoq.com/reginit.action"&gt;InfoQ Weekly&lt;/a&gt;: A comprehensive roundup of software engineering news and articles. It is worth noting that all articles mentioned there have almost academic qualities air to them. Heavy on knowledge, light on engaging storytelling, emojis or jokes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://go.libhunt.com/newsletter"&gt;Awesome Go Weekly&lt;/a&gt;: Since Go is my main programming language at work, I like to stay updated with the Go development.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://blog.bytebytego.com/"&gt;ByteByteGo&lt;/a&gt;: A bite-sized system design and architectural articles. System design is a fascinating topic. It is also a topic in which most engineers are rarely directly involved at work. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My main reason for reading these newsletters is to get up-to-date with a constant flow of news and identify new emerging topics I can explore in more depth later.&lt;/p&gt;

&lt;p&gt;It's easy to get carried away and subscribe to numerous newsletters. But remember, reading newsletters, unlike subscribing, demands time. It's better to read and benefit from a couple of weekly newsletters than to be overwhelmed with many, leading you to question your subscription choices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Articles
&lt;/h3&gt;

&lt;p&gt;I primarily come across articles I want to read either through recommendations in newsletters or while searching for answers to specific, well-defined questions.&lt;/p&gt;

&lt;p&gt;Articles are useful resources for following use cases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick broad Overviews: An introductory overview of a topic. Take, for example, &lt;a href="https://www.maxcountryman.com/articles/a-framework-for-prioritizing-tech-debt?utm_source=tldrnewsletter"&gt;"A Framework for Prioritizing Tech Debt"&lt;/a&gt;. This article provides a clear understanding of what tech debt is and presents a possible structured approach to deciding whether to eliminate it must be a priority. You do not need specific pre-existing knowledge to get value out of the article.&lt;/li&gt;
&lt;li&gt;Detailed Exploration of specific issue: Intensive focus on specific and very narrowly scoped issue. For example, the article &lt;a href="https://preslav.me/2023/02/06/golang-do-we-need-struct-pointers-everywhere/"&gt;"User or *User - Do We Need Struct Pointers Everywhere?"&lt;/a&gt; dives into nuances of passing structs either by value or by reference in Golang. You need a lot of pre-existing knowledge of Go and its type system in order to get value out of the article.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Articles help you to go very broad or very deep once you identified the topic&lt;/p&gt;

&lt;h3&gt;
  
  
  Books
&lt;/h3&gt;

&lt;p&gt;Books offer a huge amount of knowledge on their subjects. One good book can take you on a journey from zero knowledge to expert-level knowledge on the subject. &lt;/p&gt;

&lt;p&gt;I divide all engineering books into two categories: &lt;em&gt;"Practical"&lt;/em&gt; and &lt;em&gt;"Conceptual"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical Books&lt;/strong&gt; usually contain many executable code examples. The books teaching programming languages are the most obvious examples of "practical" books. For example, &lt;a href="https://learning.oreilly.com/library/view/head-first-kotlin/9781491996683/"&gt;Head First Kotlin&lt;/a&gt; contains many executable examples, as well as many pen-and-paper exercises for the readers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conceptual Books&lt;/strong&gt;lean heavily on illustrative diagrams and are sparse on executable code examples. Consider &lt;a href="https://www.amazon.co.uk/Software-Architecture-Modern-Tradeoff-Analysis/dp/1492086894/"&gt;Software Architecture: The Hard Parts&lt;/a&gt; as an example. Getting familiar with concepts like &lt;em&gt;"Architectural Decomposition"&lt;/em&gt; or &lt;em&gt;"Distributed transactions"&lt;/em&gt; is vital for being a knowledgeable engineer, but it is not something you can immediately practice by running a code example.&lt;br&gt;
Conceptual books are perfect for reading on the go when you are away from your laptop. Think commute or periods of waiting. Got a spare 15 minutes and a seat? That's a reading opportunity right there.&lt;/p&gt;

&lt;p&gt;When it comes to picking the next book, it can be challenging. Sure, there are the well-known engineering &lt;em&gt;"must-reads"&lt;/em&gt; like &lt;a href="https://learning.oreilly.com/library/view/clean-code-a/9780136083238/"&gt;Clean Code&lt;/a&gt; and &lt;a href="https://learning.oreilly.com/library/view/domain-driven-design-tackling/0321125215/"&gt;Domain Driven Design&lt;/a&gt;. Their reputation precedes them, and they certainly deserve your time. But what about the latest releases? I have a few suggestions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Social media, particularly Twitter, can help. If you follow industry leaders or fellow engineers, you'll inevitably come across book recommendations. A Social media osmosis in action.&lt;/li&gt;
&lt;li&gt;Job-based initiatives like &lt;em&gt;"engineering libraries"&lt;/em&gt; in the office or a Slack channel functioning like a book club. Both can provide valuable and relevant reading suggestions.&lt;/li&gt;
&lt;li&gt;Occasionally browsing new releases sections of major publishers such as &lt;a href="https://www.oreilly.com/whats-new.html"&gt;O'Reilly&lt;/a&gt;, &lt;a href="https://www.manning.com/"&gt;Manning&lt;/a&gt;, and &lt;a href="https://www.packtpub.com/"&gt;Packt&lt;/a&gt; can be a direct source for filling your to-read list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be conservative in estimating how many books you can read in a year. If not sure, aim for 2–3 books. Technical books aren't easy to read. While I might breeze through a novel in two weeks, I never managed to do the same with an engineering book.&lt;/p&gt;

&lt;h3&gt;
  
  
  Video Courses
&lt;/h3&gt;

&lt;p&gt;They combine auditory and visual learning, distinguishing them from text-based articles and books.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://frontendmasters.com/"&gt;Front End Masters&lt;/a&gt; excel in their 'code-along' recorded workshops on various topics, often beyond the scope of front-end development. For example, &lt;a href="https://frontendmasters.com/courses/rust/"&gt;The Rust Programming Language&lt;/a&gt; is one of such courses.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.udemy.com/li"&gt;Udemy&lt;/a&gt; has a huge number of courses, but they can be hit or miss depending on the instructor. One example of a hit is &lt;a href="https://www.udemy.com/course/pragmatic-system-design/"&gt;a bestselling course Pragmatic System Design&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.linkedin.com/learning/"&gt;LinkedIn Learning&lt;/a&gt; curates a broad spectrum of courses catering to various professional domains.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When on the hunt for a new course, I usually skim through the platforms mentioned above, searching for specific topics related to my current learning area of interest, which can be something like &lt;em&gt;"learning intermediate and advanced SQL"&lt;/em&gt; or &lt;em&gt;"Event-driven architecture"&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conference Talks
&lt;/h3&gt;

&lt;p&gt;Most of the talks presented at any given tech conference become available online a few weeks or months after the event. Conference talks have a dual role of educating and entertaining. They are valuable for broadening your knowledge horizons. As with any learning material, not all talks are equally interesting. While some presentations shine due to the excellent combination of visuals and narration, others might fall short when watched in isolation, without the context of the tech conference at which they were presented.&lt;/p&gt;

&lt;p&gt;My recently watched favorites include &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=x2-rSnhpw0g&amp;amp;t=1s"&gt;Visualizing software architecture with the C4 model - Simon Brown, Agile on the Beach 2019&lt;/a&gt; and - &lt;a href="https://www.youtube.com/watch?v=ZPIPPRjwg7Q"&gt;Debugging Treasure Hunt - Suzy Mueller, GopherCon 2021&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To curate a list of talks for future viewing, I visit websites like &lt;a href="https://confs.tech/"&gt;confs.tech&lt;/a&gt; or &lt;a href="https://dev.events/"&gt;dev.events&lt;/a&gt;, focusing on Backend engineering and Golang conferences. From there, it's a dive into individual conference websites to choose the talks to my &lt;em&gt;"watch later"&lt;/em&gt; list. I give preference to conferences with shorter 30-minute talks over longer 50-minute sessions. As I think they provide better value to time ration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hands-on Project
&lt;/h3&gt;

&lt;p&gt;Active practice is an essential form of learning. While acquiring information is vital, applying it ensures that it's converted into a skill that stays with you.&lt;/p&gt;

&lt;p&gt;Sometimes, the newly acquired knowledge can be immediately used in daily engineering tasks at work. Unfortunately, it is not always the case. So you need to find other ways to practise.&lt;/p&gt;

&lt;p&gt;In my early days as an engineer, I frequently worked on mini projects to improve and practise my skills. I still do such mini-projects, but less often. However, I do recommend it as the most straightforward way to practice, especially for junior engineers.&lt;/p&gt;

&lt;p&gt;At the current stage of my career, activities such as writing articles or preparing engineering talks also serve as practical, hands-on learning for me. I reinforce my own knowledge by sharing it with others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding Time
&lt;/h2&gt;

&lt;p&gt;First, stating the obvious, finding time for studying when you have a full-time job and various outside-of-work responsibilities is hard. And It will never be easy. But it is necessary as the key to successfully learning anything lies in continuity. Regular, even if brief, learning intervals can lead to significant progress over time.&lt;/p&gt;

&lt;p&gt;Some employers recognize the value of continuous learning and upskilling and have initiatives like &lt;em&gt;"Half-Day Learning Fridays"&lt;/em&gt;. If you're fortunate to work for such an employer, it's a boon. However, if not, you're in the majority, and it's up to you to carve out time for personal upskilling.&lt;/p&gt;

&lt;p&gt;Taking myself as an example, I dedicate 6–12 hours weekly, outside of work, to learning. This might seem like a big number, but it doesn't feel like a chore most of the time, thanks to my general passion for learning.&lt;/p&gt;

&lt;p&gt;I've found that bundling these hours over 3 days from Friday to Sunday - works best for me. My previous attempts to study in the evenings after work often made me miserable. Attempts to wake up early and study before work resulted in me being sleepy and starting the work day while already tired. &lt;/p&gt;

&lt;p&gt;Choosing your learning days and hours around what feels most sustainable for you is essential. There's no one-size-fits-all approach. Remember, the continuous learning journey is about personal growth at your own pace, free from external timelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracking Progress
&lt;/h2&gt;

&lt;p&gt;With tangible goals like &lt;em&gt;"preparing for a job interview"&lt;/em&gt;, you have a clear objective and a deadline. However, when you're aiming &lt;em&gt;"to stay reasonably up-to-date with the state of software engineering"&lt;/em&gt;, the goal is vague, and there's no set timeframe to achieve it.&lt;/p&gt;

&lt;p&gt;To manage the ambiguity of ongoing learning, I came up with the idea of &lt;a href="https://lulaleus.notion.site/lulaleus/e5b39a4bf27b4ebfac4283186628598b?v=4338c76020b94de296e5b7f179cddd01"&gt;a Learning board on Notion&lt;/a&gt;, inspired by a kanban methodology. I've been using my board successfully for the past two years. The board uses columns to represent progress stages and rows for categorizing the learning medium. I want to particularly note that there are no &lt;em&gt;"sprints"&lt;/em&gt; on my board. I use the same board for an entire calendar year.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vZifKYSx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ffqdc41b845iwr98fu7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vZifKYSx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ffqdc41b845iwr98fu7f.png" alt="Image description" width="800" height="541"&gt;&lt;/a&gt;&lt;em&gt;The essential structure of a learning board.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's how I interact with my board:&lt;br&gt;
&lt;strong&gt;On-the-Fly Updates&lt;/strong&gt;: Whenever there's a change in the status of a learning item, I move the card. For instance, when I start a video course or finish an article, I update its status.&lt;br&gt;
&lt;strong&gt;Weekly Board Check&lt;/strong&gt;: Every Sunday, I dedicate 20 minutes to review the board. This routine helps in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assessing my progress, like how many pages of the current-read book I read this week.
Thinking about the upcoming week and picking out items I plan learn.&lt;/li&gt;
&lt;li&gt;Evaluating the &lt;em&gt;"No status"&lt;/em&gt; column, either promoting items to &lt;em&gt;"Not started"&lt;/em&gt; or removing ones that no longer align with my interests.&lt;/li&gt;
&lt;li&gt;Hunting for the new materials. if I have some topic on my mind that I want to learn more about. Or if my &lt;em&gt;"No status"&lt;/em&gt; column looks particularly empty.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The learning board offers a clear snapshot of my activities. It helps me plan what I want to learn and how. It also provides a log of what I've learned so far in the current calendar year.&lt;/p&gt;

&lt;p&gt;If you like my learning board approach, you can &lt;a href="https://lulaleus.notion.site/lulaleus/e5b39a4bf27b4ebfac4283186628598b?v=4338c76020b94de296e5b7f179cddd01"&gt;duplicate it as a Notion template&lt;/a&gt; and create your own unique learning board based on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I believe that commitment to continuous learning and upskilling is a non-negotiable requirement for being a great software engineer. So, crafting an efficient and structured approach to learning is crucial. Through trial and error, I've arrived at the method shared above.&lt;/p&gt;

&lt;p&gt;Although my learning process is already  well-defined, I'm always looking for ways to refine it even further. I welcome any suggestions or feedback you can give me in the comments.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>softwaredevelopment</category>
      <category>career</category>
    </item>
    <item>
      <title>Top 3 Design Patterns for a Large Go Codebase</title>
      <dc:creator>Lula Leus</dc:creator>
      <pubDate>Wed, 05 Jul 2023 20:40:12 +0000</pubDate>
      <link>https://forem.com/lulaleus/top-3-design-patterns-for-a-large-go-codebase-mo4</link>
      <guid>https://forem.com/lulaleus/top-3-design-patterns-for-a-large-go-codebase-mo4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Design patterns are often considered to be fundamental knowledge every good software engineer should possess. Maybe it is true. However, not all theoretical knowledge is useful for day-to-day work.&lt;/p&gt;

&lt;p&gt;I felt uncertain about the applicability of design patterns to my day-to-day work in a large microservice-based codebase, servicing millions of users. So I decided to investigate.&lt;/p&gt;

&lt;p&gt;I don’t aim to describe all classical software design patterns. I concentrate on the top 3 design patterns, the usage of which I notice regularly. I’ll explain what particular real-world problem each of these patterns solves.&lt;/p&gt;

&lt;h2&gt;
  
  
  A very brief history of design patterns
&lt;/h2&gt;

&lt;p&gt;Let’s refresh our knowledge of how software engineering design patterns came about. In 1994, four authors — Erich Gamma, John Vlissides, Ralph Johnson, and Richard Helm published a book &lt;a href="https://www.oreilly.com/library/view/design-patterns-elements/0201633612/" rel="noopener noreferrer"&gt;“Design Patterns: Elements of Reusable Object-Oriented Software”&lt;/a&gt;. This book earned the nickname “The Book by the Gang of Four,” later abbreviated to “the GoF book”.&lt;/p&gt;

&lt;p&gt;The GoF book contained 23 patterns categorized into three groups: Creational, Structural and Behavioural patterns. The examples for the book were written in C++ and Smalltalk. As could be expected, the described patterns were influenced by these specific languages and by software engineering needs of the time. However, the concept of patterns proved to be enduring.&lt;/p&gt;

&lt;p&gt;Today, we still refer to these 23 patterns grouped into three categories as the classic software design patterns. Example implementations for all these patterns are written in all the popular languages, including an implementation in Go. The latest is of particular interest to me since I mostly work with Go myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use design patterns?
&lt;/h2&gt;

&lt;p&gt;So design patterns exist, but why use them? They help engineers avoid reinventing the wheel when tackling commonly known or repetitively recurring problems. Additionally, design patterns help to communicate ideas between software engineers efficiently.&lt;/p&gt;

&lt;p&gt;Knowledge of patterns may help engineers in the process of getting accustomed to an unfamiliar codebase too. The codebase, no matter its size, becomes less overwhelming if what happens in it can be mind-mapped with something familiar and universal. Design patterns provide frameworks for such mapping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategy: A plan for clarity and readability
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Strategy: a plan that is intended to achieve a particular purpose”&lt;/em&gt;&lt;br&gt;
Cambridge dictionary&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In software engineering, Strategy is a behavioural design pattern that allows objects to have a set of interchangeable behaviours and the ability to choose one of them at runtime according to the current needs.&lt;/p&gt;

&lt;p&gt;The typical use-case for a Strategy pattern is an endpoint request handler. The handler’s behaviour must differ according to the request parameters, yet the complexity does not warrant separate endpoints for each case.&lt;/p&gt;

&lt;p&gt;Let’s consider a microservice called &lt;strong&gt;authorisations-report&lt;/strong&gt; as an example. It has a single endpoint &lt;em&gt;/get-report&lt;/em&gt;, which generates well… a report. Different types of reports can be requested, such as authorisation roles, authorisation policies or assignments (connections between users and their authorisations).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz828cb5z49y5bui2n6ss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz828cb5z49y5bui2n6ss.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code for this example divided between two packages — &lt;em&gt;handler&lt;/em&gt; and &lt;em&gt;report&lt;/em&gt;. handler function &lt;em&gt;GetReport&lt;/em&gt; calls &lt;em&gt;Build&lt;/em&gt; method exposed by the report package and passes to it a requested report type. The report type can be either “roles”, “policies” or “assignments”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="s"&gt;"handler"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;reportproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetReportRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;reportproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetReportResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Generate report&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReportType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;reportproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReportResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here the &lt;em&gt;report package&lt;/em&gt;. When &lt;em&gt;Build&lt;/em&gt; functions is called, it selects a strategy for report building based on the type provided.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="s"&gt;"report"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reportType&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// We choose strategy to build report&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reportBuilder&lt;/span&gt; &lt;span class="n"&gt;reporter&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;reportType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReportTypeUsers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reportBuilder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allUsersReporter&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReportTypeRoles&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reportBuilder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;roleReporter&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;constants&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReportTypePolicies&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reportBuilder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;policyReporter&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid_report_type: Invalid report type provided"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;reportBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Strategy pattern is a simple and clean way to create different behaviours without overloading the code with numerous if/else conditions, thereby maintaining clarity and readability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Facade: a way of communication with 3rd-party service providers.
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Facade (false appearance): a false appearance that makes someone or something seem more pleasant or better than they really are”&lt;/em&gt;&lt;br&gt;
Cambridge dictionary&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In software engineering, by using a facade, we can hide an inner complexity of an actual entity implementation behind a simplified outer interface, which exposes only methods needed by the external system. This provides a simple and user-friendly interface to communicate with.&lt;/p&gt;

&lt;p&gt;In microservices-based architecture, I saw this pattern being used many times for communication with 3rd party services. For example, DocuSign for managing documents or GreenHouse to assist with recruiting. Each facade is an autonomous microservice that bridges internal company services and external 3rd party API. This offers the flexibility to construct generic integrations that can be scaled up and down, monitored like any internal service, etc. I’ll look at microservice &lt;strong&gt;hr-system&lt;/strong&gt; as an example of the facade.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdc0covl4rbt79iodzr4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdc0covl4rbt79iodzr4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code example demonstrates one endpoint handler &lt;em&gt;ReadEmployee&lt;/em&gt;, responsible for getting employee by ID from external HR system using &lt;em&gt;client.GetEmployee&lt;/em&gt;. The employee data is then transformed into a protobuf object shape using &lt;em&gt;marshaling.EmployeeToProto&lt;/em&gt;, before being returned to the requester.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;HandleGETReadEmployee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;hrsystemproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GETReadEmployeeRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;hrsystemproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GETReadEmployeeResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmployeeId&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrMissingParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"employee_id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// client is based on Go net/http package and does request to 3rd party system&lt;/span&gt;
    &lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetEmployee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmployeeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to read employee"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;marshalled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;marshaling&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmployeeToProto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to marshal employee"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hrsystemproto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GETReadEmployeeResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;marshalled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use of facades provides a few benefits. Engineers are offered a limited subset of strongly-typed endpoints, where intricacies associated with request authentication, optional parameters, or object transformation are already addressed.&lt;/p&gt;

&lt;p&gt;When the need in onboarding new 3rd party integration arises, to build it is becomes a quick and easy task because comprehensive blueprint for doing so already exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fan-out/Fan-in: Leveraging concurrency for getting results faster
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Fan-out: to spread out over a wide area”&lt;/em&gt;&lt;br&gt;
The Cambridge dictionary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This design pattern belongs to the concurrency patterns group and is outside of the The GoF book. However, the pattern is ubiquitous in distributed systems. Hence I want to discuss it.&lt;/p&gt;

&lt;p&gt;The concept of this pattern is to divide a data retrieval task into multiple chunks, execute them concurrently, and then aggregate the results.&lt;/p&gt;

&lt;p&gt;An array of items, where each item should be processed somehow, is a simple but realistic example. Imagine that the array is very large or processing of items takes a long time (For example, every item produces/requires an HTTP call).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd58m1wx74ox1eupdxpsa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd58m1wx74ox1eupdxpsa.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will look at microservice &lt;strong&gt;authorisations-report&lt;/strong&gt; as an example of the use of the Fan-in/Fan-out pattern. We already discussed this microservice in Strategy design pattern section. Noting prevents the service from implementing more than one design pattern at once.&lt;/p&gt;

&lt;p&gt;Let’s say that the service received a request to produce an “assignments” report. In this service domain, assignment means a connection between company employee and authorisations granted to this employee. And assignments report is expected to provide information about all company employees and all authorisations currently granted to them.&lt;/p&gt;

&lt;p&gt;Creation of such a report requires a lot of network requests, and doing it sequentially, on employee after employee basis, took around 30 minutes to complete.&lt;/p&gt;

&lt;p&gt;Fan-out/Fan-in pattern comes to the rescue. It’s worth noting that in snipped of code, we do not spawn a Goroutine per employee since it would create more than one thousands goroutines and unhealthy spike in requests for all downstream services. We use a semaphore to limit our fanning-out width to 100 goroutines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createReportRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;employeeProfiles&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;reportRow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;numOfEmployees&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeProfiles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rowsChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;reportRow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numOfEmployees&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;concurrencyLimiter&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;semaphore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWeighted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Fan-out stage, create rows of assignment report concurrenty&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;employeeProfiles&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Acquire a "token" from semaphore, block if none available.&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;concurrencyLimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;curProfile&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rowsChan&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;reportRow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;concurrencyLimiter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// Release the "token" back to semaphore&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;concurrencyLimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;rowsChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;curProfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rowsChan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;concurrencyLimiter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Fan-in stage, all created rows go into one data structure&lt;/span&gt;
    &lt;span class="c"&gt;// As we know the exact number of rows, we can use a simple for loop&lt;/span&gt;
    &lt;span class="c"&gt;// and wait for all of them to be created and sent to the channel.&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;reportRow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numOfEmployees&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;numOfEmployees&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;assignment&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;rowsChan&lt;/span&gt;
        &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;assignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assignment&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fan-out/Fan-in is one of the most useful and ubiquitous patterns in a modern software engineering landscape because processing things one by one is just not enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap of Discussed Design Patterns
&lt;/h2&gt;

&lt;p&gt;The demonstrated use of design patterns proves that these patterns are more than theoretical constructs. They are integral to a production codebase and help maintain high coding standards by reapplying established effective patterns for solving recurrent problems.&lt;/p&gt;

&lt;p&gt;In addition to classical design patterns, concurrency patterns have become a vital part of contemporary software development. I quickly looked at this group of patterns with the widely used Fan-out/Fan-in pattern.&lt;/p&gt;

&lt;p&gt;That’s my take on design patterns that can be applied to software engineers’ day-to-day work. I’ve explored the top 3 from my experience, but the exploration doesn’t stop there. Design Patterns have evolved beyond the original 23 from The GoF, and beyond the addition of concurrency patterns. There are architectural patterns, messaging patterns, and so much more to explore!&lt;/p&gt;

</description>
      <category>go</category>
      <category>designpatterns</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Table-driven and individual subtests in Golang: which one to use</title>
      <dc:creator>Lula Leus</dc:creator>
      <pubDate>Sat, 06 Aug 2022 11:19:00 +0000</pubDate>
      <link>https://forem.com/lulaleus/table-driven-and-individual-subtests-in-golang-which-one-to-use-4k0p</link>
      <guid>https://forem.com/lulaleus/table-driven-and-individual-subtests-in-golang-which-one-to-use-4k0p</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Unit tests are an essential part of any code base, including the one at my workplace.  When an engineer adds a piece of new logic into the codebase, they are expected to add unit tests that will cover, at least, the most common scenarios of the new logic usage. Perhaps with a couple of edge cases as a cherry on the top.&lt;/p&gt;

&lt;p&gt;Testing different scenarios is important, but requires writing fairly repetitive tests. Let’s look at approaches Golang offers for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing packing of a doughnuts box
&lt;/h2&gt;

&lt;p&gt;We’ll look at two different ways to write unit tests in Golang. We will use a playful example of packing a doughnuts box. The flavours of the doughnuts in the examples, are all inspired by &lt;a href="https://www.crosstown.co.uk/"&gt;Crosstown doughnuts&lt;/a&gt;. Let’s look at the code, for which we’ll write tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation of a doughnut box&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;doughnuts_box&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;doughnutsBox&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;capacity&lt;/span&gt;  &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;doughnuts&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;knownDoughnutTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Matcha Tea"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Lime &amp;amp; Coconut (ve)"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Home Made Raspberry Jam"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Cinnamon Scroll (ve)"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"Sri Lankan Cinnamon Sugar"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;newDoughnutsBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;doughnutsBox&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;doughnutsBox&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;doughnuts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;doughnutsBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doughnuts&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;unrecognizedItems&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doughnuts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to put %d doughnuts in the box, it's only has %d doughnuts capacity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doughnuts&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doughnut&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;doughnuts&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;knownDoughnutTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doughnut&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doughnuts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doughnuts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doughnut&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;unrecognizedItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unrecognizedItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doughnut&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unrecognizedItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"the following items cannot be placed into the box: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unrecognizedItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doughnuts&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, after we familiarised ourself with the doughnut box implementation, let’s discuss how we can tests it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Testing packing the doughnuts box with table-driven tests
&lt;/h3&gt;

&lt;p&gt;Table-driven tests are the common way to write unit tests in Golang. You’ll find this style  everywhere.&lt;/p&gt;

&lt;p&gt;Table tests offer a condensed way to write test scenarios while keeping code repetition to a minimum. The syntax density is coming with the drawback of poor readability. The tests may feel elegant to write, but they are often hard to read and reason about. &lt;/p&gt;

&lt;p&gt;The table-tests are shining in situations, where the intention is to test a large number of scenarios, with clear &lt;br&gt;
&lt;em&gt;input x produces output y&lt;/em&gt; expectations. &lt;/p&gt;

&lt;p&gt;For our doughnut box example, we wrote a set of scenarios in the shape of anonymous struct &lt;code&gt;testCases&lt;/code&gt;. Then we run all of them as subtests with &lt;code&gt;t.Run&lt;/code&gt; method, inside a familiar &lt;code&gt;for loop.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation of doughnuts box table-driven tests&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;doughnuts_box&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/stretchr/testify/assert"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/stretchr/testify/require"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestPackDoughnutsBoxTableTests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Anonymous struct of test cases&lt;/span&gt;
    &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;                           &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;boxCapacity&lt;/span&gt;                    &lt;span class="kt"&gt;int&lt;/span&gt;
        &lt;span class="n"&gt;errorExpected&lt;/span&gt;                  &lt;span class="kt"&gt;bool&lt;/span&gt;
        &lt;span class="n"&gt;errorMessage&lt;/span&gt;                   &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt;                          &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;expectedNumOfDoughnutsInTheBox&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;}{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                           &lt;span class="s"&gt;"Filling the box with tasty doughnuts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;boxCapacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                    &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;errorExpected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                  &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                   &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                          &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Sri Lankan Cinnamon Sugar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Matcha Tea"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Home Made Raspberry Jam"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lime &amp;amp; Coconut (ve)"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;expectedNumOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                           &lt;span class="s"&gt;"Attempt to fill the box with too many doughnuts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;boxCapacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                    &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;errorExpected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                  &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                   &lt;span class="s"&gt;"failed to put 5 doughnuts in the box, it's only has 4 doughnuts capacity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                          &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Sri Lankan Cinnamon Sugar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Matcha Tea"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Home Made Raspberry Jam"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lime &amp;amp; Coconut (ve)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lime &amp;amp; Coconut (ve)"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;expectedNumOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                           &lt;span class="s"&gt;"Attempt to put a giant chocolate cookie into the box"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;boxCapacity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                    &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;errorExpected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                  &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                   &lt;span class="s"&gt;"the following items cannot be placed into the box: [Giant Chocolate Cookie]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;                          &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Sri Lankan Cinnamon Sugar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Giant Chocolate Cookie"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;expectedNumOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// each test case from  table above run as a subtest&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// Arrange&lt;/span&gt;
            &lt;span class="n"&gt;box&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newDoughnutsBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;boxCapacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c"&gt;// Act&lt;/span&gt;
            &lt;span class="n"&gt;numOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c"&gt;// Assert&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errorExpected&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expectedNumOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We looked at the "happy path" test case and two test cases for errors we expect to be common - trying to put too many doughnuts into a box and an attempt to put something that isn't doughnut into the box.&lt;/p&gt;

&lt;p&gt;Next, we'll look at how we can re-write the same tests in different style.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing packing the doughnuts box with individual subtests
&lt;/h3&gt;

&lt;p&gt;Writing tests scenarios as an individual subtests is less common in Golang. This fact is regretful, in my opinion.  But still there are enough of examples of this syntax.&lt;/p&gt;

&lt;p&gt;Individual subtests syntax, unlike table tests, favours readability overall “code dryness”. The tests may look more repetitive, but each individual subtest represents an individual “story”. As such, it is easier to follow behaviour-driven testing principles with individual subtests than with table-driven tests.&lt;/p&gt;

&lt;p&gt;In our small example, all arrangements are made within the individual subtests.  In more complex examples, the state shared between subtests can be initialised in the body of the parent test. And repetitive setup/teardown can be extracted into helper functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation of Donuts box test as individual subtests&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;doughnuts_box&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/stretchr/testify/assert"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/stretchr/testify/require"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestPackDoughnutsBoxSubtests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It fills the box with tasty doughnuts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Arrange&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Sri Lankan Cinnamon Sugar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Matcha Tea"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Home Made Raspberry Jam"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lime &amp;amp; Coconut (ve)"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;box&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newDoughnutsBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Act&lt;/span&gt;
        &lt;span class="n"&gt;numOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It fails to fill the box with too many doughnuts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Arrange&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Sri Lankan Cinnamon Sugar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Matcha Tea"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Home Made Raspberry Jam"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lime &amp;amp; Coconut (ve)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lime &amp;amp; Coconut (ve)"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;box&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newDoughnutsBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Act&lt;/span&gt;
        &lt;span class="n"&gt;numOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"failed to put 5 doughnuts in the box, it's only has 4 doughnuts capacity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It fails to put a giant chocolate cookie into the box"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Arrange&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Sri Lankan Cinnamon Sugar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Giant Chocolate Cookie"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;box&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newDoughnutsBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Act&lt;/span&gt;
        &lt;span class="n"&gt;numOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;box&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"the following items cannot be placed into the box: [Giant Chocolate Cookie]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numOfDoughnutsInTheBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We wrote the same three test cases - happy path and two common error scenarios as individual sub-tests. In our example, they even took approximately the same number of code lines. 58 lines for individual subtests, comparing to 63 lines of table-driven tests example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Now, when examples for two styles for unit tests are presented, it is time to decide which one to use and when. &lt;/p&gt;

&lt;p&gt;As an engineer, you should exercise your better judgement on how to write unit tests and what syntax suits best. You can use the following little diagram to help you to decide, which syntax to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ne5M7Nar--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zhvnfbxuajp6zcolc6q5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ne5M7Nar--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zhvnfbxuajp6zcolc6q5.png" alt="Diagram helper to choice between table-driven and individual sub-test" width="784" height="948"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope the diagram helps. If you have a strong opinion for one syntax over another or have your own way of writing Golang unit tests, please share in the comments!&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>beginners</category>
      <category>unittest</category>
    </item>
  </channel>
</rss>
