Managing Common/Utility Libraries in Software Development
When developing software, especially in a collaborative environment, managing shared libraries and utilities can become challenging. Common libraries, often referred to as utility libraries, can include various helper functions and classes that enhance productivity and reduce code duplication. However, issues arise when these libraries undergo changes that disrupt their use across different projects. In this blog post, we will explore a strategy for effectively managing a common utility library, ensuring stability while promoting collaborative development.
The Problem
Imagine a scenario in your organization where a utility project containing crucial helpers like NullHelpers
, ConfigSettingHelpers
, and various extension methods is referenced across multiple applications. As new projects are created, developers pull in the latest version of this common library, attaching it as a project reference. While this setup can work well initially, it leads to potential risks when modifications are made. These modifications may inadvertently introduce “breaking changes,” meaning that while the changes may work for the developer who made them, they could cause failures in other projects that depend on the now-modified library.
This challenge raises an important question: How can we structure our development practices to safeguard against these breaking changes while still fostering collaboration and innovation?
Solution Overview
Transitioning from a project reference setup to a more flexible approach can mitigate some risks associated with breaking changes. Here’s how to do it effectively:
Versioning and Publishing the Utility Library
-
Create a Standalone DLL: Instead of incorporating the utility library as a project reference, develop it as a standalone Dynamic Link Library (DLL). This way, the library can evolve independently, and you can control versions systematically.
-
Increase Versioning with Every Release: Adopt a versioning scheme where you manually increment the version number (e.g., minor version) each time you publish changes. This can help in tracking updates efficiently.
-
Share the Library: After building the utility project in Release mode and signing it, store the DLL in a shared location accessible to all team members. Ensure that everyone is aware of where to find the latest releases.
Utilizing the Library
- Reference Specific Versions: Encourage team members to use specific versions of the library, thereby isolating their projects from potential breaking changes introduced in future versions.
Managing New Features and Breaking Changes
-
Candidate Features: If developers identify useful methods within their project that could benefit the utility library, they should store them in a special helper class. Mark these methods with a
//TODO
comment indicating they are potential candidates for the main utility library. -
Review Process: At the end of the project, review these candidate methods. Adopting a review process allows for a thorough evaluation of features before merging them into the main utility library.
-
Marking Obsolete Methods: Avoid breaking changes by marking outdated or deprecated methods and classes with the
[Obsolete]
attribute. This acts as a warning for developers, guiding them towards updated alternatives.
Continuous Improvement
- Regular Updates and Reviews: Make it a routine practice to review the utility library and adapt based on feedback and usage patterns. Continuous improvement keeps the library relevant and reduces the likelihood of technical debt building up.
Conclusion
Incorporating shared libraries into your software development can vastly improve efficiency and consistency. However, it is paramount to ensure that these libraries are managed effectively to protect against unintended disruptions. By transitioning to a versioned standalone DLL structure, emphasizing candidate methods, and introducing robust review processes, your team can leverage common libraries successfully without sacrificing stability.
Final Takeaway
Remember, handling common libraries
with care not only ensures a smoother development process but also fosters a culture of collaboration and innovation within your team.