-
두번 개발하지 않는 방법프로그래밍 2023. 11. 2. 23:23
꼭 읽어보세요. 야근 하기 싫다면...
개발자는 종종 같은 기능을 두번 개발해야 할 경우가 있다.
프로젝트 참조가 중복 참조되거나 네임스페이스 등의 문제로 또는 재귀적 호출이 되는 문제로 같은 기능을 이름만 변경 시켜서 개발해야 하는 문제가 있다.
이 문제는 Clean Architectrue와 관련 있고 준비되지 않은 프로젝트는 결국 재개발되어야 하는 문제가 발생한다.
그럼 어떻게 해결할 수 있을까?
이는 IoC 컨테이너와 DI에 밀접한 관련이 있다.
누군가는 흔히 구현 코드에서 아래와 같이 작업하고 있을지 모른다.
public class TestModel { public string Name { get; set; } public int Age { get; set; } } public class Test { public IEnumerable<TestModel> GetUserInfos() { using (var con = new SqlConnection("")) { return con.Query<TestModel>("SELECT Name, Age From Users", commandType: CommandType.Text); } } } public class Sample { public void Run() { var userInfos = new Test().GetUserInfos(); foreach (var info in userInfos) { Console.WriteLine($"Name:{info.Name}, Age:{info.Age}"); } } }
위 코드에서는 Instance를 new를 통해서 직접 생성하고 바로 함수를 실행시키고 있다.
만약, 다른 라이브러리에서 Test클래스 참조하고 있다고 가정하자.
작업자는 Test클래스가 포함된 라이브러리 클래스를 참조하고 작업할 것이다.그리고 해당 클래스를 누군가는 다시 참조할 수 있고 Test클래스가 포함된 라이브러리를 직접 참조할 수 있다.
문제는 여기서 발생한다.
이미 Test클래스가 참조된 클래스를 참조하고 있으므로 Test클래스가 구현된 클래스를 참조할 수 없게 된다.
이를 “순환 참조 오류”라고 한다.
이렇게 된 경우에는 작업자 클래스에서 같은 기능을 다시 구현해야 한다.
IoC 컨테이너와 DI가 해주는 역활이 테스트 뿐만 아니라 해당 부분도 해결해 줄 수 있다.
우리는 이것을 loose-coupling이라 한다.
그럼 프로젝트 구조는 어떻게 나와야 할까?
예로 아래와 같이 구성할 수 있다.
Root Solution | +-----> Infrastructure | +-----> Domain | +----> Domain | +----> Domain.Infrastructure | +----> Domain.Abstract | +----> Domain.Service.Interfaces | +----> Domain.Services | +----> Domain.Service.Test | +----> Domain.Service.Payment | +----> Domain.Service.Net | +-----> WebApp
위와 같이 구성할 수 있다.
모든 서비스의 구현은 Domain.Services 이하에 구현된다.
구현된 Service의 Interface들은 모두 Domain.Abstract에 선언된다.
위와 같이 구성할 경우 WebApp에서 참조될 모든 Interface들은 Domain.Abstract에 등록된 Interface들이 대상이 되고, 해당 Interface의 구현인 Domain.Service 이하의 구현체가 실행된다.
따라서, 구현 클래스는 Abstract에 종속되게 되고 서비스별 직접 참조가 아닌 Abstract를 참조하여 호출하게 된다.
여기 하나의 팁이 있다.
아래의 코드를 보자.
public static class ScrutorScanExtensions { public static IServiceCollection AddScan(this IServiceCollection services, string domainName, string targetExtensionName) { var files = Directory.GetFiles(AppContext.BaseDirectory) .Where(m => Path.GetFileName(m).Contains(domainName) && Path.GetExtension(m) == targetExtensionName) .ToList(); var assemblies = new List<Assembly>(); files.xForEach(file => { assemblies.Add(Assembly.Load(Path.GetFileNameWithoutExtension(file))); }); services.Scan(scan => scan .FromAssemblies(assemblies) .AddClasses(cls => cls.AssignableTo<IScopeService>()) .AsImplementedInterfaces() .WithScopedLifetime() .AddClasses(cls => cls.AssignableTo<ITransientService>()) .AsImplementedInterfaces() .WithTransientLifetime() .AddClasses(cls => cls.AssignableTo<ISingletonService>()) .AsImplementedInterfaces() .WithSingletonLifetime() ); return services; } }
위 코드는 Scrutor를 이용한 IoC Container 자동 주입 방법이다.
위와 같이 구현한다면 일반적인 ASP.NET Core의 의존성 주입을 자동화 할 수 있다.
도움이 되길 바라며, 해피 코딩.
'프로그래밍' 카테고리의 다른 글
Movin'In 모바일이 포함된 임대 부동산 관리 플랫폼 (0) 2023.11.06 .Net HTTP 라이브러리 비교 (0) 2023.11.06 static method? static class? (0) 2023.11.02 C# 병렬 실행 탐구 (1) 2023.11.02 if else if else if else, no more (0) 2023.11.02