A pleasant walk through computing

Comment for me? Send an email. I might even update the post!

Configuring Iterations for Teams in Azure DevOps

I don't know how much guidance Microsoft gives on creating Iterations. This is my approach.

The Basics

Here's the Azure DevOps structure, regardless of usage:

|_Process [Work items defined]
  |_Project(s) [Iterations defined]
    |_Team(s) [Board defined, Iterations selected]
      |_Area(s) 
        |_Work Item(s) [assigned to Area and Iteration]

There's always a top-level "iteration" with the name of the project, which can't be changed. This is confusing because everything in the iteration tree is called an iteration, but in fact you should think of the tree as folders of iterations.

You configure iterations at the project level (Project Settings > Boards > Project configuration). However, a Team chooses which iterations it uses. In other words, adding iterations to the project does not add them to all teams.

While initially confusing, this gives a lot of flexiblity in the project. Everyone can be on the same sprint cycle, or individual teams can be on their own cycle.

The Most Common Configuration I Recommend

Here's how I'd set up a project that has one or two teams, which should be all that are on an Agile-based project anyway.

Notice I do not use the root level for the product backlog. Unfortunately, Microsoft doesn't help enough in setting this up.

Baskets-R-Us Website
|_Product Backlog
  |_Sprint 2021-04-16
  |_Sprint 2021-04-30

Why "product backlog"? In Team configuration > Iterations, there are two settings: Default iteration, Backlog Iteration.

Default Iteration means "when I create a new work item, which iteration is it assigned to?" The default is @CurrentIteration. This is wrong! New work items should not be automatically added to the current sprint: that's contrary to Scrum thinking. Instead, I set Default iteration to the team's product backlog iteration.

Likewise, Backlog iteration means "When we look at our backlog, which iteration is at the root?" That should be, of course, the product backlog iteration. That's why I keep the naming clean.

Both teams on this project would use the same product backlog and iterations. The teams would have independent boards and work items because by default a team has its own area.

The result is that, in sprint planning, everyone would work from the same product backlog. Assuming Scrum, the project (product) should have a single Product Owner and Scrum Master shared by the two teams. When work items are assigned to iterations, they're also assigned to the team's area, allowing each team to filter for its work items in its boards.

Naming Iterations

Where organizations often go astray is naming.

Here's one way iterations might be organized for multiple teams. Again, notice my naming.

Baskets-R-Us Website <== root level folder
|_ eCommerce Product Backlog
  |_2021-04-07
  |_2021-04-30
|_Social Media Product Backlog
  |_2021-04 05-16
  |_2021-04 19-30

In this case, the teams within the project are working very independently. They don't share a backlog, instead each team maintains its own.

Yet Another Approach

Here's another--arguably better--way to organize multiple teams on a single Scrum-based project where the teams want to use their own sprint cycles. On a single project with just a couple of team. That's probably not a good idea. Keep the teams working as closely together as possible on the same project.

This rule of thumb doesn't apply on teams across projects, who shouldn't be constrained in how they independently work. They not only should have separate DevOps projects, but should be allowed to have their own process template.

Baskets-R-Us Website <== root level folder
|_Product Backlog
  |_ eCommerce Sprints
    |_2021-04-07
    |_2021-04-30
|_Social Media Sprints
    |_2021-04 05-16
    |_2021-04 19-30

Given this organization, both teams would set their default and backlog iterations to "Product Backlog." The clear naming will help them find their iterations.

The fact that it's harder to work with the sprints might be a clue that the teams should share an iteration cycle.

The Wrong Way

Some organizations (believe) they want all employees and teams to use the same process, and even share the same backlog and board. This can be done in Azure DevOps, but frankly I think it's anti-Agile, anti-productive, and there's plenty of evidence to back me up.

Really, don't do this. It encourages a top-down, tightly-coupled, bureaucratic culture.

If you're determined, here's how you might do it by taking advantage of the little-used (for good reason) Areas feature.

Using multiple Areas should be reserved for really complex projects

Remember, work items are assigned to an Area and Iteration. What we're doing here is inverting (and subverting) the Azure DevOps structure by turning Areas into Projects.

|_MRU Process [THE Monsters-R-Us Process]
  |_Monsters-R-Us Project [The ONLY project in the entire company]
    |_MRU Team [EVERYONE including vendors. Iterations defined here. Backlog/Board defined here]
      |_Area - MRU Website
        |_Work Item(s) [assigned to Area and Iteration]
      |_Area - MRU Mobile Applications
        |_Work Item(s)
      |_Area - MRU Developer Experience
        |_Work Item(s)
      |_Area - Internal DevOps Improvements
        |_Work Item(s)

What this allows:

  • Any employee can be assigned work in any area
  • All work items are in a single, monolithic backlog that can be filtered by area
  • Single, monolithic board that can be filtered by area or person

I'm sure someone will say Tags can be used for categorization and filtering. That's true, but adds complication.

Wrap Up

Azure DevOps is a quite capable suite of features that will work for many types of organizations. Because of that, it can be challenging to understand how to configure well.

Hopefully, this helps you along toward your own success.

Basic Daily Git Commands, including "Rebase is Good"

These are the commands I use on a daily basis. Hopefully this helps explain and put to rest the fear of rebase.

