<?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: Guillermo Fuchter</title>
    <description>The latest articles on Forem by Guillermo Fuchter (@g-fuchter).</description>
    <link>https://forem.com/g-fuchter</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%2F2017468%2F8d23c8a3-468e-4ae7-b835-5a22fe577b18.jpg</url>
      <title>Forem: Guillermo Fuchter</title>
      <link>https://forem.com/g-fuchter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/g-fuchter"/>
    <language>en</language>
    <item>
      <title>How to Survive AI as a Developer</title>
      <dc:creator>Guillermo Fuchter</dc:creator>
      <pubDate>Sun, 08 Mar 2026 22:31:50 +0000</pubDate>
      <link>https://forem.com/g-fuchter/how-to-survive-ai-as-a-developer-5f7a</link>
      <guid>https://forem.com/g-fuchter/how-to-survive-ai-as-a-developer-5f7a</guid>
      <description>&lt;p&gt;In his latest sketch comedy, "&lt;a href="https://www.youtube.com/watch?v=xE9W9Ghe4Jk" rel="noopener noreferrer"&gt;Shipping a button in 2026&lt;/a&gt;", the YouTuber Kai Lentit depicts a software engineer debating with ghostly caricatures of different software developer archetypes, on how he should go about implementing a new feature for his software. Each one convincing him to pick a certain programming language, framework, and or technology to implement his basic software feature. In the end, after a lot of back-and-forth, and frustrated by the amount of choice and how the scope has expanded, he finally decides to open his AI code editor and let an AI model take care of it instead.&lt;/p&gt;

&lt;p&gt;The punchline resonates with many developers, because it mirrors our new reality where we can have AI write code in programming language and frameworks we are not familiar with. AI has created a new layer in the software development process, where natural language can be compiled into working software code, and with the latest models and tools, it can debug, refactor and iterate. This has lead many people to prophesy that human programmers will be replaced by AI.&lt;/p&gt;

&lt;p&gt;What these supposed prophets miss is the most important step of software engineering; modeling the domain using meaningful and consistent natural language. modeling and language developing is the key step that will determine if the code that AI produces will result in a codebase that becomes a nightmare to work with, even for very capable AI models, or if it becomes a legible codebase, where code changes integrate smoothly, without churning millions of AI tokens.&lt;/p&gt;

&lt;p&gt;Modeling the domain is a process in which developers and domain experts collaborate to create a mental model of a domain that is to be translated into code. In his book "Domain Driven Design", Eric Evans Eric Evans also calls this process 'knowledge crunching', and describes how language is cultivated based on the model of a domain. As an example of the importance of modeling a domain, think of trying to build an e-commerce website. We, as programmers, will find ourselves having to define core concepts such as 'order', 'shopping cart', 'receipt', 'shipment', and 'purchase'. A person who does not have context about this domain might use the terms 'order'  and 'shipment' interchangeably, given that a shipment is always linked to an order. But a good software model &lt;strong&gt;must&lt;/strong&gt; define and differentiate these terms, otherwise developing the software for the domain becomes hard, and the resulting codebase ends up being a confusing mess riddle with bugs.&lt;/p&gt;

&lt;p&gt;Coming back to AI, you can imagine how even the most advanced and sophisticated models would have difficulty fulfilling a request to develop a new feature, or update an existing one when the language used to prompt it is based on a poor domain model, or a non-existing one. Picture asking AI to 'fix your ordering system' on a codebase where the term 'order' is being used interchangeably with 'shipment'. You should not be surprised if the AI model ends up making assumptions and changing the behavior you did not expect, or even worse, breaking how the 'shipment' logic works. Maybe you get the expected result after tweaking your prompts and giving the AI enough context on your poorly defined domain model. But once you submit your code changes and close the session with the AI agent, all the gained context is flushed away down the toilet, and the only thing remaining is a confusing mess in the form of "working "code. You might be able to repeat this process many times, but with time you will notice that the process will start taking longer. The AI model will require you to provide more context every time, and you will find yourself nudging it more often to get it to produce your desired behavior while it burns through your budget in tokens.&lt;/p&gt;

