# Tightly coupled code

Tightly coupled code is a common issue in software development, where modules or components are so dependent on each other such that a change in one requires a change in the other, making it challenging to modify or maintain code. In C#, tight coupling often arises when classes and methods are too intertwined, making it difficult to make changes without impacting other parts of the code. In this article, I will explore the concept of tightly coupled code and provide C# examples.

Consider a simple example where we have a class called `User` and another class called `Authenticator`. The `Authenticator` class is responsible for authenticating users and relies heavily on the `User` class to do so. Here is an example of how these two classes might be implemented in a tightly coupled way:

```csharp
public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

public class Authenticator
{
    private User _user;

    public Authenticator()
    {
        _user = new User { Username = "admin", Password = "password" };
    }

    public bool Authenticate(string username, string password)
    {
        if (username == _user.Username && password == _user.Password)
        {
            return true;
        }

        return false;
    }
}
```

In this example, the `Authenticator` class creates an instance of the `User` class and uses it to authenticate users. This creates tight coupling between the two classes because the `Authenticator` class is dependent on the `User` class. Let's try to test this code. A test might look like below code:

```csharp
public class Tests
    {
        [Test]
        public void WHenPasswordDoesNotMatchResultIsFalse()
        {
            Authenticator auth = new();
            bool authResult = auth.Authenticate("admin", "password1");
            authResult.Should().Be(false);
        }
    }
```

Any problems with the above test? The test passes fine but what happens when another developer updates the `Authenticator` class to create a user whose password is now *password1*? The test above will need updating to match the change in `Authenticator` class. Let's say we had a test for a positive case of a username and a password that matches, and negative cases for either username or password not matching. That's 3 tests already where you need to change the code.

Let's improve this a bit to avoid such changes.

```csharp
public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

public class Authenticator
{
    private User _user;

    public Authenticator(User user)
    {
        _user = user;
    }

    public bool Authenticate(string username, string password)
    {
        if (username == _user.Username && password == _user.Password)
        {
            return true;
        }
        return false;
    }
}
```

This is better! Our tests now do not rely on a user object created in the `Authenticator` class. We can create user objects and just inject them into `Authenticator`. However, `Authenticator` is still dependent on the `User` class. For each User to be authenticated, we need a new instance of `Authenticator`.

To fully decouple `Authenticator` and *User* classes, and avoid creating a new instance of `Authenticator` each time a user needs authenticating, we can use another object that is responsible for creating a `User` object. In fact, in a real application, users will be stored somewhere where a lookup can be performed when there is a login attempt. Let's look at the below code snippet.

```csharp
public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

public interface IUserRepository
{
    User GetUser(string username);
}

public class Authenticator
{
    private readonly IUserRepository _userRepository;

    public Authenticator(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public bool Authenticate(string username, string password)
    {
        User user = _userRepository.GetUser(username);

        if (user != null && password == user.Password)
        {
            return true;
        }

        return false;
    }
}
```

In this example, we define an interface called `IUserRepository` that specifies the methods for getting a `User` object. We then modify the `Authenticator` class to accept an instance of this interface via its constructor. This enables us to inject a different implementation of the `IUserRepository` interface, depending on our needs. As a start, we may have users in a database for the actual application but we may also have users in a file for our unit tests. We can then implement a `FileUserRepository` for our tests and a `DbUserRepository` for actual application code.

You may also argue that you may want to abstract `User` class by creating an `IUser` interface that can be implemented by classes representing different types of users.

Developers sometimes write tightly coupled code because it feels easier at the beginning. Loosely coupled code requires thinking and planning upfront. However, tightly coupled code quickly becomes difficult to main as a change in one place may result in changes in many other places.

One practice that forces developers to put in the effort to implement loosely coupled code is Test Driven Development. Following the principle of the path of least resistance, a developer can write unit tests upfront with much thought into the structure of the actual implementation. However, when actual code is developed, this is where effort will be required to align with the unit tests.