I have aliases for these that mostly came from Phil Haack.

The below commands assume your mainline branch is named 'main'. Adjust accordingly if it's called 'master,' 'trunk', etc.

# Start day getting latest
git checkout main
# Create a new branch
git checkout -b features/my-feature
# work for a half hour
git add -A
git commit -m "Did some work"
# push branch to remote in case I die
git push --set-upstream origin features/my-feature
# work another couple of hours, occasionally syncing to remote
# (one liner)
git add -A && git commit -m "Did some other work"
git push
# ready to submit PR. I want my code to be *after* the latest, so . . .
git checkout main
git pull [gets latest changes]
git checkout feature/my-feature
git rebase main
# deal with any merge conflicts, then squash and force push
git rebase main --interactive [I squash all commits into one]
git push --force
# I'm done. Create the pull request.

Q&A

Isn't rebase bad and you should never ever do it because everyone says so?

No. Rebase is good and you're listening to the wrong people. It's what significantly reduces merge conflicts in your pull requests. What's bad is not understanding what rebase does and what problems it could cause.

When rebasing onto main, you're saying, "If I merge my changes into main now, they'll be in the middle of what's already committed. I want them at the end. So take my changes and apply them to the end of main as if I just made them."

From Git's point of view, these are new commits, so they get new file hashes. That's why you have to force-push them, overwriting the remote branch.

This is OK as long as:

  1. You do not ever rebase main onto a branch and then push main.
  2. If someone else is working on your branch with you, you tell them to git pull --force.

The first one you should never, ever even think of doing. The second one is rare because developers tend to work indepedently on short-lived branches.

When it comes to merge vs rebase, the directions of change are always:

Merge from branch into main. Rebase branch onto main.

When you "merge from", you start in main. When you "rebase onto" you start in the branch.

What about merge conflicts?

That's a whole other topic. What matters is using a good diff/merge tool. The one I use, KDiff3, is really old but I like it best.

Professional Development Fundamentals

The one thing missing from this guide right now is tracking work in an Agile way. I plan to add that later.

Contents

Local Development Cycle

Release small often

  1. Pull and rebase latest code from mainline.
  2. Work from a short-lived feature branch.
  3. Unit test, frequently commit locally, push branch when it passes tests.
  4. Integrate latest mainline locally, run private build/tests, push.
  5. Final push, create a pull request.

Pull Requests and Code Reviews

No unreviewed code

  • Another developer reviews the PR (code review)
  • PR merges into mainline

Continuous Integration

Build once, deploy-to-many

  • CI Server is triggered by source control changes.
  • Build Triggered by mainline and feature branch changes. Build in clean environment, run unit tests, create deployment package.
  • TDD Always runs and fully automated. Environment is created and deployed to from scratch. Automated integration tests run.
  • UAT Runs if mainline changes and TDD succeeds. Existing environments deployed to. Some automated testing. Users perform acceptance tests.
  • Prod Runs if UAT succeeds and deployment is approved. Existing environment deployed to. Some automated smoke testing. Can require approval.

Aspects of quality code

Code is never finished

  • Loosely coupled Dependencies are reduced. See SOLID, DRY, YAGNI.
  • Complexity reduced Packages, classes, methods have one purpose.
  • Tested early Unit testing reduces defects and improves architecture. See TDD.
  • Reviewed Code reviews improve quality and share knowledge.
  • Clearly named Naming (of classes, methods, variables) is hard and important.
  • Self-documenting What the code does should be obvious. Comment why the code does what it does, when not obvious.
  • Properly versioned Harder than it seems. See Semantic Versioning and your language's package peculiarities.
  • Maintanable and replaceable No code lasts forever. Design for change.

Capabilities of high-performing software teams

A couple of principles can guide making lots of better decisions.

  1. Reduce friction to doing the right thing
  2. Do all the steps

Here are the 24 capabilities of high-performing software organizations from the DORA group's meticulous, evidence-based research.

Capability (and desired result)
CONTINUOUS DELIVERY CAPABILITIES
01 Version control
02 Deployment automation
03 Continuous integration (CI)
04 Trunk-based development
05 Test automation
06 Test data management
07 Shift left on security (put first, make easy)
08 Continuous delivery (CD)
ARCHITECTURE CAPABILITIES
09 Loosely coupled architecture
10 Empowered teams
PRODUCT AND PROCESS CAPABILITIES
11 Customer feedback
12 Value stream mapping
13 Working in small batches
14 Team experimentation
LEAN MANAGEMENT AND MONITORING CAPABILITIES
15 Change approval processes (lightweight, not external)
16 Monitoring
17 Proactive notification
18 WIP limits (limit work-in-progress)
19 Visualizing work (public Kanban boards)
CULTURAL CAPABILITIES
20 Westrum organizational culture (Generative)
21 Supporting learning
22 Collaboration among teams
23 Job satisfaction
24 Transformational leadership

The Four Key Metrics

How do you know you're succeeding?

Again, from the DORA group.

  • Deployment Frequency How often an organization successfully releases to production
  • Lead Time for Changes The amount of time it takes a commit to get into production
  • Change Failure Rate The percentage of deployments causing a failure in production
  • Time to Restore Service How long it takes an organization to recover from a failure in production

Resources