&lt;p&gt;In conclusion, this advancement of AI for software development has made writing code easier and accessible, to the point where deep knowledge of programming languages, frameworks, and libraries are no longer requisites. On the other hand, it has highlighted the importance for developers to collaboratively model the domain before attempting to write any code. With a good domain model, prompts become easier and more meaningful. Codebases better reflect the domain models and become simpler for developers and AI models to change it. For the developers looking to survive in the age of AI, my advice is to start focusing on how you model your domain, and how you can more effectively do it in collaboration with domain experts. Here are some resources that can help you with that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.amazon.de/-/en/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215" rel="noopener noreferrer"&gt;Domain Driven Design by Eric Evans&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.de/-/en/Learning-Domain-Driven-Design-Aligning-Architecture/dp/1098100131/" rel="noopener noreferrer"&gt;Learning Domain Driven Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.eventstorming.com/" rel="noopener noreferrer"&gt;Event Storming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.de/-/en/Stefan-Hofer-ebook/dp/B0DFX5GS9Q/" rel="noopener noreferrer"&gt;Domain Story Telling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>My First Experiences With Test-Driven Development</title>
      <dc:creator>Guillermo Fuchter</dc:creator>
      <pubDate>Mon, 15 Dec 2025 16:43:12 +0000</pubDate>
      <link>https://forem.com/g-fuchter/my-first-experiences-with-test-driven-development-1pk9</link>
      <guid>https://forem.com/g-fuchter/my-first-experiences-with-test-driven-development-1pk9</guid>
      <description>&lt;p&gt;&lt;em&gt;Love it or hate it, Test-Driven Development (TDD) is a very popular software development method used within the industry. Here I share my experiences with TDD and some neat ideas I learned along the way.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I was aware of TDD, mostly from people talking about it negatively, claiming that TDD does not leave space for design. Popular software developer streamer, The Primeagen, talked &lt;a href="https://youtu.be/kJWsFWY25GA?si=srLNjqwyl_NkDXla&amp;amp;t=128" rel="noopener noreferrer"&gt;on his podcast&lt;/a&gt; about trying out TDD for his game and finding it difficult to integrate his Test-Driven developed module to the game he was developing. On the other hand, well-known software developers like Kent Beck &lt;a href="https://martinfowler.com/bliki/TestDrivenDevelopment.html" rel="noopener noreferrer"&gt;have written extensively&lt;/a&gt; about TDD's positive effects on the software development process.&lt;/p&gt;

&lt;p&gt;With this in mind, I decided to give TDD a go for my day-to-day coding tasks. At first I found it frustrating, feeling the friction of writing tests before the code itself. But when I got through the initial phase, and I started to see my test pass, it gave me a great feeling of accomplishment and satisfaction. I noticed that because of the initial friction, I did end up spending more time on the task that I would normally have, but that extra time spent was reflected in the higher quality tests. Not only did the tests cover more edge-cases, but they were easier to read. When I used to write tests after writing the code, I found myself rushing them to get my code deployed sooner. This led to lower-quality tests, that did not test many edge cases, and were difficult for other developers to read and understand. Funnily enough, in some rare cases, the test cases were so badly written that they would succeed when ran, even when the module they were testing failed! I managed to catch those scenarios accidentally when I was updating the module weeks later. This could have been avoided if I had used TDD sooner.&lt;/p&gt;

&lt;p&gt;Applying TDD has been beneficial for me, and it has led me to discover ideas, practices, tricks, and tips for writing more maintainable code that complement TDD. In this post I would like to share those with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests as Documentation
&lt;/h2&gt;

&lt;p&gt;The well-known manifesto for agile web development is composed of 4 values, one of them being valuing "working software before comprehensive documentation". The main idea is that we are in the business to create software, not comprehensive documentation, therefore working software should take main stage. The main reason is that documentation can only work if it gets constantly updated, so it reflects the source of truth, and maintaining documentation is work intensive. Maintaining an up-to-date documentation would require developers to update the documentation every time that they change their code. On the other hand, documenting what your software does is beneficial because the more your software grows, and the more people get involved in the maintenance and construction of such software, the need to have some kind of software documentation gets stronger.&lt;/p&gt;

