Some time ago Piotr Stapp explored the “leader” part of the staff+ engineer role. It’s the part that often eludes new staff+ engineers or those aspiring to such a role. In contrast, the “engineer” part of staff+ engineer seems to be the obvious part (it’s even in the name). But is it obvious? In my experience, not necessarily. In fact, there is an ongoing debate about whether software engineering qualifies as "real" engineering.
Many claim that software engineering isn’t really engineering because it’s not governed by strict standards and licensing requirements (which would regulate the educational process). It’s hard to deny these arguments when we take a broader look at software quality and reliability (and their consequences). When it comes to education, the apprenticeship often outweighs or replaces any formal approach. To be honest, our discipline often leans toward craftsmanship and I won’t deny that.
On the other hand, one of the possible (not required) paths into our discipline is through a formal engineering education that can lead to an official engineering title. Software engineering is an officially recognized, legitimate field within engineering.
The problem is that many people in software engineering don’t practice engineering.
What is Software Engineering?
I once ran a workshop for a cohort of young tech leads. During this workshop I’ve defined software engineering as the systematic application of engineering approaches and criteria to the development of software. This is my paraphrase of the IEEE definition which states that software engineering is the systematic application of scientific and technological knowledge, methods, and experience to the design, implementation, testing, and documentation of software.
Why did I use my own definition? Because I wanted to push the conversation beyond “knowledge and experience” applied to a specific subset of activities (design, implementation, testing, and documentation). I wanted to establish, together with that group, something more tangible. That’s why I’ve introduced “criteria” into my definition, because they imply conditions that should be met. This approach worked, and I’ve decided to stick with the concept of “engineering criteria” in many subsequent discussions about software engineering. How do I define them? As a set of rules, conditions, guidelines or characteristics for projects, related processes and delivery methods. Yes, that’s broad. The goal is to leave room for selecting appropriate criteria for a given project in a given context but at the same time to emphasize that there must be a strictly defined list that covers all the important areas if we are to dare to say that we are practicing software engineering. Of course, I do have my initial list of engineering criteria that I use to start the discussion with a team.
What Should You Consider as Engineering Criteria?
On the one hand, you probably won’t find anything surprising on my list. To be honest the industry has been talking about these things for years. And that’s exactly why I’ve included them in my engineering criteria - after all, engineering is about following well established standards. On the other hand, I’ve seen countless projects and organizations that lacked at least some, if not all, of them. Discussing some of them also proves to be quite challenging.
Unfortunately, I will not be able to do justice to each criterion in detail. Each of them deserves its own article. Here I’ll just touch on them, along with some key considerations. That said, let me jump to the first one.
Coding standards. Yes, in 2024 there is still a need to discuss coding standards as a basis for engineering criteria. And I don’t have anything fancy in mind, just the basics like naming conventions, code organization, code formatting, or error handling. Think about how many of your projects started with a team sitting down and creating a set of rules for them. That may be a smaller number than we would like to admit. I’m also pretty sure that more than once you’ve seen a new team member start writing code in a completely different way, because that’s the way he likes it, and the existing standards are stupid to him. Coding standards are something that should be established at the very beginning, tools should be configured to enforce them, and the topic should be closed unless a new area comes up that needs to be covered. And the conversation shouldn’t be religious as it often is - it should be pragmatic, looking for quick consensus between different preferences (you can run GitHub statistics if you want to resolve arguments). The goal is not to have the most beautiful code in the world. The goal is consistency, readability, and maintainability. They also allow for mature discussions about the second criterion.
Code reviews. Controversial, I know. Very often code reviews are being seen as a negative practice that hinders efficiency. They can be. You may be able to not have them because of a different team culture (pair programming, mob programming) or mature testing and automation criteria (yes, I’ll get there). But you may have to have them as a quality gate, because your other quality gates are not there yet. Or you may be in a highly distributed and asynchronous team that wants to use code reviews as a knowledge-sharing tool. The first problem with code reviews is that people focus on the wrong thing. Code reviews should be about function, not form. Form should already be taken care of by coding standards and tools that enforce them. The second problem with code reviews is when they are not being given the right priority by the team. Therefore, if we need code reviews, their rules and priority should be enforced by tools. That said, code reviews can never be the only quality gate, so the next part of the criteria discussion you should have is how you’re going to approach testing.
For testing to be considered an engineering grade quality gate, it cannot be an afterthought. Yet the old meme of developers throwing tasks “over the wall” to testers is still very much alive in many organizations. Establishing a well-thought-out testing strategy for the entire project should be part of the initial design. The same goes for testing specific features - as the team grooms them, they should also discuss how they will test them. The goal should always be to choose a testing approach that balances the highest reasonable confidence with the lowest reasonable cost. There is a trap in my previous statement. Taking it at face value can often lead to manual testing being seen as the right choice. This is not necessarily wrong. If we are building a “one-off”, manual testing toward the end of the project may be the right approach. But as the number of iterations increases, manual testing becomes less and less efficient. So we need to think about the future when looking for this balance. After all, engineering is about repeatable standards and that requires automation.
Yes, automation is a necessary engineering criterion, unless we do something only once. And I don’t just mean test automation. We should consider automation for any process that can be standardized. It will also allow us to free teams from repetitive, error-prone tasks that machines can do much better than we can. The obvious first processes to automate are the ones you’ve probably heard a lot about: continuous integration and continuous delivery/deployment. Keep in mind that these processes shouldn't just exist for the sake of existence - they have a purpose. The continuous integration workflow should be a quality gate, it is where you enforce coding standards (through static analysis) and run tests. You can also bring in additional aspects such as security or third-party dependency management here. The continuous delivery/deployment workflow should be your source of truth about how you deliver your project. Ideally, it shouldn’t have any manual steps, and if it does, they should be triggered by it through automated task creation. That way your team is not focused on how to push to production, but on how things behave in production. This brings us to the next criterion - observability.
The observability strategy for your project, like the testing strategy, should be part of the initial design. You should decide, at least at a high level, how you will use the key observability signals to be able to operate and maintain your project. Properly designed logs (structured, correlated, and with configurable levels) will provide the ability to reproduce what has happened in the system. The right metrics should allow you to understand the state of the system at any given time. And for the critical transactions you should have configurable traces to capture a comprehensive set of information about their journey through the system. This information, along with proper documentation, will enable a standardized and efficient approach to resolving production issues.
Documentation. Last but certainly not least. Often despised, but always crucial. Knowledge tends to fade away, but knowledge is power! This is why a true engineer will document the important knowledge. What knowledge is important? That’s easy, the harder it is to reverse engineer the knowledge the more important it is. You should also use established documentation approaches that are likely to be familiar to changing team members. Consider approaches like the Architecture Decision Log to capture past context, things that have been tried, and the reasoning behind the choice of one decision or another. You can use the C4 model for structured diagrams. There are other techniques for capturing other aspects - choose the one you need.
Software Engineering Is About Following Standards
Is my list of engineering criteria exhaustive? No. Is everything on this list mandatory? Not necessarily. It’s a discussion starter. A discussion starter designed to highlight the core idea behind the engineering approach - you should set standards and make sure they are followed.
That’s what I do with every one of my engineering criteria. I establish a standard with the team and put tools or automation in place to enforce it. Done right, this becomes part of the team's culture. The team will look for new areas that can be treated the same way. Because having the right standards in place takes the burden off and creates safety. Such an environment allows the craftsmanship part of our discipline to really flourish where it should.