An Opinionated Usage of Interface

Every C# developer knows what interface is. From the code perspective it is interface ISomething. There is no requirement for the I in the interface name. But that is just the naming convention. And it is good to know it is an interface by looking at the name. A more interesting question is when do we use interface?. And I guess each developer might have their own answer and reasons behind them.

Back in time, about 10 years ago, I started to use interface a lot. Back then the obvious reason was mocking and unit testing. And then the dependency injection came to my developer life. I read somewhere that you should inject interfaces instead of concrete implementations.

Have you ever heard of these?

  • Depend on interfaces instead of concrete implementations
  • It is easier for you to change the implementation later
  • It helps you mocked the implementation in the unit test
  • Your code looks clean and professional

In some codebases, I ended up with interfaces everywhere. The unit test was a bunch of mocks and mocks, everywhere. It looked good in the beginning. However, after a while, it was a pain.

  • It was hard to do the refactoring. For example, when I did not want to move a piece of code from this class to another class without changing the outcome behavior, the unit test failed. Because the expected interface was no longer there. The unit test knew too much about the implementation detail. I have the habit of refactoring code quite often. And I expect the unit test to catch my mistake if I accidentally change the outcome behavior. With mocking, I failed to archive that
  • Had to test at every layer. Basically, there were behavior test with mocking and there were tests for actual implementation. There were too much test code to maintain. Well, that was a waste of time and effort and error prone in the test
  • The chances of actually changing an implementation was rare

Ok, so is interface useful? Of course yes it is. And here are my opinions when to use it.

Code Contract

The interface tells the consumers the functionalities it supports. A class might have 10 methods. But not all consumers use or care 10 methods. They might be interested in 2 or 3 methods. It is fine to inject the class. However, the consumer is confused and might misuse.

Let take an example of an imagination log service. Here is the concrete implementation

public class SimpleLogService
{
    public void WriteLog(string logMessage)
    {

    }

    public IList<string> GetLogs()
    {
        return new List<string>();
    }
}

// API Controller to read the log
public class LogController : Controller
{
    private readonly SimpleLogService _logService;
    public LogController(SimpleLogService logService)
    {
        _logService = logService;
    }

    public IActionResult Get()
    {
        return OK(_logService.GetLogs());
    }
}

There is nothing wrong with the above code. However, I do not want the LogController to see/use the WriteLog method. That method is used by another controllers or services. And the SimpleLogService class might grow in size over the time. More and more methods are developed.

To solve that problem, I want to create a contract to tell LogController what it can use.

public interface ILogReaderService
{
    public IList<string> GetLogs();
}

public class SimpleLogService : ILogReaderService
{
    public void WriteLog(string logMessage)
    {

    }

    public IList<string> GetLogs()
    {
        return new List<string>();
    }
}

// API Controller to read the log
public class LogController : Controller
{
    private readonly ILogReaderService _logService;
    public LogController(ILogReaderService logService)
    {
        _logService = logService;
    }

    public IActionResult Get()
    {
        return OK(_logService.GetLogs());
    }
}

And I can do the same for the WriteLog part if necessary.

Decouple Implementation Dependency

In many projects, there is data involve. There are databases. And then comes the concept of Repository. And if the repository implementation is easy and that the database is ready. A developer can write a complete feature from API layer down to database layer. But I am doubt that is the reality. So the situation might look like this

  • One developer takes care of front end development
  • One developer takes care of the API (controller) implementation
  • One developer takes care of designing database, writing the repository. This might be the same developer that implements the API

The API layer depends on the Repository. However, we also want to see the flow and speed up the development. Let’s see some code

public class UserController : Controller
{
    private readonly IUserRepository _repository;

    public UserController(IUserRepository repository)
    {
        _repository = repository;
    }

    public async Task<IActionResult> GetUsers()
    {
        var users = await _repository.GetAllUsers();

        return Ok(user);
    }
}

The IUserRepository is the Code Contract between API and the repository implementation. To unlock the development flow, a simple in memory repository implementation is introduced

public class InMemoryUserRepository : IUserRepository
{
    public async Task<IList<User>> GetAllUsers()
    {
        await Task.CompletedTask();

        return new List<User>{
            new User("Elsa"),
            new User("John"),
            new User("Anna")
        };
    }
}

And the API can function. This releases the dependency on the actual repository implementation. When such an implementation is ready, switch to use it.

However, do not overuse it. Otherwise, you end up with interfaces everywhere and each developer gives their own temporary implementations. Choosing the right dependencies is an art and context matters a lot.

Conclusion

I rarely create interfaces with the purpose of unit testing in mind. Rather, it is the outcome of writing code, refactoring from a concrete implementation and then extracting into interfaces where they make the most sense. When I do, I pay close attention to its meaning. If I can avoid an interface, I will do it.

Code Contract and Decouple Implementation Dependency are the 2 big benefits from having proper interfaces. There are other reasons to use interfaces. They are all valid depending on the context. Sometime, it is the way the project architect wants it.

What are yours?

Have Fun with Fibonacci

I barely remember when the last time I implemented the famous Fibonacci was. It was the doctrine example of recursive implementation. I am not sure whether it is still a thing at the moment.

Over the weekend, I read some recent stuff in C#. The Fibonacci came to my mind. I have not tried to implement it differently and have not tested how bad it is with recursive implementation. So it is fun to have write some code.

Given that we need to know the result of F30 (or F40), how long would it take and how many calls in the recursive approach? And how about the alternative implementation?

Recursive Implementation

class Program
{
    private static int _recursiveCount = 0;
    private static long RecursiveFibonacci(int n)
    {
        _recursiveCount++;
        return n < 2 ? n : RecursiveFibonacci(n - 1) + RecursiveFibonacci(n - 2);
    }

