<?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>DEV Community: Lorenzo Spinelli</title>
    <description>The latest articles on DEV Community by Lorenzo Spinelli (@spinalorenzo).</description>
    <link>https://dev.to/spinalorenzo</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%2F268720%2Fbde74a11-aab5-4778-a52a-c1eda14c6846.jpg</url>
      <title>DEV Community: Lorenzo Spinelli</title>
      <link>https://dev.to/spinalorenzo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/spinalorenzo"/>
    <language>en</language>
    <item>
      <title>Don't use TDD for testing!</title>
      <dc:creator>Lorenzo Spinelli</dc:creator>
      <pubDate>Mon, 11 Nov 2024 07:42:23 +0000</pubDate>
      <link>https://dev.to/spinalorenzo/dont-use-tdd-for-testing-2ffk</link>
      <guid>https://dev.to/spinalorenzo/dont-use-tdd-for-testing-2ffk</guid>
      <description>&lt;p&gt;Today, I want to talk about an important problem many of us deal with in software development: production failures.&lt;/p&gt;

&lt;p&gt;A study of 198 production failures (&lt;a href="https://www.usenix.org/system/files/conference/osdi14/osdi14-paper-yuan.pdf" rel="noopener noreferrer"&gt;https://www.usenix.org/system/files/conference/osdi14/osdi14-paper-yuan.pdf&lt;/a&gt;) revealed that most of these are caused by simple, trivial programming mistakes. &lt;/p&gt;

&lt;p&gt;Yes, we’re talking about errors that might seem small but can actually have serious consequences for our applications.&lt;/p&gt;

&lt;p&gt;The most alarming finding from this study is that 58% of these failures are trivial mistakes that could have been easily avoided with proper test coverage. &lt;/p&gt;

&lt;p&gt;Imagine the time and cost spent fixing these errors after they have already gone live. &lt;/p&gt;

&lt;p&gt;The fragility of our code becomes evident: A small mistake can lead to a big disaster.&lt;/p&gt;

&lt;p&gt;When mistakes happen in production, they can cause our applications to become unstable and can make users lose trust in us. &lt;br&gt;
This situation can harm our company’s reputation, and our team may feel stressed trying to fix problems that could have been avoided.&lt;/p&gt;

&lt;p&gt;Fortunately, there is a solution. &lt;br&gt;
A study by Microsoft and IBM showed (&lt;a href="https://www.infoq.com/news/2009/03/TDD-Improves-Quality/" rel="noopener noreferrer"&gt;https://www.infoq.com/news/2009/03/TDD-Improves-Quality/&lt;/a&gt;) that teams using TDD experienced 40% to 90% fewer defects compared to teams not using TDD&lt;/p&gt;

&lt;p&gt;As we've seen, mistakes in production can severely impact our applications and the trust of our users&lt;br&gt;
Think about it: when you type a wrong word in a book, the entire book doesn’t fall apart. It may have a typo, but it remains intact. &lt;/p&gt;

&lt;p&gt;In contrast, a single buggy line of code can bring your whole production system crashing down. &lt;/p&gt;

&lt;p&gt;And I told you this just to highlight how fragile our software can be.&lt;/p&gt;

&lt;p&gt;As human beings, we all make mistakes, and that’s perfectly normal. &lt;/p&gt;

&lt;p&gt;But because of this, we need a powerful error detection protocol in place. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's not about admitting that we’re not good developers; it’s about ensuring that when we push code into production, we do so with the confidence that it won’t break anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I wrote it so big because, please, I would like you to take a picture and always remember it.&lt;/p&gt;

&lt;p&gt;We need systems that help us catch errors before they cause real problems, allowing us to focus on creating great software without fear. &lt;/p&gt;

&lt;p&gt;And I have experienced this on myself, that's the only reason why I am telling you this&lt;/p&gt;

&lt;p&gt;Okay, we’ve spoken about how fragile our software can be. Let’s look at how we can fix these problems. &lt;/p&gt;

&lt;p&gt;And… Since this post is about testing, I imagine you can guess what the solution might be!&lt;/p&gt;

&lt;p&gt;This is the definition of “testing” that a dictionary would give us: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Evaluating a system, product, or software to assess its functionality, performance, reliability, and quality by executing it under specific conditions to identify defects and ensure it meets requirements&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Testing is a basic part of software development.&lt;/p&gt;

&lt;p&gt;Here's a thought: Do you make testing a regular part of your coding process? If so, you're already on the path to cleaner, more reliable code! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The problem is that &lt;em&gt;Just doing tests isn’t always enough&lt;/em&gt;.&lt;br&gt;
Unit testing focuses on checking if the code works, but it misses the bigger picture of good design.&lt;/p&gt;

&lt;p&gt;Relying only on unit testing can compromise code quality.&lt;br&gt;
Without a solid design foundation, our code may become difficult to maintain, less efficient, and more prone to errors over time.&lt;/p&gt;

&lt;p&gt;That’s where TDD comes in.&lt;br&gt;
TDD focuses on design first, leading to better software quality.&lt;br&gt;
While unit testing checks the code, TDD helps create better designs, and the improved tests are a side effect.&lt;/p&gt;

&lt;p&gt;When we think about unit testing, it’s all about focusing on the code to ensure it works correctly.&lt;br&gt;
 In contrast, Test-Driven Development, shifts our focus to design first, which not only leads to better software but also naturally results in improved tests as a side effect.&lt;br&gt;
And we’ll see what i mean by this in a moment. But first, let’s dive into what Test-Driven Development is all about!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important!&lt;/strong&gt;&lt;br&gt;
One thing I want to point out is that tests (unit tests but not only) are not in conflict with TDD, and I have nothing against unit tests, in fact they are a fundamental part of TDD.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is TDD?
&lt;/h2&gt;

&lt;p&gt;Test-driven development is a software development approach that emphasizes writing tests before writing the actual code. It’s not just about catching bugs early, though—that’s a great side benefit. &lt;/p&gt;

&lt;p&gt;More importantly, TDD is about expressing intent. It’s a process of clearly defining what you want the code to do by first writing a test that sets the expectation.&lt;/p&gt;

&lt;p&gt;Here’s a definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TDD helps you express the intent of your code in the form of a test. The test describes the behavior you expect from the code, guiding the development process. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This approach leads to better design and ensures that the code behaves as expected from the start.&lt;/p&gt;

&lt;p&gt;The TDD Process relies on these step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a Test: Start by writing a test for a new feature or functionality. This test defines what the code should do.&lt;/li&gt;
&lt;li&gt;Run the Test: Execute the test to see it fail. This step confirms that the test is valid and that the feature isn’t implemented yet.&lt;/li&gt;
&lt;li&gt;Write the Code: Next, write the minimum amount of code needed to make the test pass.&lt;/li&gt;
&lt;li&gt;Run the Test Again: Execute the test again. If it passes, you know your code meets the requirement defined in the test.&lt;/li&gt;
&lt;li&gt;Refactor: With the test passing, take time to improve the code, ensuring it is clean and efficient without changing its functionality.&lt;/li&gt;
&lt;li&gt;Repeat: Go back to step one for the next feature or functionality.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The process is that easy! But we have to follow some rules. The first one is: &lt;br&gt;
&lt;strong&gt;the Red-Green-Refactor cycle&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Red (Write a test and see it fail):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start by writing a test for the new feature or functionality you want to add.&lt;/li&gt;
&lt;li&gt;Run the test, and it should fail because the feature hasn’t been implemented yet.&lt;/li&gt;
&lt;li&gt;This “red” stage confirms the test is working and the code needs to be written.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Green (Write just enough code to pass the test):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now, write the smallest amount of code needed to make the test pass.&lt;/li&gt;
&lt;li&gt;Run the test again, and it should pass, turning the test result from “red” to “green.”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Refactor (Improve the code):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With the test passing, go back and clean up the code.&lt;/li&gt;
&lt;li&gt;Simplify and optimize without changing what it does.&lt;/li&gt;
&lt;li&gt;The test should still pass after refactoring, ensuring the code is cleaner and more efficient.&lt;/li&gt;
&lt;li&gt;This process repeats for every new feature or functionality you add.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are more rules, but I won't cover those here. For now, let’s focus on how TDD improves design and helps create better code, not just tests. &lt;br&gt;
And why it is way better than unit testing. &lt;/p&gt;

&lt;p&gt;Unit testing focuses only on testing—just making sure the code works. But is that enough? Not really.&lt;/p&gt;

&lt;p&gt;The Main Point is:&lt;br&gt;
&lt;strong&gt;TDD is about design, not just testing&lt;/strong&gt;.&lt;br&gt;
&lt;em&gt;As a side effect, it naturally creates better tests.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a moment to think about &lt;strong&gt;design&lt;/strong&gt; and why it matters in code quality. What do we really look for in good code?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modular&lt;/strong&gt; – It’s broken into smaller pieces, each easier to understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loosely coupled&lt;/strong&gt; – These pieces aren’t too tightly connected and can change independently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High cohesion&lt;/strong&gt; – Related behaviors are grouped together in the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separation of concerns&lt;/strong&gt; – Each piece focuses on one task or outcome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Information hiding&lt;/strong&gt; – You can use parts of the code without needing to know the inner details.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we follow Test-Driven Development (TDD), we don’t write any code until we have a failing test that demands it. And by starting with tests, we naturally avoid writing overly complicated, messy code.&lt;/p&gt;

&lt;p&gt;Writing tests should be easy and make our lives easier. To do that, we need to create testable code—code that is designed with testing in mind. &lt;/p&gt;

&lt;p&gt;Testable code looks different from code that wasn’t designed with testing in mind. &lt;/p&gt;

&lt;p&gt;Let’s demonstrate this. &lt;/p&gt;

&lt;p&gt;Here's a simple example: a class representing a car, that has an engine (line 2) and a method start (line 4) to start the car, by starting the engine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Car {
  engine = new PetrolEngine();

  start() {
    this.engine.start()
    //other logic
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we try to test it, we see that we cannot assert anything, we don’t have access to the engine&lt;br&gt;
(plus, if we use a production engine, it will start the car in our test environment, which is not a good thing to do)&lt;/p&gt;

&lt;p&gt;I think we can change our design to make it more testable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//test
const car = new Car();
car.start();

//nothing to assert!!

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Car class now utilizes a &lt;code&gt;FakeEngine&lt;/code&gt;, which allows us to easily verify its behavior. With this setup, we can assert that the engine has started successfully without depending on a real engine implementation. As a result, we can focus on testing the Car class's functionality. This also means we might need to modify the class slightly to accept an engine as a parameter, enhancing its flexibility and testability.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as assert from "assert";

const engine = new FakeEngine();
const car = new Car(engine);
car.start();

assert.deepEqual(engine.isStarted, true, "Engine should be started");

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, the Car class doesn’t directly depend on the PetrolEngine. Instead, an engine is passed to it (in this case, a &lt;code&gt;FakeEngine&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;FakeEngine&lt;/code&gt; allows you to control and inspect its behavior in tests without dealing with real engine complexities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why It's More Testable:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Loose Coupling&lt;/strong&gt;: The Car class isn't tied to a specific engine (like &lt;code&gt;PetrolEngine&lt;/code&gt;). It works with any engine that follows the same interface, making it more modular and testable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation&lt;/strong&gt;: You can test the Car without involving the actual engine logic, focusing the test and making debugging easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mocking&lt;/strong&gt;: Using a &lt;code&gt;FakeEngine&lt;/code&gt;, you can simulate engine behavior and make assertions. I know we could use a mock instead of the fake class, but it’s just an example to demonstrate the principle: now we can test and assert that the engine was started.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;petrolCar = new BetterCar(new PetrolEngine());
electricCar = new BetterCar(new ElectricEngine());
jetCar = new BetterCar(new JetEngine());

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By focusing on testability, we’ve achieved cleaner, more flexible code. My improved Car class works with any engine that follows the contract—whether petrol, electric, or even a jet engine.&lt;/p&gt;

&lt;p&gt;The beauty of this design is that we can easily swap engines in both tests and actual code without modifying the Car class. This flexibility improves maintainability and future scalability.&lt;/p&gt;

&lt;p&gt;By prioritizing testability, we’ve gained dependency injection, making our code both functional and adaptable to new requirements while catching bugs early.&lt;/p&gt;




&lt;p&gt;Testing is not a magic fix! It won't instantly make you the best programmer in the world.&lt;/p&gt;

&lt;p&gt;But!... here's what I've noticed:&lt;/p&gt;

&lt;h3&gt;
  
  
  Test-driven development acts like a talent amplifier.
&lt;/h3&gt;

&lt;p&gt;It’s true that it won’t transform a poor programmer into a superstar.&lt;/p&gt;

&lt;p&gt;However, it will help a less skilled programmer become more competent.&lt;/p&gt;

&lt;p&gt;And for good programmers, it can make them even better, turning great programmers into exceptional ones!&lt;/p&gt;

&lt;p&gt;No matter where you stand in your coding journey, embracing TDD will help you improve your work.&lt;/p&gt;

&lt;p&gt;Alright, so when we think about TDD, it embraces more than just unit testing; there are several other important aspects to consider, such as: Behavior-Driven Development, Continuous Integration, Refactoring, and many others.&lt;/p&gt;

&lt;p&gt;But! …where do we start? What’s the minimum step we can take to get going?&lt;/p&gt;

&lt;p&gt;A fantastic way to kick things off is through Coding Katas (kata)! You might be wondering, what exactly is a kata? Well, they are simple coding problems that you can use for practice. They help you focus on the principles of TDD and improve your skills at the same time.&lt;/p&gt;

&lt;p&gt;Question for you: Have you ever tried coding KATA?&lt;/p&gt;

&lt;p&gt;Do not be fooled into thinking they are too simple or do not reflect the real world. Think of it like karate: if a fighter only practiced in the ring, it would be chaos! Training with katas builds your skills before tackling real challenges.&lt;/p&gt;

&lt;p&gt;I want to challenge you: if you dedicate 30 minutes a day for two weeks, I bet that not only will you quickly learn TDD, but also that the quality of your code will improve drastically.&lt;/p&gt;

&lt;p&gt;Here’s the secret to success: Always start with a test! This mindset will guide your coding process, ensuring you create what you truly need.&lt;/p&gt;

&lt;p&gt;Resources to Explore:&lt;br&gt;
To fuel your journey, check out these great websites for coding katas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CyberDojo&lt;/li&gt;
&lt;li&gt;CodeWars&lt;/li&gt;
&lt;li&gt;KataCoda&lt;/li&gt;
&lt;li&gt;CodeKata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To close, I want to say that I believe Test-Driven Development (TDD) is one of the few practices in our field that embodies genuine engineering. What do I mean by that? TDD offers a reliable and repeatable technique for producing better code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why TDD Works:
&lt;/h3&gt;

&lt;p&gt;It’s not just about being “smarter”—that’s not very helpful! TDD provides a structured approach that improves our coding skills and results.&lt;/p&gt;

&lt;p&gt;Remember, as Dijkstra once said: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Testing shows the presence, not the absence of bugs!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope I don’t come across as too presumptuous by sharing a quote after Dijkstra, but I’d like to conclude with this&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The purpose of testing is to find the bugs, not to prove the program is correct.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, Happy coding :)&lt;/p&gt;

</description>
      <category>testing</category>
      <category>testdriven</category>
      <category>development</category>
    </item>
    <item>
      <title>React app global state management with hooks</title>
      <dc:creator>Lorenzo Spinelli</dc:creator>
      <pubDate>Sun, 10 Nov 2019 08:41:01 +0000</pubDate>
      <link>https://dev.to/spinalorenzo/react-app-global-state-management-with-hooks-5b20</link>
      <guid>https://dev.to/spinalorenzo/react-app-global-state-management-with-hooks-5b20</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D626IuAX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1gtpumifya77ru7yylqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D626IuAX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1gtpumifya77ru7yylqy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React app global state management made easy with hooks and Context API: &lt;br&gt;
&lt;a href="https://link.medium.com/bZs5cKG6r1"&gt;https://link.medium.com/bZs5cKG6r1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How to achieve this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rh0P03KF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s34zy9h1bfwc3t06yo5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rh0P03KF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/s34zy9h1bfwc3t06yo5p.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can read how it works on medium, or jump directly to the code:&lt;br&gt;
&lt;a href="https://github.com/Spyna/react-context-hook"&gt;https://github.com/Spyna/react-context-hook&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
