Tips for Software Development
- Don’t write code that you think you might need in future, but don’t need yet.
- Tests don’t need testing. Infrastructure, frameworks, and libraries for testing need tests.
- The third time you write the same piece of code is the right time to extract it into a general-purpose helper (and write tests for it).
- When it comes to API design (external facing and object API): Simple things should be simple; complex things should be possible.
- Fail fast. Check input and fail on nonsensical input or invalid state as early as possible.
- Unit tests test to the unit of behavior, not the unit of implementation.
- For unit tests (including test infrastructure tests) all code paths should be tested. 100% coverage is a good place to start.
- Code is the enemy: It can go wrong, and it needs maintenance. Write less code. Delete code. Don’t write code you don’t need.
- Strive to make your code readable and self-documenting through good naming practices and known programming style.
- Write defensively. Always think about what can go wrong, what will happen on invalid input, and what might fail, which will help you catch many bugs before they happen.
- Logic is easy to unit test if it is stateless and side-effect free. Break out logic into separate functions, rather than mixing logic into stateful and side-effect-filled code.
- Globals are bad. Functions are better than types. Objects are likely to be better than complex data structures.
- Using the Python built-in types—and their methods—will be faster than writing your own types (unless you’re writing in C). If performance is a consideration, try to work out how to use the standard built-in types rather than custom objects.
- Dependency injection is a useful coding pattern for being clear about what your dependencies are and where they come from.
- The more you have to mock out to test your code, the worse your code is. The goal is small testable units, along with higher-level integration and functional tests to test that the units cooperate correctly.
- Design external facing APIs carefully, still keeping to the “simple things should be simple” principle.
- If a function or method goes past 30 lines of code, consider breaking it up. A good maximum module size is about 500 lines. Test files tend to be longer than this.
- Don’t do work in object constructors, which are hard to test and surprising. Don’t put code in __init__.py (except imports for namespacing). __init__.py is not where programmers generally expect to find code, so it’s “surprising.”
- Don’t repeat yourself matters much less in tests than it does in production code. Readability of an individual test file is more important than maintainability.
- Refactor whenever you see the need and have the chance. Programming is about abstractions, and the closer your abstractions map to the problem domain, the easier your code is to understand and maintain.
- Make code correct first and fast second. When working on performance issues, always profile before making fixes. Usually the bottleneck is not quite where you thought it was.
- Smaller, more tightly scoped unit tests give more valuable information when they fail—they tell you specifically what is wrong.
- Not invented here is not as bad as people say. If we write the code, then we know what it does, we know how to maintain it, and we’re free to extend and modify it as we see fit.
- Shared code ownership is the goal; siloed knowledge is bad. At a minimum, this means discussing or documenting design decisions and important implementation decisions.
- Generators rock! They’re generally shorter and easier to understand than stateful objects for iteration or repeated execution.
- Let’s be engineers! Let’s think about designing and building robust and well-implemented systems, rather than growing organic monsters. Programming is a balancing act.
- Intermittently failing tests erode the value of your test suite, to the point in which eventually everyone ignores test run results because there’s always something failing. Fixing or deleting intermittently failing tests is painful, but worth the effort.
- Generally, particularly in tests, wait for a specific change rather than sleeping for an arbitrary amount of time.
- Always see your test fail at least once. Put a deliberate bug in and make sure it fails, or run the test before the behavior under test is complete. Otherwise you don’t know that you’re really testing anything.
- And finally, a point for management: Constant feature grind is a terrible way to develop software. Not letting developers take pride in their work ensures you won’t get the best out of them.
Curiosity Ai Team
Join Our Newsletter
Reducing waste through automation!
We design and implement custom software solution helping forward thinking customers automate vital operational and production processes in order to increase productivity and achieve exponential growth.
Together with our customers/partners we also try to identify how to maximise the value of operational data through artificial intelligence implementations.