DEV Community

Cover image for 🛠️ Writing Reliable Code from the Ground Up !
Sahil Dahekar
Sahil Dahekar

Posted on

🛠️ Writing Reliable Code from the Ground Up !

The Coding Nightmare - We’ve all Experienced 😵

Imagine spending hours crafting what you believe is the perfect piece of code, only to discover a cascade of bugs when you finally run it. The debugging marathon begins: fixing one issue reveals three more, and suddenly, your elegant solution looks like a house of cards ready to collapse 🐛 .

This was my reality during a local coding meetup while implementing Conway's Game of Life. I wrote extensive code, confident in my approach, only to find the implementation completely missed the mark. Hours of debugging later, I was frustrated and demoralized. 😤

Java Code that i wrote during local coding meetup

Then I discovered Test Driven Development (TDD) – a methodology that flips traditional software development on its head 🔄

The Reactive Approach - Chasing Bugs and Deadlines 🕰️

In traditional software development, the typical workflow looks like this:

  1. Write implementation code
  2. Develop tests after the fact
  3. Hope everything works as expected 🤞

This approach is fraught with risks:

  • Developers often overlook edge cases 🤔
  • Tests become an afterthought 📝
  • Bugs can slip into production 🐛
  • Refactoring becomes increasingly difficult 🧹
  • Confidence in code reliability diminishes 😟

Enter Test Driven Development - A new Hope for Devs 🙌 :

TDD introduces a radical yet powerful approach: write tests first, then write the code to pass those tests.

Test Driven Development Illustration

The Red-Green-Refactor Cycle 🔁

TDD follows a simple yet powerful cycle:

  1. Red: Write a failing test

    • Define the expected behavior
    • Ensure the test fails initially ❌
  2. Green: Write minimal code to pass the test

    • Implement just enough code to make the test pass
    • Focus on solving the immediate requirement ✅
  3. Refactor: Improve code without changing its behavior

    • Clean up the implementation 🧹
    • Enhance readability and efficiency
    • Ensure all tests still pass

Red - Green - Refactor Cycle Diagram

Why TDD ? Unlocking the Key Benefits 🔑

1. Superior Code Quality

  • Emphasis on clean, modular, and maintainable code
  • Testability becomes a primary design consideration
  • Clear documentation through tests 🧠

2. Early Bug Detection

  • "Fail-fast" approach identifies issues immediately
  • Prevents complex, deeply embedded bugs
  • Reduces long-term debugging time 🐛➡️🚫

3. Confidence in Refactoring

  • Comprehensive test suite acts as a safety net
  • Enables continuous code improvement
  • Reduces fear of breaking existing functionality 👨‍💻👩‍💻

4. Clear Requirements and Design

  • Forces developers to think about requirements first
  • Improves understanding of problem domains
  • Facilitates better architectural decisions 🏗️

5. Collaborative Documentation

  • Tests serve as living documentation
  • Provides clear specifications for team members
  • Bridges communication between technical and non-technical stakeholders 👥

TDD in Action - A Step-By-Step Example :

Let's see TDD in action by building a Password Strength Checker

Step 1: Set Up Your Project

Make sure you have NodeJS installed in your system

Initialize a new Node.js project:

mkdir tdd
cd tdd
npm init -y
Enter fullscreen mode Exit fullscreen mode

Install Jest:

Jest is testing framework for JavaScript

npm install jest
Enter fullscreen mode Exit fullscreen mode

Update package.json to use Jest:

