-
Notifications
You must be signed in to change notification settings - Fork 332
Description
Refactor: Modularize the Project
Problem
The current codebase is monolithic, making it difficult to maintain, test, and extend. As the project grows, this structure limits flexibility and increases technical debt.
Check the https://github.com/gitextensions/gitextensions/tree/master/src/app as an example
Proposal
-
Split the codebase into several projects/libraries
-
1nd proposal:
src/App/sourcegit.csproj
src/Commands/Commands.csproj
src/Converters/Converters.csproj
src/Models/Models.csproj
src/Models_and_Native/Models_and_Native.csproj
src/Utils/Utils.csproj
src/VCS_Access/VCS_Access.csproj
src/Resources/Resources.csproj
src/ViewModels/ViewModels.csproj
src/Views/Views.csproj
src/Tests/Tests.csproj
- 2st prposal:
- Core, UI, VCS_Access,.
- Clearly define interfaces and contracts between modules.
- Ensure each module is independently testable and reusable.
Why Modularize? (Arguments Beyond Feature Flags)
-
Loose Coupling, Clear Boundaries: Modularization allows you to separate business concerns into distinct modules, making the codebase easier to reason about and maintain. Each module can be developed, tested, and understood independently.
-
Improved Maintainability: When modules are loosely coupled, changes in one area are less likely to introduce bugs in others. This reduces regression risk and technical debt.
-
Easier Onboarding: New contributors can focus on individual modules, learning and contributing to a smaller, well-defined area of the codebase.
-
Testability: Smaller, focused modules are easier to unit test and mock, improving code quality and confidence in changes.
-
Parallel Development: Teams can work on different modules simultaneously with minimal merge conflicts or coordination overhead.
-
Future Flexibility: Should a need arise to extract a module into a separate service or microservice, a modularized codebase makes this transition much easier.
-
Industry Practice: Modularization allows to get into some industry best practices.
Modularization is not only allow feature flags(like Nuget package Microsoft.FeatureManagement ) or runtime toggles—it's about maintainability, clarity, and future-proofing the codebase for growth and change.
Benefits
- Improved Testability: Smaller, focused modules are easier to unit test.
- Better Maintainability: Isolated changes reduce risk of regressions.
- Enhanced Extensibility: New features are easier to implement.
- Future-Proofing: Make easier to add support for other frontends ( browser ) and for other ways to work with git.
AOT Compatibility Note
This modularization plan does not inhibit .NET Native AOT (Ahead-of-Time) compilation. While AOT does not support dynamic loading of modules or assemblies at runtime, this proposal does not rely on such mechanisms. Instead, all modules are included in the build, ensuring compatibility with AOT's single-executable requirement.
Flexibility can still be achieved by:
- Clearly defining interfaces and contracts between modules to maintain separation and testability.
- Ensuring each module is independently testable and reusable, even when statically linked.
This approach enables maintainability and flexibility without conflicting with AOT constraints.
What Does Modularization Mean?
All modules are compiled into the single executable (as required by .NET Native AOT).
Example:
Suppose you have an advanced analytics module. In your code:
AnalyticsModule.Initialize();If the module is not needed, it can be removed or not initialized.
Additional Argument: Forkability and Community Contribution
A modular codebase is much easier to fork and maintain by independent developers or downstream projects. When modules are clearly separated and loosely coupled, maintainers of forks can more easily adapt or extend only the parts they need, without having to diverge from the upstream project as a whole. This encourages:
- Healthy Ecosystem: Fork maintainers are more likely to contribute improvements and bugfixes back to the main project, since merging changes is simpler when boundaries are clear.
- Reduced Fragmentation: Modularization lowers the risk of incompatible forks and helps keep the community aligned.
- Attracting Contributors: New contributors are more likely to participate when they can focus on a specific module relevant to their needs.
This benefit is especially important for open source projects that want to foster a collaborative, sustainable ecosystem.
Steps
- Identify logical boundaries in the current codebase.
- Create separate projects for each major concern.
- Refactor code to remove cross-project dependencies.
- Add automated tests for each module.
References: