Table of Contents
I have a strong belief that most of the time, there is a clear separation between two concerns: software engineering and coding. Both look similar, both work together, but they aren’t the same.
Software engineering is more than coding in the aspect that it involves more about your work than just your pull request on GitHub. It’s more about the processes and patterns that you apply through your workflow that impact what I mean by engineering here, in this blog post.
Software engineering is about the guarantee that, from the macro perspective, the product and the code that you are working on will correspond to the expectations that they have, both from the product and technical sides.
About the product side, it follows the expectations around the culture and what your company, product or anything else you’re working on has, like:
- If it is what the customer wants;
- If it will bring some quality of life improvement for your customer;
- If it will be a building block for a greater feature,
- And anything else that gives a clear objective for the final customer. Assuming that your “customer” here could be anything in that scenario that will consume the product that you are working on.
About the technical side, the core properties that should be followed in my vision are:
- The guarantee that everything related to your code will follow the expectations around the patterns, the code guidelines that have been discussed in your company, project, etc.
- Ensure that your feature has been tested, by yourself, by systematic tests, here being any kind of test (integration, unit, property, end-to-end, anything).
- Ensure that the documentations are available and up-to-date according to the expectations that you and your coworkers have around the feature/code that you are working on.
- Ensure that the code won’t break the existing codebase.
About my thoughts around what I believe are responsibilities of software engineers that are more than coding, I will write some of my thoughts below:
Documentation as a Resource for the Future
Documentation is one of the most important parts of a project, in my opinion. It’s about the guarantee that the decisions and the resources that you have at the moment you wrote a code have been saved in a way that can be validated in the future, by yourself or any other developer that will need to maintain your code.
Having a powerful context of the past decisions brings to the table the ability to review it and understand why some options have been taken or not. Some projects have been written by people that aren’t in the company anymore and you can’t contact them, so think how much easier it would be for you when you try to run that old project if they had at least one documentation about “How to run Project X”.
Documentation brings to you a safe guarantee that, in the future, yourself from the past prepared all the place answering some of the future doubts that could exists.
Documentation should be an atemporal feature for anyone that wants to build a resilient, scalable, and maintainable software.
Tests as The Reinforcement Guarantee
If your code isn’t supported by tests, your code isn’t production-ready. I would say that for the majority of scenarios, you should have at least 1 test that guarantees the behavior of a given scope.
Recently, I read a great piece of blog posts from Matklad: How to Test, it brings some great material around how you could exactly test your software. And I believe that a strong software should be test oriented, in a perspective where you have the guarantee that, even if you inserted some specific new thing into your system, the feedback loop of the tests that you have will ensure that, if something has been broken, it will be caught up.
Tests are the proof of the axioms of your systems, the rules and the guarantee that your system will be working in a specific way. They aren’t about what exactly users shouldn’t do, but it’s the guarantee that, based on what users really can do, you won’t have a breaking change.
Tests also let you move fast, with the security that if there is any breaking change, it will be easily caught by those ones.
In any other kind of engineering, you have tests, redundancy, and tools that provide safety through their work, like a civil engineer building a bridge. Tests, for software engineers, follow the same idea.
Migrations and Refactors as Engineers
WE DO NOT BREAK USERSPACE!
At the moment that your code goes to production, you have more concerns than just the usability of your code. How many people will be using it? How will a breaking change impact them if you inserted a new one? What are the implications? The second and third order effects of those changes? Can you think of the entire chain of consequences of this action?
You, as an engineer, should be carefully thoughtful about the decisions in your code. The implications of a specific change can impact a lot of customers in a harmful way that even you can’t imagine.
Backward compatibility is a term that I like a lot. Being the guarantee of the interoperability of an older system (as said by Wikipedia), on the software side, it’s the guarantee that we will ensure the same behavior of our APIs even for old clients.
Even for internal tooling or between shared modules across your codebase, you should carefully think about backwards compatibility. You will always have a consumer of an API and, in that scenario, your API is the interface that has been exported by your functions and is being consumed on the other side of your codebase. The guarantee that it won’t break, or that it will change in every place, is a guarantee of less entropy throughout your entire codebase.
Conclusion
This is what I believe are some specific parts of a job of a software engineer, coding is one of the easier parts of the job. You have a lot more concerns to think about regarding your product, your code and other related aspects of the company.
And I believe that we should be more engineers and not just developers.