mercredi 20 mars 2019

SRP and additional logic inside class

For example, I have a class, which does different requests to some external API:

internal class ServiceCore : IDisposable
{
    public ServiceCore(IConfiguration configuration, Func<HttpMessageHandler> handler)
    {
        _configuration = configuration;
        _handler = handler;
        devKey = _configuration.GetSection("ApiBillCom:DevKey").Value;
        client = new HttpClient(_handler())
        {
            BaseAddress = new Uri(_configuration.GetSection("ApiBillCom:ApiUrl").Value)
        };

        if (_sessionId == null || !_sessionId.IsValueCreated)
            SetSessionId();
    }


    public async Task<JToken> ListJTokenAsync(int start, int count, string endpoint, bool nested = false, List<FilterData> filterData = null)
    {
        //....
    }

    public async Task<List<T>> ListAsync<T>(string endpoint, int start, int count, bool nested = false, List<FilterData> filterData = null)
    {
        //.....
    }

ok, but each call requires sessionId, which we can get calling LoginAsync method before. This LoginAsync method can be as private method inside this ServiceCore class:

private void SetSessionId()
{
    _sessionId = null;
    LoginCore loginCore = new LoginCore(_configuration, _handler);
    _sessionId = new Lazy<string>(() => LoginAsync().Result);
}

private async Task<string> LoginAsync()
{

but then, seems, Single Responsible Principle is violated (because then ServiceCode has 2 duties, get (or put) data to API and supports session. I did refactoring and moved it to special class:

internal class LoginCore
{
    private readonly IConfiguration _configuration;
    private readonly Func<HttpMessageHandler> _handler;

    public LoginCore(IConfiguration configuration, Func<HttpMessageHandler> handler)
    {
        _configuration = configuration;
        _handler = handler;

    }

    internal async Task<string> LoginAsync(string devKey)
    {
        // ....
    }
}

Right now no SRP violation, every class has only one duty (ServiceCore - work with API, LoginCore - get actual sessionId), but I'm not sure, that I need to do it (separate login workflow to another class). Right now I have to pass one parameter to LoginAsync (with private method I have not to do it, because devKey is private property inside ServiceCore), have to write constructor for LoginCore and pass the same dependency injection parameters, which I passed to ServiceCore. I have to create LoginCore instance before calling LoginAsync

I will not use this LoginCore somewhere else, only in ServiceCore, I need not to have dependency injection (because I need not to replace LoginCore, method LoginAsync is actual for any calls. I see only one benefit: I can mark LoginCore as:

[assembly: InternalsVisibleTo("BillComRealTest")] 

and write unit test specially only for LoginAsync method, with mock HttpMessageHandler.

Should I create this separate class with one method for following SRP or enough to create just private method inside ServiceCore ?

Aucun commentaire:

Enregistrer un commentaire