Dec 7, 2016

My Python software development practices

UPDATE ON 2022-11-12

This post is continuously updated list of software development practices that I use every day developing software in Python. They include coding conventions, software design principles and software project management principles.

Well-known conventions and practices

Extensions, exceptions and customization to well-known conventions and practices from the previous section

Python-specific

  • Python code maximum line length is 100 or 120 characters
  • Preferred order of attributes within a class:
    • NAMED_CONSTANTS
    • class data attributes
    • __init__() if present
    • __magic_methods__()
    • @properties
    • @staticmethods
    • @classmethods
    • _private methods
    • public methods (related private and public methods should be placed together for better readability)
  • When overriding a method always call an overridden parent class method (with super) and return its result (if you are not altering it) even if the overridden method is not supposed to return anything then None at the moment (it is a forward compatibility measure)
  • Usage of introspection (e.g. getattr(), hasattr()) and __magic_methods__ override should be well-considered. If a feature can be implemented without introspection or explicit __magic_methods__ it should implemented with out them (with very rare exceptions). Usage of introspection or explicit __magic_methods__ usually is a sign of bad code design or "reinvention of the wheel"
  • Use strict version dependencies to prevent unexpected upgrades. Apply the same rule to the dependencies of your dependencies recursively. Example: dependency-package-name==x.y.z (explanation) → Use poetry
  • Use Python packaging instead of requirements.txt and git-based deploys → Use poetry

Development Process

  • Collective code ownership
  • Code review is a good investment of your time
  • Favor code development performance (productivity) over code run-time performance (with reasonable trade-offs)
  • Favor good enough code and code development performance over perfect code when you have tight deadlines. You can always improve later
  • It is fine to write an optimal code in the first place (in terms of size, performance or resource usage) if it comes at zero or near zero cost (we should not deoptimize code on purpose to avoid being accused in premature optimization).
  • Dedicate time on code run-time performance optimization only if it is really needed. Premature optimization may result in waste of time
  • Every time you put a dirty hack or just something that can be done better into your code put a TODO near it with an explanation and/or description of actions for improvement. It will help to track technical debt and help other developers during refactoring or regular development to understand if they are right to judge this code as strange and to be improved
  • If it is hard to choose between alternative technical solutions, then choose any of them instead of wasting time trying to make the right choice. Later when you have more information or circumstances change you can refactor if the original choice was wrong
  • Using a language feature just to show others that you know the feature is unprofessional
  • Manage to see more lines at the screen at the same time for lesser defect count (vertical orientation of display and meaningless lines elimination may help)
  • Keep development environment close to production as much as possible
  • Keep testing environment identical to production environment (including the deployment procedure)
  • Never submit changes that are known to break something that already works
  • Never remove something that you do not understand or because you do not understand it

Code Design

  • Write code to be read by humans
  • Favor code readability over code run-time performance (with reasonable trade-offs)
  • Maintain code reuse of own code and reuse code from publicly available libraries. Reinventing the wheel is a waste of time
  • Avoid code copy & paste unless you have very strong reasons for it
  • Know the difference between agile and universal: instead of writing a code for all imaginary future use cases write the code that can be easily adapted to many of the future use cases (also known as maintainable code)
  • Maintain the least possible cyclomatic complexity of the code for better readability and smaller defect count
  • Favor a readable code over a well commented code. A necessity for comment is good sign of a poor readability of the code
  • Consider writing a logging message instead of a comment. It will serve two purposes
  • Code run-time performance optimization should start from identifying bottlenecks and their elimination instead of something that is easy to optimize
  • If a literal used twice in the code then prefer putting it to a named constant. Even literals that occur only once deserve to be put in a named constant, because named constant will describe the nature of the literal
  • Do not put .gitignore into git repository. Every developer should be free to ignore whatever extra file he/she has locally (.gitignore should not aggregate every developer's local "mess") → Use .git/info/exclude for developer specific ignores

Code style

  • Maintain a shorter code size in number of lines and characters for better readability and lesser defect count unless it impacts performance or readability
  • TODO format: TODO(author) <LOW | MEDIUM | HIGH | CRITICAL>: textual description of todo
  • A longer variable, function, class or method name is better than an unclear or ambiguous name
  • Code style should be consistent across the entire code base
  • Code base should not contain commented out source code unless it is a part of a comment or TODO.
  • Non-ASCII characters should not be a part of the source code. Presence of such characters is a sign of poor localization, internationalization or parameterization of the code 

Organizational (may be boring for some developers)

  • Every decision should be reasonable (based on reasons)
  • Actual responsibility for a decision always lays on the person(s) who made the decision independent of how it cooked or formalized
  • Every decision should be considered in every longevity term (short, medium and long)
  • Every technical decision should be made considering its effect on business as the most important criteria
  • Technical solutions of a highest efficiency (= effect / expenses) should be chosen during the decision making process
  • Honor established processes, rules, methodologies and patterns, but do not hesitate to step out if it is beneficial in terms of profit and loss

No comments:

Post a Comment