Nothing can substitute a great team. But a real warrior has to be able to rely on thyself if needed.
A few people nowadays, work on a team of one.
People that are subject matter experts and the very best on their fields (and I am the last human on earth who can give them any professional advice).
People that have just founded, solo, their own company (or their company partners are not technical).
Or people who work always remotely, and in a vastly different time zone compared to the headquarters, where getting help from other colleagues might be difficult.
Testing your work, the broccoli of day-to-day software engineering.
The first skill I can think of, that we all need to pay attention to, is to test our own dev work, more effectively. QA guys are great, but you work together on this case, you don’t just throw your crap to the other side of the fence.
Like broccoli, it is hard to do it (or eat it) but very beneficial to your professional life (or health).
Over time, I have gathered a few tips, the number of which I want to grow more. Let’s start.
Be a badass dad and break ‘em
Being a developer is mostly about giving value through the features you make. Being a tester is about giving value through the elimination of the errors that exist in the software.
If you don’t figure out how to become more cold-blooded against your beloved creature, you can never succeed on this journey. I believe I still have lots of work to do here, so any tips are appreciated.
Plan the cases before
What will you test eventually? The written specifications are the only source of truth here. Do a few passes through them, until you can visualize the final product/feature, as much as possible, inside your head.
Do not hesitate to underline the points you think important and do follow up with questions to the product/feature owner(s).
So, now that you have the big picture, you can use something like the pseudo-algorithm below to make a testing plan.
Break the functionality into testable parts
For each one of the above part:
Write down the “happy paths” that derive from the specs
Write down the boundary values that derive from the specs
Write down any crazy paths you might think off, as they might be not that crazy when released to the public
Think the various parts can be triggered and how this can affect the system and keep regression in mind
So, you finished a function? Test it now. Did you finish a class? Test it now and I hope you have already tested the individual functions alone. Some people make it more extreme, by testing every N lines of code.
Given the chance, do not listen to other people saying that this time-consuming. YOU are in charge of the quality of your deliverables and your career, not them; so make sure you ignore the sirens of low quality (which can be quite compelling). Unless this is a directive from the management, so maybe it is better to discuss it with them first, before ignoring them. 🙂
And this is because, the earlier you find an issue, the easier (and thus with less cost) will be to tackle it effectively.
At this stage, I am talking about manual testing. But as for the TDD lovers, this is not negotiable. Tests are being written, even before the source code files are created.
Test often and automatically
Even though you can perform this part with manual testing, automated tests are totally the way to go. I have written about unit testing in a previous article and if overcome the initial effort to have a great percentage of coverage you will be very compensated.
Today, there is ubiquitous tooling (i.e Continuous integration solutions, where the tests can run on every commit) to let you do a regression testing to your whole platform with one-click, so automated testing is, in my humble opinion, a high-reward investment.
Use a “randomizer”
Above, in point “Plan the cases before” we mentioned the need to identify crazy paths. As mentioned in the first point “Be a badass dad and break ‘em”, we are not good at finding flaws in our code. So how about letting “others” decide the inputs to the system under test? That’s where randomizers come to the rescue.
Randomizers can be as simple as a loop of few hundred iterations, that give every combination of ASCII characters, numbers and…mongo objects (ok, I am exaggerating a bit) as input to a field representing…age and then counting the number of errors, non-graceful handling, and success. Or sophisticated libraries.
Make sure your tests agree with the architecture.
That’s simple enough, for example, don’t do load tests, if you don’t care about performance. If there are no non-functional requirements, to be precise.
Static and dynamic analysis
Static and dynamic analyzers are tools that cannot be missing from our arsenal and can prevent a percentage of issues, in time, from being released.
If you need a list for dynamic analysis tools, please target the search to your favorite language, looks like I could not find any massive lists, language agnostic (like with the static analysis).
Make sure that all lines are executed once.
Sometimes 100% coverage for automated tests is hard, due to limitations with dependencies. So, at least try and execute all the lines by hand, by giving the necessary inputs to the function.
Last but not least, you will never be as a good as a QA.
Don’t give in, don’t get discouraged, don’t settle, and know your weaknesses. Only God and chocolate are perfect in this world.
Thank you for reading this article, I hope you enjoyed it. I am really curious to hear the approaches of great engineers in that matter, so your comments are more than welcome. But please remember, that we are talking about a “team of one dev”.