在过去的几年中,我们一直在缓慢地转换为逐渐更好的书面代码,每次只需几个小步骤。我们终于开始切换到至少与SOLID类似的东西,但是我们还没有到那儿。自从进行切换以来,开发人员最大的抱怨之一就是他们无法忍受同行审查和遍历数十个文件,而以前的每个任务只需要开发人员触摸5-10个文件即可。
在开始进行转换之前,我们的体系结构非常类似于以下内容(已授予,但又增加了一个或两个数量级的文件):
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不兼容的第三方系统进行通信的仓库以及建立用于处理某些操作的复杂性的逻辑方法时,这个数字急剧膨胀。