Software engineering tools and version control

IDEs, CASE tools, documentation, and version control: commits, branches, merges and finding the commit that broke the robot.

A14.6Software development, law and ethicsA level40 min

Do this lesson in the simulator

Implementation turns the design into data structures and code a computer can run. On a real project this is done by a team, over months, with thousands of changes. Software engineering is the discipline of doing that reliably, and it depends on tools: an IDE for writing and debugging, CASE tools for the whole lifecycle, and version control so a team can change the same code without losing work. At GCSE you met the IDE (F6.6); this lesson adds the tools that make teamwork possible.

The IDE

An integrated development environment puts the tools a programmer needs in one program:

Feature How it helps
Editor with syntax highlighting, auto-indent and auto-complete fewer typing and syntax errors, faster writing
Error diagnostics syntax errors are underlined with a message before the program runs
Breakpoints stop the program at a chosen line to inspect it
Stepping run one line at a time and watch the path the program takes
Watch windows show variables' values changing as the program runs
Run-time environment and translator run the program without leaving the editor
Refactoring tools rename a variable everywhere it is used, safely

Breakpoints, stepping and watches are what find logic errors, the ones that give no error message.

CASE tools

CASE (computer-aided software engineering) tools support the whole lifecycle, not only coding:

  • diagramming tools for structure charts, data flow diagrams, class diagrams and entity relationship diagrams, which keep the design consistent with itself;
  • code generators that produce skeleton code or database definitions from a design;
  • automated testing tools that run the whole test suite after every change (regression testing, lesson A14.5);
  • documentation generators that build a reference from the comments and docstrings in the code;
  • project management tools that track the backlog, tasks and bugs.

Documentation

Two audiences need documentation:

  • Technical (maintenance) documentation is for programmers who will change the system: the design, the purpose and interface of each module, the data structures, and the test plan. Most of it lives in the code as meaningful identifiers, comments and docstrings, where it is most likely to be kept up to date.
  • User documentation is for the people who use it: how to install it, how to do each task, what the error messages mean, and troubleshooting.

Code that is modular, consistently laid out to a coding standard, and well named is cheaper to maintain, because most of the cost of software comes after release (lesson A14.1).

Version control

A version control system (VCS), such as Git, records every change to a project's files, who made it, when and why. The files and their history are kept in a repository.

Term Meaning
Commit a saved snapshot of the project, with a message saying what changed and why
History (log) the list of commits, so any earlier version can be looked at or restored
Diff the lines added and removed between two versions
Revert undo a commit by making a new commit that reverses it
Branch a separate line of development, so a new feature can be built without disturbing working code
Merge join a branch's changes back into the main branch
Merge conflict two branches changed the same lines differently; a person must decide which to keep
Clone, push, pull copy a repository, send your commits to a shared one, and fetch others' commits

A diff is how programmers review each other's changes. Python can show one:

import difflib

commit_2 = ['while distance() > 20:', '    forward(50, distance=5)', 'led("green")']
commit_3 = ['while distance() > 20:', '    forward(100, distance=50)', 'led("green")', 'tone(880, 0.3)']

for line in difflib.unified_diff(commit_2, commit_3, "commit 2", "commit 3", lineterm=""):
    print(line)

Run this in the simulator

Lines starting - were removed, lines starting + were added, and lines starting with a space are unchanged context. @@ -1,3 +1,4 @@ means lines 1 to 3 of the old version became lines 1 to 4 of the new one.

Why teams use version control

  • Nothing is lost: any version can be recovered, so a disastrous change is one command away from undone.
  • Accountability: every line can be traced to the commit, the person and the reason. When the robot starts crashing into walls, the history shows which commit introduced it.
  • Working in parallel: each developer works on a branch; merging combines the work, and conflicts are flagged rather than one person silently overwriting another.
  • Releases: a commit can be tagged as version 1.2, so the exact code on every robot in every school is known.
  • Review: changes are proposed, read as diffs, and approved before they are merged.

A typical feature is built like this:

git switch -c beep-on-arrival      # make a branch for the feature
(edit, test)
git commit -am "Beep when parked"  # snapshot with a message
git switch main
git merge beep-on-arrival          # bring the feature into the main line

Continuous integration takes this further: every commit pushed to the shared repository is automatically built and tested, so a change that breaks the tests is found within minutes, by the person who made it.

Finding the commit that broke it

When a bug appears, the history answers "when did this start?". Look at the versions in order and find the first one that has the problem. Git automates this with bisect, which uses a binary search over the commits (lesson A5): with 1000 commits, about 10 tests find the one that broke it.

Task: the commit log

versions is a list of commits in order. Each is a tuple (message, text): message is a string, and text is the whole program at that commit, as one string with lines separated by \n.

Write a function changes(old, new) that takes two such texts and returns a tuple (added, removed). A line counts by its exact text, including its indentation. If a line appears more times in new than in old, the extra appearances count as added; if it appears more times in old than in new, the extra appearances count as removed.

Compare each commit with the one before it; the first commit is compared with the empty string "". For each commit print commit <n>: <message> (+<added> -<removed>), numbering from 1. Then find the first commit whose text contains the string in BUG, and print bug introduced in commit <n>: <message>. The robot stays still.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

versions = [
    ("first drive", "from bugbot import *\nconnect()\nforward(50, distance=20)"),
    ("stop at the wall", "from bugbot import *\nconnect()\nwhile distance() > 20:\n    forward(50, distance=5)"),
    ("faster approach", "from bugbot import *\nconnect()\nwhile distance() > 20:\n    forward(100, distance=50)\nled(\"green\")"),
    ("beep when parked", "from bugbot import *\nconnect()\nwhile distance() > 20:\n    forward(100, distance=50)\nled(\"green\")\ntone(880, 0.3)"),
]
BUG = "forward(100, distance=50)"

def changes(old, new):
    pass

Challenges

  1. Two students edit the same line of approach() on different branches. Describe what happens when the second branch is merged, and how it is resolved.
  2. Write bisect(versions, bad) that finds the first version containing bad by testing the middle version each time, and count how many versions it looks at.
  3. List three things a user guide for the delivery robot must contain, and three things its technical documentation must contain.