&lt;p&gt;Some developers may claim that "well-written code is self-documenting", but this kind of idealism is unrealistic. Tech debt builds up quite quickly and naming software modules is very easy to get wrong. Fortunately, I found that well-written test make for great documentation. Tests are supposed to convey how a code module behaves, and that makes for great documentation, provided that tests are written with a good structure and using descriptive test cases' names. Additionally, writing tests as if they were documentation results in more maintainable and readable test code. To achieve this I found useful following these tips:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Make use of nested test cases (if you framework allows it)
&lt;/h3&gt;

&lt;p&gt;Many testing frameworks allow for nesting your test cases. This makes it easier to write a permutation of test scenarios without repeating yourself. It also allows you to organize all your test case's setup code, so it is kept lean and descriptive. Here is an example written with the jest framework for a user deletion use case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Given a user with the admin role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;UserFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not be able to get deleted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useCase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserDeletionUseCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;toReject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&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;h3&gt;
  
  
  2. Keep your test cases focused on behavior rather than implementation
&lt;/h3&gt;

&lt;p&gt;Test cases that describe how a module should work from the point of view of a consumer, are the easiest to read and understand. When you create and describe your test cases with a focus on implementation, then it is easily understandable only for the person who wrote the module. With this in mind, I like to try to write my test cases as if my product owner were the one reading the tests themselves.&lt;/p&gt;

&lt;p&gt;Keeping tests focused on the functionality has additional advantages that I will describe below&lt;/p&gt;

&lt;h2&gt;
  
  
  Gray Box Testing
&lt;/h2&gt;

&lt;p&gt;Black box testing is the method of testing where you evaluate the functionality of a module without knowledge of its internal structure or implementation. White box testing is the opposite, where the internal structure is known and used to derive test cases. While black boxing can only be done with high-level tests such as end-to-end tests, or certain integration tests, I believe that unit tests should be approached with a gray box testing method. This means that we mock as little as we need to, and we try to avoid assertion on a module's internal workings. By doing this, we are focusing on the function of the module rather than its implementation.&lt;/p&gt;

&lt;p&gt;Tests that are focused too much on the implementation are brittle and harder to read for the person not writing the module. One of the biggest advantages of writing tests is that it is supposed to make refactoring easier by reassuring the developer that the refactoring does not change the behavior in an unexpected way. By having brittle tests, that advantage is lost. This is because the developer refactoring code is forced to change 20 different test cases, and it becomes difficult to distinguish if the failing test is due to an unexpected result of the test, or due to a test that is too coupled with a specific implementation. Focusing on the behavior make tests more robust to small changes, and makes the test failure more meaningful.&lt;/p&gt;

&lt;h2&gt;
  
  
  London Style: Outside-In Testing
&lt;/h2&gt;

&lt;p&gt;Described in many places as the "London Style" of TDD, I like to start my tests from the "outside-in". This means I start writing tests for the higher level modules, mocking interfaces for modules that don't exist yet, and work myself down to the lower modules. For this to work, I need to define my interfaces beforehand, which adds to the friction, but this prevents me from building the wrong interfaces by forcing a consumer-first view. If I start the other way around, I risk running into the same issue that the Primeagen complained about. Writing interfaces that are good for testing but don't integrate well with other modules.&lt;/p&gt;




&lt;p&gt;My website: &lt;a href="https://www.fuchter.dev" rel="noopener noreferrer"&gt;https://www.fuchter.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>tdd</category>
    </item>
    <item>
      <title>Lessons From "Dependency Injection Principles, Practices, and Patterns"</title>
      <dc:creator>Guillermo Fuchter</dc:creator>
      <pubDate>Sun, 07 Dec 2025 22:22:08 +0000</pubDate>
      <link>https://forem.com/g-fuchter/lessons-from-dependency-injection-principles-practices-and-patterns-48li</link>
      <guid>https://forem.com/g-fuchter/lessons-from-dependency-injection-principles-practices-and-patterns-48li</guid>
      <description>&lt;p&gt;&lt;em&gt;Book review of &lt;a href="https://www.manning.com/books/dependency-injection-principles-practices-patterns" rel="noopener noreferrer"&gt;"Dependency Injection Principles, Practices, and Patterns"&lt;/a&gt; and lessons I learned from reading it.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;My first job as a software developer was writing C# for a software development agency that worked very closely with Microsoft. As a junior engineer, I had a basic notion of object-oriented programming and SOLID principles, but I was puzzled every time I opened a project that used .NET dependency injector container. Why are we writing an interface for everything? Why aren't we instantiating instances inside of classes? Why are we passing all instances through the constructor? It all seemed very bureaucratic. I didn't understand why we were following these strict rules that added so much code, when we could keep the code lean and simple by getting rid of those boiler-plate interfaces, and instantiating the instances of a class inside where they were going to be used.&lt;/p&gt;

