During last weeks’ Git Like a Pro talk I tried to convey the message that switching to Git is much more than introducing a new source control system. It will affect not just the way you commit source code, branch or merge, it changes the entire development workflow. In fact, I’m willing to claim that switching from any centralized source control system to Git and a decent hosted Git service such as GitHub, BitBucket or GitLab can help you to prevent building a monolith. Or maybe I should revert that claim by saying that not using hosted Git will make it a whole lot more difficult to prevent building monoliths. Why? Let me elaborate on this a bit.
Preventing a monolith is difficult and painful, especially if the team is under a lot of pressure to release early and often. Technology like NuGet can help you to distribute components in a controlled way. And if that component needs to expose HTTP APIs, you can use OWIN to host that NuGet component in virtually every kind of host. On an organizational level, you might be aware of Conway’s Law and decide to split your teams in a way that aligns with the envisioned components of your architecture. Physical boundaries will tend to cause your teams to introduce procedures and API contracts that formalize the interaction between those teams. However, that’s, in my opinion, not enough.
If I look back at my own projects, a recurring reason for not building some feature as a component is that would cause unexpected planning dependencies between the teams. So unless it was quite obvious that something could be built as a functional slice, we usually just build the feature into the existing codebase. So why this planning dependency? That’s simple; because we were using Microsoft Team Foundation Server (TFS). TFS offers a nice and integrated collaboration environment for teams, but it used to offer a centralized source control system only. If you assign a team to own a particular component, usually maintained in a dedicated source code repository, only that team can make changes the component. Sure, you can grant access to other teams as well, but then you have no easy mechanism to control code changes that end up in the core code base.
Considering planning dependencies, the worst thing that can happen to a team is that they have to wait for another team to finish a change request or bug report before they can continue. If your team practices an agile methodology like Scrum, it becomes very hard to plan for these things. Usually, this dependency doesn’t popup until you start to work on some part of the code that relies on such a component. Unless the owning team has nothing planned that day, that user story that you carefully planned in your sprint planning meeting will get blocked for a couple of days. If your sprints only run for two weeks, being blocked in such a way is a significant impediment for high velocity teams.
And even if that other team has plenty of time to spare, in most TFS projects, the release strategy for a component is everything but optimized. In many TFS projects I’ve seen, the most advanced thing they do is to add the change set number of the last source control change to the component version. Anything more advanced than that is pretty painful with TFS’s build system. So what is it that Git and hosted Git services offer that TFS doesn’t? I’ve already blogged about this last year, but those that are essential are… pull requests and forking.
Forking a repository on GitHub means that you’re going to create a clone of the original source code repository that is stored under your own account. The crucial feature here is that GitHub will create a link between your clone and the original repository. Your clone gets all the branches and tags from that original and you’re free to create new branches, experiment with the original code base and do other advanced stuff like rebasing. All without affecting the original repo.
You could add some new extension point to the original code or fix that bug that you found while your team was working on some code changes. If the owners of the original repo added build scripts such as PSake as part of the source, you can even build a NuGet package from it and use that for the time being. Now, if you’re confident that the bug was fixed, or that new extension point serves its purpose well, it’s time for that pull request. With such a PR, you’re asking the owners of the original owners to pull your changes into the official code base. The PR serves as a central point for discussions, and code reviews, and may even include status changes and unit test results from their build system. In essence, forking and PRs facilitate the autonomy needed for successful agile teams. You’re never blocked by the other team simply because you can alter the code to your need without going in separate ways. That on itself, is a crucial ingredient for component-driven development in emergent architectures. And I haven’t even started about advanced Git-only release strategies such as GitFlow and GithubFlow or automatic versioning through GitVersion.
Now, some of the TFS proponents around me might say that TFS has supported Git as a source control system for a couple of years now. Hey, they may even tell you that TFS offers pull requests these days. But, it does not support creating cross-repository pull requests yet. Don’t get me wrong though. This blog is not a rant against TFS. But over the last two years I’ve come to realize that we have been held back significantly by using TFS. And although I fully realize that Microsoft has pushed a lot of new features to TFS over the last year or so, we still miss that crucial feature.
If it’s up to me, TFS is not a viable option for large-scale agile development anytime soon. So what do you think? Let me know by commenting below. And follow me at @ddoomen to get regular updates on my everlasting quest for better solutions.