지난 몇 년 동안, 우리는 한 번에 몇 단계 씩 단계적으로 개선 된 코드로 점진적으로 전환 해 왔습니다. 우리는 마침내 적어도 SOLID와 비슷한 것으로 전환하기 시작했지만 아직 멀지 않았습니다. 전환 이후 개발자의 가장 큰 불만 중 하나는 이전에 모든 작업에서 5-10 개의 파일을 다루는 개발자 만 필요했던 수십 및 수십 개의 파일을 동료 검토하고 통과 할 수 없다는 것입니다.
전환을 시작하기 전에 아키텍처는 다음과 같이 구성되었습니다 (1 ~ 2 배 더 많은 파일이 부여됨).
Solution
- Business
-- AccountLogic
-- DocumentLogic
-- UsersLogic
- Entities (Database entities)
- Models (Domain Models)
- Repositories
-- AccountRepo
-- DocumentRepo
-- UserRepo
- ViewModels
-- AccountViewModel
-- DocumentViewModel
-- UserViewModel
- UI
현명하게, 모든 것이 엄청나게 선형적이고 컴팩트했습니다. 분명히 코드 중복, 긴밀한 결합 및 두통이 많았지 만 모두가 그것을 통과하고 알아낼 수있었습니다. Visual Studio를 오픈 한 적이없는 완전한 초보자는 단 몇 주 만에 알아낼 수있었습니다. 전체적인 파일 복잡성의 부족으로 초보자 개발자와 신입 사원이 너무 많은 램프 업 시간없이 기여하기 시작하는 것이 비교적 간단합니다. 그러나 이것은 코드 스타일의 이점이 거의없는 곳입니다.
코드베이스를 개선하려는 모든 시도를 진심으로지지하지만, 이와 같은 대규모 패러다임 전환에 대해 팀의 나머지 부분에서 약간의 피드백을 얻는 것이 일반적입니다. 현재 가장 큰 두 가지 문제는 다음과 같습니다.
- 단위 테스트
- 수업 수
- 동료 검토 복잡성
단위 테스트는 모두 시간 낭비라고 생각하고 각 조각보다 개별적으로 코드 전체를 훨씬 빠르게 처리 테스트 할 수 있다는 점에서 팀에게 엄청나게 판매되었습니다. SOLID에 대한 승인으로 단위 테스트를 사용하는 것은 무의미했으며 현재로서는 농담이되었습니다.
클래스 수는 아마도 극복해야 할 가장 큰 장애물입니다. 5-10 개의 파일을 가져 오는 데 사용 된 작업에 이제 70-100이 걸릴 수 있습니다! 이러한 각 파일은 고유 한 용도로 사용되지만 파일의 양은 압도적 일 수 있습니다. 팀의 반응은 대부분 신음과 머리 긁힘이었습니다. 이전에는 작업에 하나 또는 두 개의 리포지토리 (모델 또는 둘, 논리 계층 및 컨트롤러 방법)가 필요했을 수 있습니다.
이제 간단한 파일 저장 응용 프로그램을 만들려면 파일이 이미 있는지 확인하는 클래스, 메타 데이터를 작성하는 클래스, 추상화 할 클래스가 DateTime.Now
있으므로 단위 테스트 시간, 로직이 포함 된 모든 파일의 인터페이스, 파일을 주입 할 수 있습니다. 각 클래스에 대한 단위 테스트와 DI 컨테이너에 모든 것을 추가하는 하나 이상의 파일을 포함합니다.
중소형 응용 분야의 경우 SOLID는 매우 쉽게 판매 할 수 있습니다. 누구나 유지 보수 용이성과 이점을 봅니다. 그러나 대규모 응용 프로그램에서 SOLID에 대한 가치 제안은 보이지 않습니다. 따라서 조직과 관리를 개선하여 점점 커지는 고통을 극복 할 수있는 방법을 찾고 있습니다.
최근에 완료 한 작업을 기반으로 파일 볼륨의 예를 조금 더 강력하게 생각했습니다. 파일 동기화 요청을 받기 위해 최신 마이크로 서비스 중 하나에서 일부 기능을 구현하는 작업을 받았습니다. 요청이 수신되면 서비스는 일련의 조회 및 검사를 수행하고 문서를 네트워크 드라이브와 2 개의 개별 데이터베이스 테이블에 저장합니다.
문서를 네트워크 드라이브에 저장하려면 몇 가지 특정 클래스가 필요했습니다.
- IBasePathProvider
-- string GetBasePath() // returns the network path to store files
-- string GetPatientFolderName() // gets the name of the folder where patient files are stored
- BasePathProvider // provides an implementation of IBasePathProvider
- BasePathProviderTests // ensures we're getting what we expect
- IUniqueFilenameProvider
-- string GetFilename(string path, string fileType);
- UniqueFilenameProvider // performs some filesystem lookups to get a unique filename
- UniqueFilenameProviderTests
- INewGuidProvider // allows me to inject guids to simulate collisions during unit tests
-- Guid NewGuid()
- NewGuidProvider
- NewGuidProviderTests
- IFileExtensionCombiner // requests may come in a variety of ways, need to ensure extensions are properly appended.
- FileExtensionCombiner
- FileExtensionCombinerTests
- IPatientFileWriter
-- Task SaveFileAsync(string path, byte[] file, string fileType)
-- Task SaveFileAsync(FilePushRequest request)
- PatientFileWriter
- PatientFileWriterTests
따라서 총 15 개의 클래스 (POCO 및 스캐 폴딩 제외)는 상당히 간단한 저장을 수행합니다. 이 수치는 소수의 시스템에서 엔티티를 나타 내기 위해 POCO를 생성하고 다른 ORM과 호환되지 않는 타사 시스템과 통신 할 수있는 리포지토리를 구축하고 특정 작업의 복잡성을 처리하는 논리 방법을 구축해야 할 때 크게 증가했습니다.