&lt;p&gt;Fast-forward a couple of years, while working for another company, I decided to pick up "Dependency Injection Principles, Practices, and Patterns". I remember the book showing up in the background of a &lt;a href="https://www.youtube.com/@ChristopherOkhravi" rel="noopener noreferrer"&gt;Youtuber's video&lt;/a&gt;. At the time, I thought that reading it could help me introduce some more structure and order to our projects. Part of me was curious to know if the book could answer the questions that plague me all the way back to my C# days. After reading the book, I can say it did answer all of my questions and more. It has helped me have a much better understanding of object-oriented programming and software design as a whole.&lt;/p&gt;

&lt;p&gt;The book authors, Steven van Deursen and Mark Seeman, do a great job of explaining central concepts to dependency injection such as "decoupling", "cohesion", and how they relate to the SOLID principles. They provide examples of dependency injection pattern,s common "anti-patterns", and "code smells", all of which help illustrate their main advantages of dependency injection to the reader. The book is very well written, and I highly recommend it to anyone working with object oriented programming.&lt;/p&gt;

&lt;p&gt;Having introduced the book, I would like to share with you 3 ideas from this book that have had the biggest impact on how I approach software development. Beware, I am not aiming to boil down the book, or dependency injection to 3 ideas. If you look to understand dependency injection, and all of its benefits, I would encourage you to read the book.&lt;/p&gt;

&lt;h2&gt;
  
  
  Low Coupling
&lt;/h2&gt;

&lt;p&gt;The book introduces the concept of coupling with an analogy to a hotel's hair dryer. Many hotels' hair dryer's are wired directly into the socket. Like code that is highly coupled together, it is a pain to fix or change. When the hair dryer breaks, an electrician has to come, switch off the electricity in the room, and de-solder the cabling before they can start replacing the hair dryer. With highly coupled code, the process can be very similar; having to change other modules before you can replace the module that needs fixing or refactoring.&lt;/p&gt;

&lt;p&gt;In contrast to the direct-wired hair dryer, a hair dryer with a plug is easier to replace; all you have to do is unplug it from the wall socket. Loosely coupled software behaves the same; it is easier to replace, remove, and maintain.&lt;/p&gt;

&lt;p&gt;Maintainability is a very important aspect of software development. A software solution that is not maintainable means that it has a very high cost to change, and for business that means software features being released less often. Loosely coupled code improves a project's maintainability which enables the development of new features at a faster pace.&lt;/p&gt;

&lt;h2&gt;
  
  
  High Cohesion
&lt;/h2&gt;

&lt;p&gt;The authors touch upon the SOLID principles, and the principle that gets mentioned the most is the "Single Responsibility Principle", which they define it in the following way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Single Responsibility Principle (SRP) states that each class should have only one reason to change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In relation to the Single Responsibility Principle (SRP), the authors define cohesion and how cohesion allow us to determine if a module violates SRP.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cohesion is defined as the functional relatedness of the elements of a class or module. The lower the amount of relatedness, the lower the cohesion; and the lower the cohesion, the greater the possibility a class violates the SRP.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When aiming to write loosely coupled code, the Single Responsibility Principle becomes an invaluable guideline that helps us achieve that. The loose coupling has to take place with modules that have a high level of cohesion. Otherwise you have a difficult to understand software solution, and that impacts the maintainability negatively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Volatile and Stable Dependencies
&lt;/h2&gt;

