Thet Bhone Htut
Thet Bhone Htut

Reputation: 1

SRP and DRY confusion

I am new to developing clean codes and trying to discipline myself with principles. My application has 3 user entities and each user entities have different data sources. When it comes to authentication logic, all 3 entities will use the same logic, except from data source. What I am doing now is, I separated the logic into 3 different classes for each entities (for the sake for different data sources) and feels like I am violating the DRY principle.

I used to do like this (I'll just use pseudo code):

class Auth
loginFunction(dto,loginType){
connect to datasource for auth(datasource = loginType=A?datasourceA:loginTypeB?datasourceB:datasourceC)
}

What I am doing now is this:

class AuthA
loginFunction(dto){
}
class AuthB
loginFunction(dto){
}
class AuthC
loginFunction(dto){
}

For the first approach, I feels like I am violating SRP because, the class is responsible for handling authentication for all the entities. I can argue that it's responsibility is just to handle authentication, regardless of the number of entities. But then again, I feel like each entity's authentication should be handled by their own respective classes. And hence, the second approach. But the second approach have same logic repeated across all classes, with the only difference of datasource.

I feel like both approaches aren't right. Is there any way to handle this as eloquently as possible? Thank you all.

Upvotes: 0

Views: 145

Answers (1)

J.F.
J.F.

Reputation: 15187

I don't know if I'm undestanding correctly but I think you are looking for inheritance where you have a base class like BaseAuth which will be extended for each specific "Auth" class and each specific class will implement its own datasource.

And also, It's not a good idea connect to the datasource into login method. Your Auth class is doing two things: Connect to DataSource and Login the user.

So you can have something like this example (I've used Java):

abstract class BaseAuth {
  protected DataSource dataSource;
  
  public BaseAuth(DataSource dataSource) {
    this.dataSource = dataSource;
  }
  
  public void login(LoginDTO dto) {
    // this.datasource.connect().login() or whatever
    // for testing I've added this line:
    System.out.println("DATASOURCE = " + this.dataSource.toString());
  }
}

And each specific class will implement its own datasource and will be accessible via login method.

Something like this:

class AuthA extends BaseAuth {
  public AuthA() {
    super(new DataSourceA());
  }
}

Now AuthA creates its own DataSourceA. The same way for B and C. So the class AuthX provide the datasource while the base class provide the login logic.

And DataSource from BaseAuth can be another abstraction (interface or abstract class):

interface DataSource { }

Where each DataSourceX implements DataSource.

I've created this DataSource example overriding toString() to test the example:

class DataSourceA implements DataSource {

  public DataSourceA() {
    // here the specific implementation
  }

  @Override
  public String toString() {
      return "DataSource A";
  }
}

So now:

  1. BaseAuth class allows you to call .login() method regardless it is called from AuthA, AuthB or AuthC. Login is not repeated and this class only have the responsability to do the login.
  2. When each "auth" class is created, it also creates its own DataSource. So each auth has only the responsability to create its own datasource.
  3. .login() will call the specific DataSource for the specific class.

Then, if you do (removing the DTO object from the method to read better):

BaseAuth auth = new AuthA();
auth.login();
auth = new AuthB();
auth.login();
auth = new AuthC();
auth.login();

The result will be:

DATASOURCE = DataSource A
DATASOURCE = DataSource B
DATASOURCE = DataSource C

Note how you don't have to repeat code. You have only one login method which will execute the according DataSource.

By the way and as append I will remember you another principle "Duplication is far cheaper than the wrong abstraction". If you are not completly sure the abbstraction is ok... don't try that.

Upvotes: 0

Related Questions