Trong vài năm qua, chúng tôi đã dần dần chuyển đổi sang mã được viết tốt hơn, một vài bước một lần. Cuối cùng chúng tôi cũng bắt đầu thực hiện chuyển đổi sang một cái gì đó ít nhất giống với RẮN, nhưng chúng tôi chưa hoàn toàn ở đó. Kể từ khi thực hiện chuyển đổi, một trong những phàn nàn lớn nhất từ các nhà phát triển là họ không thể xem xét ngang hàng và duyệt qua hàng chục và hàng chục tệp mà trước đây mọi tác vụ chỉ yêu cầu nhà phát triển chạm vào 5-10 tệp.
Trước khi bắt đầu thực hiện chuyển đổi, kiến trúc của chúng tôi đã được tổ chức khá giống như sau (được cấp, với một hoặc hai đơn đặt hàng nhiều tệp hơn):
Solution
- Business
-- AccountLogic
-- DocumentLogic
-- UsersLogic
- Entities (Database entities)
- Models (Domain Models)
- Repositories
-- AccountRepo
-- DocumentRepo
-- UserRepo
- ViewModels
-- AccountViewModel
-- DocumentViewModel
-- UserViewModel
- UI
File khôn ngoan, mọi thứ đều cực kỳ tuyến tính và nhỏ gọn. Rõ ràng có rất nhiều sự trùng lặp mã, khớp nối chặt chẽ và đau đầu, tuy nhiên, mọi người đều có thể vượt qua nó và tìm ra nó. Những người mới hoàn thành, những người chưa bao giờ mở Visual Studio, có thể tìm ra nó chỉ trong vài tuần. Việc thiếu độ phức tạp của tệp tổng thể khiến cho các nhà phát triển mới làm quen và tuyển dụng mới bắt đầu đóng góp mà không mất quá nhiều thời gian. Nhưng điều này là khá nhiều khi bất kỳ lợi ích của phong cách mã đi ra ngoài cửa sổ.
Tôi hoàn toàn tán thành mọi nỗ lực của chúng tôi để cải thiện cơ sở mã hóa của chúng tôi, nhưng rất phổ biến để có được một số phản hồi từ phần còn lại của đội trong các thay đổi mô hình lớn như thế này. Một vài điểm gắn bó lớn nhất hiện nay là:
- Bài kiểm tra đơn vị
- Đếm lớp
- Độ phức tạp đánh giá ngang hàng
Các bài kiểm tra đơn vị đã cực kỳ khó bán cho nhóm vì tất cả họ đều tin rằng họ lãng phí thời gian và họ có thể xử lý kiểm tra mã của họ nhanh hơn nhiều so với từng phần riêng lẻ. Sử dụng các bài kiểm tra đơn vị như một sự chứng thực cho RẮN hầu hết là vô ích và chủ yếu trở thành một trò đùa vào thời điểm này.
Số lượng lớp có lẽ là trở ngại lớn nhất để vượt qua. Các tác vụ được sử dụng để lấy 5-10 tệp giờ có thể mất 70-100! Mặc dù mỗi tệp này phục vụ một mục đích riêng biệt, khối lượng tệp tuyệt đối có thể áp đảo. Phản hồi từ đội chủ yếu là rên rỉ và gãi đầu. Trước đây một tác vụ có thể đã yêu cầu một hoặc hai kho lưu trữ, một hoặc hai mô hình, một lớp logic và một phương thức điều khiển.
Bây giờ, để xây dựng một ứng dụng lưu tệp đơn giản, bạn có một lớp để kiểm tra xem tệp đã tồn tại chưa, một lớp để viết siêu dữ liệu, một lớp để trừu tượng hóa DateTime.Now
để bạn có thể tiêm thời gian để kiểm tra đơn vị, giao diện cho mọi tệp chứa logic, tệp để chứa các bài kiểm tra đơn vị cho từng lớp ngoài đó và một hoặc nhiều tệp để thêm mọi thứ vào thùng chứa DI của bạn.
Đối với các ứng dụng cỡ nhỏ đến trung bình, RẮN là một sản phẩm siêu dễ bán. Mọi người đều thấy lợi ích và dễ bảo trì. Tuy nhiên, họ chỉ không thấy một đề xuất có giá trị tốt cho RẮN trên các ứng dụng quy mô rất lớn. Vì vậy, tôi đang cố gắng tìm cách cải thiện tổ chức và quản lý để giúp chúng tôi vượt qua những cơn đau ngày càng tăng.
Tôi hình dung tôi sẽ đưa ra một chút mạnh mẽ hơn về một ví dụ về khối lượng tệp dựa trên một nhiệm vụ đã hoàn thành gần đây. Tôi đã được giao một nhiệm vụ để thực hiện một số chức năng trong một trong các dịch vụ siêu nhỏ mới hơn của chúng tôi để nhận được yêu cầu đồng bộ hóa tệp. Khi nhận được yêu cầu, dịch vụ sẽ thực hiện một loạt các tra cứu và kiểm tra, và cuối cùng lưu tài liệu vào ổ đĩa mạng, cũng như 2 bảng cơ sở dữ liệu riêng biệt.
Để lưu tài liệu vào ổ đĩa mạng, tôi cần một vài lớp cụ thể:
- 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
Vì vậy, đó là tổng cộng 15 lớp (không bao gồm POCO và giàn giáo) để thực hiện tiết kiệm khá đơn giản. Con số này tăng lên đáng kể khi tôi cần tạo POCO để đại diện cho các thực thể trong một vài hệ thống, xây dựng một số repos để liên lạc với các hệ thống bên thứ ba không tương thích với các ORM khác của chúng tôi và xây dựng các phương thức logic để xử lý các vấn đề phức tạp của một số hoạt động nhất định.