    private static void DisplayFibonacci(Func<int, long> fibo, int number)
    {
        Console.WriteLine($"{number}: {fibo(number)}");
    }

    static void Main(string[] args)
    {
        const int number = 30;
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        DisplayFibonacci(RecursiveFibonacci, number);
        stopwatch.Stop();

        Console.WriteLine($"Completed after: {stopwatch.Elapsed}; Recursive Counts: {_recursiveCount}");
    }
}

Run and observe the result

Completed after: 00:00:00.0457925; Recursive Counts: 2.692.537

The completion time depends on the computer the code runs. But the recursive count is impressive—2.5 millions time. I increased the number to 50 but lost my patient to wait.

Recursive with Cache

We could improve the recursive solution with result caching. Again, this is a simple implementation for fun.

private static readonly List<long> _fiboCache = new List<long> { 0, 1 };
private static long FibonacciRecursiveWithCache(int n)
{
    _recursiveCount++;
    while (_fiboCache.Count <= n)
    {
        _fiboCache.Add(-1);
    }

    if (_fiboCache[n] < 0)
    {
        _fiboCache[n] = n < 2 ? n : FibonacciRecursiveWithCache(n - 1) + FibonacciRecursiveWithCache(n - 2);
    }

    return _fiboCache[n];
}

For Loop Implementation

And I gave a try with non-recursive approach. There are more lines of code but runs so much faster

private static long FibonacciForLoop(int n)
{
    long n_1 = 1;
    long n_2 = 1;
    long total = 0;
    for (int i = 3; i <= n; i++)
    {
        total = n_1 + n_2;
        n_1 = n_2;
        n_2 = total;
    }

    return total;
}

I do not need 3 variables (n_1, n_2, total). The solution only needs 2 variables. However, I felt natural with 3 variables. It follows the way I calculate it manually.

So let put them together and see the differences

static void Main(string[] args)
{
    const int number = 30;

    Console.WriteLine("Recursive");
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    DisplayFibonacci(RecursiveFibonacci, number);
    stopwatch.Stop();

    Console.WriteLine($"Completed after: {stopwatch.Elapsed}; Recursive Counts: {_recursiveCount}");

    Console.WriteLine("Recursive with cache");
    _recursiveCount = 0;
    stopwatch.Reset();
    stopwatch.Start();
    DisplayFibonacci(FibonacciRecursiveWithCache, number);
    stopwatch.Stop();

    Console.WriteLine($"Completed after: {stopwatch.Elapsed}; Recursive Counts: {_recursiveCount}");

    Console.WriteLine("For loop");
    stopwatch.Reset();
    stopwatch.Start();
    DisplayFibonacci(FibonacciForLoop, number);
    stopwatch.Stop();

    Console.WriteLine($"Completed after: {stopwatch.Elapsed}");
}

Ladies and gentlemen, I present to you

Recursive
30: 832040
Completed after: 00:00:00.0277573; Recursive Counts: 2692537
Recursive with cache
30: 832040
Completed after: 00:00:00.0003827; Recursive Counts: 59
For loop
30: 832040
Completed after: 00:00:00.0001500

That’s it! I know how to implement the Fibonacci.

Technical Notes – CosmosDB Change Feed and Azure Function

Some notes while looking deeper into the integration between Azure CosmosDB Change Feed and Azure Function. Most of the time, we simply use the built-in trigger. And it just works. That is the beauty of the Azure.

// Azure function code, CosmosDb Trigger. Took from MS Example
public static class CosmosTrigger
{
    [FunctionName("CosmosTrigger")]
    public static void Run([CosmosDBTrigger(
        databaseName: "ToDoItems",
        collectionName: "Items",
        ConnectionStringSetting = "CosmosDBConnection",
        LeaseCollectionName = "leases",
        CreateLeaseCollectionIfNotExists = true)]IReadOnlyList<Document> documents,
        ILogger log)
    {
        if (documents != null && documents.Count > 0)
        {
            log.LogInformation($"Documents modified: {documents.Count}");
            log.LogInformation($"First document Id: {documents[0].Id}");
        }
    }
}

The example is everywhere. Nothing is fancy about it.

In a project, we took the advantages of that feature to migrate data from CosmosDB to Azure SQL Database for later processing. I wanted to make sure that we are well-prepared for the production. So I did some learnings. So here are the notes. Note that none of them are mine or new. They are simply my writing in the way that I want to remember them and in the areas that I am interested in.

Container, Logical Partition, and Physical Partition

Change Feed is per container. If a database has 3 containers, each has its own Change Feed. The Change Feed ensures that the documents are sent in the order they were written.

Change Feed is reliable as the database itself.

Under the hood, data is stored in many physical partitions. At that level, Change Feed is actually per physical partition. The data might be shuffled from one physical partition to another. When that happens, the Change Feed is moved as well. So how to ensure the document order across the physical partition, especially after moved? The Change Feed Processor (CFP) manages all the complexity for us.

Change Feed Processor (CFP)

In theory, developers can write code to interact directly with Change Feed. It is possible but not practical. In practice, not many (I cannot say NONE) want to. Instead, many depend on the Change Feed Processor (CFP). The MS Docs has sample code that you can write your own consumer code.

Azure Function with CosmosDb trigger

Azure CosmosDb trigger configuration

By default, the poll interval is 5 seconds (see the FeedPollDelay attribute).

Azure Function with the CosmosDb trigger is a layer on top of the CFP. It saves us from dealing with hosting, deployment, scaling, … with the power of Azure Function.

If the function execution fails, by throwing an exception, the changed documents are sent again in the next run. So there is a risk that the flow is stuck if the failure has not designed to handle properly. The Change Feed and Azure Function ensure that your code will received the changed documents at least once.