&lt;p&gt;Although loosely coupled code contributes to a more maintainable code base, it also has a cost. That cost is having more "seams" in your code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Everywhere you decide to program against an Abstraction instead of a concrete type, you introduce a Seam into the application. A Seam is a place where an application is assembled from its constituent parts, similar to the way a piece of clothing is sewn together at its seams.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because of this cost, it is important to introduce seams only where they are necessary, like for volatile dependencies. A volatile dependency, as opposed to a stable one, is a dependency that meets one of the following criteria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The dependency runs in a different environment, like in a different machine or different process within a machine. An example would be a database.&lt;/li&gt;
&lt;li&gt;The dependency does not exist or is under development.&lt;/li&gt;
&lt;li&gt;The dependency contains nondeterministic behavior.&lt;/li&gt;
&lt;li&gt;New versions may contain breaking changes.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;There are so many other concepts I've learned from reading this book that I haven't added here. It is an easy read thanks to its structure, explanations, and analogies. I would recommend everyone to buy it, read it at least once, and find a space in your bookshelf to have it at hand for whenever a question pops up.&lt;/p&gt;

</description>
      <category>books</category>
    </item>
    <item>
      <title>DDD CRUD-Like Repository</title>
      <dc:creator>Guillermo Fuchter</dc:creator>
      <pubDate>Mon, 24 Nov 2025 16:38:06 +0000</pubDate>
      <link>https://forem.com/g-fuchter/ddd-crud-like-repository-1a9i</link>
      <guid>https://forem.com/g-fuchter/ddd-crud-like-repository-1a9i</guid>
      <description>&lt;p&gt;The repository pattern is an essential part of object-oriented software development. It has become the most popular abstraction to retrieve data from the database and map them into business objects (Aggregates). &lt;/p&gt;

&lt;p&gt;Lately I have noticed that many developers choose to restrict their repository to follow a CRUD (Create, Read, Update, and Delete) pattern, where the methods' names are generic and contain a verb associated with CRUD such as &lt;code&gt;get&lt;/code&gt; or &lt;code&gt;delete&lt;/code&gt;. The methods are highly versatile by accepting a object parameter with many properties so the consumer ca re-use the method in many different scenarios.&lt;/p&gt;

&lt;p&gt;Example of a User repository interface (typescript):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IUserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern seem to be loosely inspired by Eric Evan's description of a specification-based repository.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A SPECIFICATION is a way of allowing a client to describe (specify) what it wants without concern for how it&lt;br&gt;
will be obtained in the process creating an object that can actually carry out the selection&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The issue comes when constraining repositories to only follow a specification / CRUD interface. Methods suddenly have to cover many cases and they become bloated. Additionally, the method names do not convey the same intent as compared to "hard-coded" methods&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;playerRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPlayer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;highScore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;playerRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPlayerFromUSAWithHighScore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, we can see the two different approaches. The "Specification-Based" does not convey the intent very well. It is not obvious if it is retrieving a Player from the USA &lt;strong&gt;and&lt;/strong&gt; with a high score of 500, or if it is retrieving a Player from the USA &lt;strong&gt;or&lt;/strong&gt; with a high score of 500.&lt;/p&gt;

&lt;p&gt;Additionally, Eric Evans pointed out that we should allow for repositories to contain hardcoded methods, so as to maintain clarity in the domain design.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Even a REPOSITORY design with flexible queries should allow for the addition of specialized hard-coded&lt;br&gt;
queries. These might be convenience methods that encapsulate an often-used query, or a non-object query&lt;br&gt;
such as mathematical summaries of selected objects. Frameworks that don’t allow for such contingencies&lt;br&gt;
tend to distort the domain design or get bypassed by developers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having said that, it is important for hardcoded methods not to encapsulate the definition of domain terms. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IArticleRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getMostPopularArticles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;In this example, we are defining what a "Popular" article is within the implementation of a repository, which should belong as an infrastructure concern. We are violating the segregation of concern.&lt;/p&gt;

&lt;p&gt;Finally, I would like to point out that the specification-based example given here does not follow Eric Evan's example of what a specification-based query should look like. It just happens to be the most common repository structure I come across.&lt;/p&gt;

