Skip to content

Cycle time

B. K. Oxley (binkley) edited this page Aug 22, 2024 · 39 revisions

Cycle time

An important concept for writing programs is cycle time. This is how long it takes from having an idea until users see benefits. There are other definitions that break up this general concept into specific portions of development.

Each project should develop their own notion of cycle time(s)! This is a great discussion with others on "ways of working":

  • What do we measure during development?
  • Who is interested in improving these measurements?
  • Who benefits from going faster?
  • Do benefits depend on particular kinds of work? (documentation, deployments, new features, managing projects, etc)
  • Are folks on project happy? Do they like the pace of improving the project? (No one finds slow work fun. I wanted to say "slow work is unfun", but maybe it should be anti-fun, the enemy of enjoying your work.)

For this project, I'm focused on: How long from when programmers start work until it is ready to deploy from CI. So discussion is not about:

  • Time from forming a new idea until turning it into work you can start
  • Time from a deployable CI build until when users see your changes
  • Time for management to track different kinds of work

This is my focus because I am focused on your build pipeline. You should have awesome build pipelines that make you happy! The above "not" list is important, and worth your effort, but not what I'm writing about.

In pictures

Here might be a picture of Cycle Time end-to-end (these are duplicated in What is a build pipeline):

flowchart TB

idea("Idea for improvement")
card("Turn idea into potential work")
analysis("Flesh out work needed")
process("Discussion and moving work to "ready"")
dev("Programmers pick up ready work")
progress("Programmers turn work into feature")
push("Feature goes to the CI pipeline")
ci("CI pipeline builds work")
ready("Feature ready to deploy")
deploy("Feature goes into production")
users("Use software")

subgraph idea_steps [Idea]
  idea-->card
  card-->analysis
  analysis-->process
end

subgraph work_steps [Work]
  process-->dev
  dev-->progress
  progress-->push
  push-->ci
  ci-->ready
  ready-->deploy
end

style work_steps stroke:black,stroke-width:4px

work_steps-->|New ideas|idea_steps

subgraph deploy_steps [Users]
  deploy-->|Feature|users
  users-->|Start again|idea
end

deploy_steps-->|New ideas|idea_steps
Loading

And here is a more focused picture:

flowchart TB

red("RED:<br>Work on programming")
green("GREEN:<br>Local tests pass (unit, et al)")
refactor("REFACTOR:<br>Improve and clean up code")

coverage("Local coverage passes")
local_checks("Local checks pass")
push("Push to shared CI")

pushed("New changes in CI")
ci("Run full build")
ci_checks("Same checks as local + CI-specific checks")
ready("Result ready to deploy")

subgraph work_steps [Write some code]
  refactor-->red
  green-->refactor
  red-->green
end

work_steps-->push_steps

subgraph push_steps [Prepare Git push]
  coverage-->local_checks
  local_checks-->push
end

push_steps-->ci_steps

subgraph ci_steps [CI]
  pushed-->ci
  ci-->ci_checks
  ci_checks-->ready
end
Loading

But what should I do?

The key tools for improving cycle time are measure and decide. Yes, that is all! With such generic advice, maybe examples would help.

Example 1 — nothing to decide

Everything works as expected:

  • Developers are happy with local build times.
  • CI completes quick enough to meet everyone's expectations.
  • Project quality and security are solid.

This really is the happy path, and what you strive for. And ... there is nothing to change. Your project is in a sweet spot, so be happy. However, keep measuring: you want to stay in this place, and tracking is minimal effort so worth it to stay on top of things.

Tips

Let's say you are most interested locally in the red-green-refactor cycle as you write unit tests and passing code, and want to wait until time to push for a full local build with style checks and static analysis. You can do this!

# Run only tests, no other tools to check your code.
# Wait until "push" time for a full build including all checks
$ ./gradlew test 
# OR
$ ./mvnw test

Then after you are happy with the tests and code, you can look for other concerns before sharing work with others:

$ ./gradlew clean build
# OR
$ ./mvnw clean verify
# THEN if all is green
$ git push  # Your commits

Note that the CI builds call "Earthly" as a CI container for your builds. This is a containerized build that you can also run locally.

Specific to this example project

You can take advantage of the the "ignores" feature in your CI configuration. This project has both Gradle and Maven builds, and we don't want to, for example, run the Gradle build when only Maven-specific files change, and vice versa.

The example project uses .github/workflows/ci-earthly-gradle.yml for the Gradle CI build, and .github/workflows/ci-earthly-maven.yml for the Maven CI build,

Going further

TODO: Placeholder section

Clone this wiki locally