Once I had a conversation about programming education with a director of a programming school. There was one word in that conversation that shifted it into a whole new direction.

We were talking about the curriculum, and my observation was that it mostly teaches specific technologies — TypeScript, React, REST API. That was weird given how rapidly technology changes in this field nowadays.

Which raises a fair question: “What else is there to teach?” I prefer the analogy with driving school. Everyone understands that driving school teaches you to pass the exams, and teaches you actual driving as a side effect. A student who can pass the exam still feels quite uncomfortable on the road at least for the first weeks. And a seasoned driver with a couple of decades of experience could easily fail the exam.

What does the experienced driver have that the top student doesn’t? Driving culture. And that’s exactly what’s missing — not just mastery of technologies, but mastery of the discipline and methods of building software at different levels.

The moment I said the word “culture”, my conversation partner’s gaze drifted somewhere into the distance. You could see a kind of renewed understanding — something new had entered the picture.

So what are we actually talking about? At the product level, we don’t care what language it’s written in or what technology it uses. When a new version of an app ships, we think about new features, release dates, versions. There are various ways to version a product — for example semantic versioning and calendar versioning.

When the conversation moves to the repository, we talk about code style (which can be consistent across different programming languages — tabs or spaces for indentation), programming approach and paradigm, and so on.

One level down — branches and pull requests (a change of what, exactly?…). These are essentially the same thing, since one pull request contains one branch. At this level you get debates about “Merge or Rebase?” and other holy wars.

A branch consists of commits — the minimal unit of code change (which doesn’t always produce a change in product behavior!). There are various methods and cultures for making commits — for example, “commit everything at the end of the day” (horrible) or Conventional Commits. I also really like Arlo.

And finally we get to the code itself — only here do functions, classes, loops and everything else appear, which is essentially the syntax of a language used to assemble implementations and models of algorithms and meta-models. An algorithm is always the same regardless of language; it can be described with a flowchart just as well.

This gives us the following programming stack:

Level Role Functional objects and practices
Product/Code base Product manager/owner Feature, delivery, release, versioning, CI/CD, pipeline
Repository Maintainer Code style, linter, formatter, hook, programming language (paradigm)
Branch/Pull request Submitter, reviewer Merge/rebase, Pull request, branch rules/conventions
Commit Committer Commit rules/conventions, intention
Code change Programmer Programming language (syntax), framework, library