&lt;p&gt;If you're curious, this is an example of a specification-based repository query given by Eric Evans in his book:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;criteria&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Criteria&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;criteria&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TradeOrder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SECURITY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WCOM&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;criteria&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TradeOrder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ACCOUNT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tradeOrderRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matching&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;criteria&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a href="https://a.co/d/bSRQea2" rel="noopener noreferrer"&gt;Domain-Driven Design by Eric Evans&lt;/a&gt;&lt;br&gt;
&lt;a href="https://fuchter.dev" rel="noopener noreferrer"&gt;My website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ddd</category>
      <category>cleancode</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>How to Add MinIO as a Service in a GitLab CI Job</title>
      <dc:creator>Guillermo Fuchter</dc:creator>
      <pubDate>Mon, 09 Sep 2024 17:09:45 +0000</pubDate>
      <link>https://forem.com/g-fuchter/how-to-add-minio-as-a-service-in-a-gitlab-ci-job-4fe</link>
      <guid>https://forem.com/g-fuchter/how-to-add-minio-as-a-service-in-a-gitlab-ci-job-4fe</guid>
      <description>&lt;p&gt;You recently added MinIO to your back-end web API to store the invoices for your ground-breaking app. You write the the smoke test for it locally, executing it with no error, but when the time comes for the GitLab CI Job to execute the smoke test, it fails. You have forgotten to add the MinIO to your GitLab CI job, so the app can't connect to any bucket. Don't worry, I'll show you how to add MinIO server as a service to your GitLab CI smoke test job, so it can pass with flying colors.&lt;/p&gt;

&lt;h2&gt;
  
  
  MinIO Image
&lt;/h2&gt;

&lt;p&gt;For our service, we will be using &lt;code&gt;bitnami/minio&lt;/code&gt; &lt;a href="https://hub.docker.com/r/bitnami/minio" rel="noopener noreferrer"&gt;docker image&lt;/a&gt;, since it implements the &lt;code&gt;MINIO_DEFAULT_BUCKETS&lt;/code&gt; environment variable. This variable will allow us to create default buckets without having to execute any scripts, or download any clients to create those buckets. If your smoke tests / CI Job does not rely on buckets, then you can use another image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Service
&lt;/h2&gt;

&lt;p&gt;Beside the &lt;code&gt;MINIO_DEFAULT_BUCKETS&lt;/code&gt;, you will have to set the following environment variables within the service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MINIO_ROOT_USER&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Previously known as &lt;code&gt;MINIO_ACCESS_KEY_ID&lt;/code&gt;, but it was changed with the newest versions of MinIO. Do not use &lt;code&gt;MINIO_ACCESS_KEY_ID&lt;/code&gt; as a variable since it is deprecated.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;MINIO_ROOT_PASSWORD&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Previously known as &lt;code&gt;MINIO_SECRET_ACCESS_KEY&lt;/code&gt; and it also has been deprecated&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;MINIO_DOMAIN&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Domain where you MinIO is being hosted. In this case, it should be localhost, since we are accessing it within the job.
Additionally, don't forget to add an alias to your service, so it can be accessible with the endpoint.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Result
&lt;/h2&gt;

&lt;p&gt;Your &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;smoke&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$YOUR_IMAGE&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;S3_ACCESS_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin&lt;/span&gt;
    &lt;span class="na"&gt;S3_SECRET_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-password&lt;/span&gt;
    &lt;span class="na"&gt;S3_ENDPOINT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://minio:9000"&lt;/span&gt;
  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bitnami/minio:latest&lt;/span&gt;
      &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minio&lt;/span&gt;
      &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;MINIO_ROOT_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$S3_ACCESS_KEY&lt;/span&gt;
        &lt;span class="na"&gt;MINIO_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$S3_SECRET_KEY&lt;/span&gt;
        &lt;span class="na"&gt;MINIO_DOMAIN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;
        &lt;span class="na"&gt;MINIO_DEFAULT_BUCKETS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-bucket&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5m&lt;/span&gt;
  &lt;span class="na"&gt;interruptible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;allow_failure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm run test:smoke&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://www.linkedin.com/in/g-fuchter/" rel="noopener noreferrer"&gt;My Linkedin Profile&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/G-Fuchter" rel="noopener noreferrer"&gt;My Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gitlab</category>
      <category>s3</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Should Domain Models Have Interfaces?</title>
      <dc:creator>Guillermo Fuchter</dc:creator>
      <pubDate>Mon, 02 Sep 2024 23:23:18 +0000</pubDate>
      <link>https://forem.com/g-fuchter/should-domain-models-have-interfaces-4h30</link>
      <guid>https://forem.com/g-fuchter/should-domain-models-have-interfaces-4h30</guid>
      <description>&lt;p&gt;When developing a project following &lt;a href="https://en.wikipedia.org/wiki/Domain-driven_design" rel="noopener noreferrer"&gt;Domain-Driven Design&lt;/a&gt; and clean architecture, one might ask themselves the following question: Should my domain models implement interfaces? After all, a good programmer should program against abstraction, not concretions. But then why don't most public examples of domain-driven design projects on the internet create interfaces for their entities? This is one of the questions I came across while implementing a DDD project, and it made me think of reasons for and against implementing interfaces for models that I'd like to share with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why You Might Want to Create an Interface for Your Models
