Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

Dependency Graphs

dependencies.png

This sample, written in Java, is used in the book to explain the trade-offs in attempting to achieve a balance in testability and readability. The following example on how to instance a service isn't ideal.

Traditionally, people create instances of their dependencies inside the classes which require it. Like in this example.

In this case, the dependency is hard-coded into the class, and we won't be able to inject a fake implementation. You effectively become unable to test the UserService class as a unit, without testing UserMySqlRepository as a side-effect as well.

In testing, side-effects are poison.

A better approach might be providing the dependencies as you create instances, like below.

String connectionString = "SOME_CONNECTION_STRING";
SqlConnectionString connString = new SqlConnectionString(connectionString);
SqlDbConnection conn = new SqlDbConnection(connString);
IUserRepository repo = new UserMySqlRepository(conn);
UserService service = new UserService(repo);

Here is how the UserService should look like if we seek to go for IoC.

The constructor receives the dependencies we have, rather than us creating them ourselves. this is known as Inversion of Control. Thus, code becomes more testable. You can create a fake implementation of that same interface, provide it to the class when you instance it, and the module is still supposed to work, because we aren't coding to the implementation. It's only the interfaces matter.

That's why we resort to dependency injection frameworks, so we can have the best of both worlds: testable and readable code.