At a recent retrospective meeting, somebody asked a question that inspired a lot of discussion in our group.
“ With so many people at client sites, what should we be doing to share knowledge and engineering culture between teams? ”
In the last six months or so, we’ve embedded a lot more members of our core development team with clients, and it’s been a great experience. We’ve seen benefits from more effective communication, and problems are easier to solve when they come up. To put it another way, it’s helped us enhance collaboration with our clients. A significant advantage of this strategy is that by working in the same room with our customers, we get to show them in person the benefits of how we do things.
General UI’s culture and coding practices are about spreading knowledge throughout the team. That means we work best when we’re face to face (or side by side) as much as possible. We practice pair programming to increase our shared brain power. We alter the makeup of teams, to make sure the project’s success doesn’t depend on any one person. We research new tools and engineering practices and teach them to one another in our weekly Tech Talks. We flag each other down in the hallway to ask for help.
But how do you do that when most of us aren’t working out of the same building every day? As we go onsite to spend in-person time with more and more customers, we create some geographic distance that could affect our collaborative culture.
The more we thought about this question, the more it became clear that we needed to come up with a good answer.
“ As a consultancy with people in the field, our challenge is to make sure that we spread the best of our culture outward, and pull in the best parts from other teams. ”
— Don Biszek, Director of Program Management
Our solution was to call a quarterly summit to spread information around the team. At this summit, everyone in General UI taught the rest of the group something they’d learned. Their topic could be a useful piece of technology, or a new development practice. It could be a warning about a mistake they’d made, or seen someone else make. Any piece of useful knowledge is fair game, as long as it was an improvement.
On any given day, hundreds of teams in Seattle alone are tackling the same basic problem. That problem is: how do you write software well? Being on site exposes us to more of these strategies, and our quarterly summit lets us pick the ones we like.
As we adopt these new methods, some will turn out to be great, but others won’t. Some of them may seem exciting, but we’ll find out they don’t work for us after all. We’ll stop using them, and try something else. The best will make their way through our developers, and then back out to other clients.
Here’s what we picked up from our first summit.
Our team completed a proof of concept – just enough to show it was possible. Then, they moved on to the rest of the application.
Early in the project, the team realized their original approach could be improved. In fact, they foresaw that future improvements to the application would be unnecessarily complicated by the existing architecture. On the other hand, being prepared for the future would entail a huge, and potentially risky refactor of the existing code.The developers would have to tear out every trace of their original approach, and replace it with a new one. This new code would underlie many parts of the application.
If everything worked as it should, they would have a forward-looking application that could handle anything the client might dream of. But, if it didn’t work, the refactor might waste time, and introduce a whole new set of problems.
With the stakes so high, refactoring much of the application without types in place would have been inadvisable. According to the lead developer, it would have blown the project timeline. As it was, though, Typescript had been in place from the beginning of the project. This simplified the challenge posed by the refactor. In fact, it allowed the team to retool a critical part of the front end in just a few days.
“…provides very useful real-time blueprinting information for variables and functions. During development, this can very useful because the content of a variable can easily be forgotten or change without regard to the original intent. Maintaining variable intents as pre-defined types not only avoids risks of unexpected changes, but also provides clear insight to developers what variables are and what types of return values you can expect from functions. ”
— Stanley Jovel, Software Engineer
As a rule, we try to be loyal to an idea rather than a particular way of implementing that idea. So, we’ll leave the choice of Typescript or Flow to the devs who work on a given project. Everybody can have their own preference. The important thing is that we agreed on the value of typing in general.
First things first
Another theme of the summit was saving work by doing things in the right order. Some features are easy to put in place at the beginning of the project, but difficult to add at the end. We want to save ourselves trouble by planning ahead.
“ The foundation of the real production app should meet all of the testing, code, and architectural standards of the team, taking into consideration the whole deliverable of the current SOW. ”
Examples we’ve run into in the last couple months are single sign-on (SSO) and routing. These features are often estimated as one day stories, but that’s only true if you do them early on. If you write a lot of code that assumes you don’t have routing or SSO in place, that’s wasted time. Plus, it’s a lot of work to add them in to a working system and keep that system working, and this work comes at the end of the project, when you’d rather be polishing and optimizing the final result.
As one developer put it, features like these “involve using a pattern throughout the whole app,” and it’s easiest to establish that pattern from the very beginning.
This principle applies not only to SSO and routing, but to other kinds of functionality. Responsive design, API integration, and navigation, for example. In fact, you should tackle all global, pattern-like features as early as possible.
It’s tempting to tackle just the hard, interesting problems first. Often, they seem like the core of the application. Plus, all the boilerplate features can be uninteresting and tedious. We’ve learned that crossing off the boilerplate stuff early leaves you more time for the hard problems later.
At this summit, we returned to an old argument: feature branches, or feature flags… or both? In other words, should developers create a branch for each feature they work on, then merge them all into a single branch for deployment? Or, should they work on a single branch, and toggle features off and on as they are ready for deployment?
We didn’t reach an overall consensus on this. Instead, we discussed the advantages of both, and in what situations we might use one or the other.
We favor feature branches in an environment where we can request frequent pull reviews. In this case, we move commits from branches into master. When we can communicate face-to-face to resolve merge conflicts, feature branches have an advantage.
Our primary use case for feature flags is when testing new features is important. They shorten downtime in the case of a bug sneaking into the deployment. Should the feature cause a problem for the system, or the user experience, you just have to turn it off again.
Promoting our practices
Some speakers talked about the challenge of evangelizing our development practices to other teams. They spoke about the ‘psychological toolbox’ for initiating changes when you’re a consultant. We believe in our development practices, and spread the gospel whenever we can. But, how do we try to improve an existing team’s workflow without being presumptuous? How do we make sure we improve the groups we work with, rather than disrupt a process that (sort of) works. It’s about leading by example, and identifying where the client knows they need improvement.
“ With so many people at client sites, are there things that we should be doing to share knowledge / team-culture between teams? ”
Safety, collaboration, and transparency are some of our core principles. In this case, we needed all three to arrive at the solution we did. Safety means feeling like you can bring up the potential impact of a business decision on the team. Transparency means revealing how we work, both to our team and to our clients, warts and all. Collaboration means coming together to discuss the possibilities and come up with a plan.
Our first quarterly summit was a huge success. People who hadn’t seen each other in months got together for a few hours. We shared gossip. We cracked jokes. In our presentation sessions, we discussed our ideas about to make a great team even better. It helped us stay tight-knit as a group, and gave us a lot of great ideas for how to improve as software engineers.