&lt;/h2&gt;

&lt;p&gt;Domain models encapsulate a rich understanding of the processes and rules of a domain &lt;a href="https://martinfowler.com/bliki/DomainDrivenDesign.html" rel="noopener noreferrer"&gt;1&lt;/a&gt; and depending on the programming language you use, you might find yourself encapsulating the properties behind getters and setters. If that is the case, you will have an object that only exposes methods, which means that it could be abstracted by an interface, given that no properties are publicly exposed.&lt;/p&gt;

&lt;h3&gt;
  
  
  SOLID
&lt;/h3&gt;

&lt;p&gt;Since we aspire to be great programmers, we want to apply &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/SOLID" rel="noopener noreferrer"&gt;SOLID&lt;/a&gt; principles pervasively&lt;/strong&gt; through our project so as to build upon a good foundation. The 'I' in SOLID stands for &lt;a href="https://en.wikipedia.org/wiki/Interface_segregation_principle" rel="noopener noreferrer"&gt;Interface segregation principle&lt;/a&gt; and it states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No code should be forced to depend on methods it does not use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The idea is for "consumers" of the entity to rely on interfaces offering the methods they need, so as to decouple the consumers from the entity itself. &lt;strong&gt;Decoupled code&lt;/strong&gt; is much easier to replace, refactor, and work with than coupled code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unit Tests
&lt;/h3&gt;

&lt;p&gt;Having interfaces helps with unit testing. When creating an unit test for a module that depends on a model's interface, there is no need to instantiate complex domain models just to test a path of the service. Creating a mock model that complies with the model's interface can be &lt;strong&gt;easier than instantiating a real one&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Case Against Interfaces For Domain Models
&lt;/h2&gt;

&lt;p&gt;The theory might suggest that domain models should be kept behind interfaces, but there are good reasons why not to do that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Unnecessary Complexity and Abstraction
&lt;/h3&gt;

&lt;p&gt;The idea of having decoupled layers is to be able to replace them eventually. Perhaps one day you will be using a relational database, and the next day you will need to use a non-relational one. But unless you're designing a framework, the reality is that you will never have to replace the domain layer. Your domain is the most stable dependency you will have in your other layers. It is the core of the application, and replacing it would mean creating an entire different application. Additionally, adding seams into your application just to follow a design principle blindly can &lt;strong&gt;add complexity&lt;/strong&gt; without any benefits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain Models Should Be Simple
&lt;/h3&gt;

&lt;p&gt;Domain models tend to encapsulate simple domain behavior. This is because &lt;strong&gt;domain services&lt;/strong&gt; are the ones responsible for carrying out the complex business behavior that include more than one model. Given this, and the fact that model contain deterministic behavior, it can be argued that a domain model interfaces would not provide a big benefit when it came to writing unit tests for modules that rely on domain models. If you find yourself working with complex models, that is a sign that the domain should go through a &lt;a href="https://thedomaindrivendesign.io/distilling-domain/" rel="noopener noreferrer"&gt;distillation process&lt;/a&gt; to simplify it.&lt;/p&gt;

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

&lt;p&gt;It is not a white-black issue. I would consider both of them to be valid interpretations of DDD, clean architecture, and SOLID. Personally, I side more with not implementing since adding extra abstractions has a cost, and as long as the models stay simple, unit testing modules that depend on domain models should not be a problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/g-fuchter/" rel="noopener noreferrer"&gt;My Linkedin Profile&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/G-Fuchter" rel="noopener noreferrer"&gt;My Github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>ddd</category>
      <category>cleancode</category>
    </item>
  </channel>
</rss>