"scripts": {
    "test": "jest"
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Write the First Test 🔴

Create a file named index.test.js in your project directory. Start with a simple test for weak passwords.

const checkPasswordStrength = require('./index');

describe('Password Strength Checker', () => {
    test('should return "Weak" for passwords less than 8 characters', () = { 
        expect(checkPasswordStrength('abc')).toBe('Weak');
    });
});
Enter fullscreen mode Exit fullscreen mode

Run the test using the following command:

npm test
Enter fullscreen mode Exit fullscreen mode

You’ll see an error because checkPasswordStrength doesn’t exist.

Test failing error console output

Step 3: Implement the Initial Function 🟢

Create a file named index.js and implement the initial checkPasswordStrength function to pass the first test.

function checkPasswordStrength(password) {

    if (password.length < 8) {
    return 'Weak';
    }

    return 'Medium'; // Default return value for now
}

module.exports = checkPasswordStrength;
Enter fullscreen mode Exit fullscreen mode

Run the test again:

npm test
Enter fullscreen mode Exit fullscreen mode

It should pass now.

First Test Passing console ouput

Step 4: Add More Tests and Logic Incrementally

Test for Medium Strength Passwords 🔴

Update index.test.js to include a test for medium strength passwords.

describe('Password Strength Checker', () => {

    test('should return "Weak" for passwords less than 8 characters', () => {
        expect(checkPasswordStrength('abc')).toBe('Weak');
    });

    test('should return "Medium" for passwords with 8+ characters but no uppercase, numbers, or special characters', () => {
        expect(checkPasswordStrength('abcdefgh')).toBe('Medium');
    });
});

Enter fullscreen mode Exit fullscreen mode

Update index.js to handle medium strength passwords. 🟢

function  checkPasswordStrength(password) {

    if (password.length  <  8) return  'Weak';

    const  hasUppercase  = /[A-Z]/.test(password);
    const  hasNumber  = /\d/.test(password);
    const  hasSpecialChar  = /[!@#$%^&*(),.?":{}|<>]/.test(password);

    if (!hasUppercase  &&  !hasNumber  &&  !hasSpecialChar) return  'Medium';

    return "Strong";
}

module.exports = checkPasswordStrength;
Enter fullscreen mode Exit fullscreen mode

Run the tests again to ensure they pass.

Test for Strong & Very Strong Strength Passwords 🔴

Update index.test.js to include a test for strong & very strong strength passwords.

describe('Password Strength Checker', () => {
    test('should return "Weak" for passwords less than 8 characters', () => {
        expect(checkPasswordStrength('abc')).toBe('Weak');
    });

    test('should return "Medium" for passwords with 8+ characters but no uppercase, numbers, or special characters', () => {
        expect(checkPasswordStrength('abcdefgh')).toBe('Medium');
    });

    test('should return "Strong" for passwords with uppercase, lowercase, and numbers', () => {
        expect(checkPasswordStrength('Abcdef12')).toBe('Strong');
    });

    test('should return "Very Strong" for passwords with uppercase, lowercase, numbers, and special characters', () => {
        expect(checkPasswordStrength('Abcdef12@')).toBe('Very Strong');
    });
});
Enter fullscreen mode Exit fullscreen mode

Update index.js to handle strong strength passwords. 🟢

function  checkPasswordStrength(password) {

    if (password.length  <  8) return  'Weak';

    const  hasUppercase  = /[A-Z]/.test(password);
    const  hasNumber  = /\d/.test(password);
    const  hasSpecialChar  = /[!@#$%^&*(),.?":{}|<>]/.test(password);

    if (!hasUppercase  &&  !hasNumber  &&  !hasSpecialChar) return  'Medium';

    if (hasUppercase  &&  hasNumber  &&  !hasSpecialChar) return  'Strong';

    return  'Very Strong';
}

module.exports = { checkPasswordStrength };
Enter fullscreen mode Exit fullscreen mode

Run the tests again to ensure they pass.

All tests passing console output

Step 5 : Optimization and Refactoring 🔵

Once all tests are passing, it's time to improve and refactor the code.

Here’s the refactored version of index.js:

function  checkPasswordStrength(password) {

    if (password.length  <  8) return  'Weak';

    // Evaluate complexity conditions
    const  conditions  = [
    /[A-Z]/.test(password), // Uppercase letters
    /\d/.test(password), // Numbers
    /[!@#$%^&*(),.?":{}|<>]/.test(password), // Special characters
    ];

    const  score  =  conditions.filter(Boolean).length;

    // Determine strength based on score
    if (score  ===  0) return  'Medium';
    if (score  ===  2) return  'Strong'; // Uppercase + Number
    if (score  ===  3) return  'Very Strong'; // Uppercase + Number + Special char

    return  'Weak';
}

module.exports  =  checkPasswordStrength
Enter fullscreen mode Exit fullscreen mode

Instead of relying on multiple if-else conditions, we optimized the logic by calculating a strengthScore based on the password's complexity. This approach makes the code easier to read and maintain.

Edge Case :

What happens if the password is an empty string ('') or contains only whitespaces (' ')?

Try adding tests for these scenarios to strengthen the function. You can explore the complete solution here.

By letting test cases drive development, we ensured robust functionality while avoiding unnecessary complexity.

Myth-Busting TDD - Separating Fact from Fiction 🤔

Myth #1:

TDD slows down development because developers have to write tests before writing code.

Reality:

TDD may seem slower at first, but it speeds up development in the long run by:

  • Catching bugs early 🔍
  • Reducing debugging time 🕰️
  • Improving code quality 🚀

Myth #2:

TDD is just about writing tests and has no impact on the actual development process.

Reality:

TDD is more than just writing tests—it’s a design methodology that:

  • Clarifies requirements upfront 🧩
  • Promotes modular and testable code 📦
  • Ensures incremental and iterative development 🔄

Myth #3:

TDD is only suitable for certain types of projects or specific programming languages.

Reality:

TDD is universal and can be applied to:

  • Projects of any size or complexity 🌍
  • Any technology stack or programming language 💻

Its principles—writing tests first, focusing on small increments, and iterating based on feedback—are beneficial for all developers.

Beyond TDD - What’s Next in your Development Journey 🚀

Behaviour Driven Development (BDD) extends TDD's principles by focusing on behavior and business value. It uses more descriptive, narrative-style tests that non-technical stakeholders can understand. 🗣️

Your TDD Toolkit - Recommended Resources 📚

If you're curious to dive deeper into Test-Driven Development (TDD), here are some excellent resources:

  1. Test-Driven Development by TestDriven.io
    A comprehensive guide that walks you through the TDD process step-by-step, making it beginner-friendly and practical.

  2. Introduction to TDD by BrowserStack
    An insightful overview of TDD principles, benefits, and real-world applications—great for developers of all levels.

  3. TDD Tutorial by freeCodeCamp
    A hands-on tutorial focusing on JavaScript and React, perfect for anyone working with modern frontend frameworks.

  4. Jest Documentation
    The official Jest docs—a must-read for understanding how to write and run tests effectively with this powerful framework.

Wrapping Up 🎉

Test Driven Development is more than a methodology – it's a mindset. It transforms coding from a reactive to a proactive process, where quality is built-in, not bolted-on. 🧠

Ready to revolutionize your coding approach? Start small, be consistent, and watch your code quality soar. 🚀

Happy Testing! 🧪

💬 Let’s Connect!

Got any doubts or feedback? Share your thoughts in the comments below!

  • What topic should I cover in my next blog?
  • How did you like this one?

Your feedback and suggestions mean the world to me. Let’s keep the conversation going! 🌟

Top comments (1)

Collapse
 
dilnaj_atar_ec48929ba3bfe profile image
Dilnaj Atar

Informative!!