0% found this document useful (0 votes)
19 views29 pages

50 Coding Laws That Would Make You A Decent Programmer. - by Alexander Obidiegwu - Medium

Uploaded by

walteravelin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views29 pages

50 Coding Laws That Would Make You A Decent Programmer. - by Alexander Obidiegwu - Medium

Uploaded by

walteravelin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Get unlimited access to the best of Medium for less than $1/week.

Become a member

50 Coding Laws That Would Make


You A Decent Programmer.
Follow these laws or get fired.

Alexander obidiegwu · Follow


24 min read · Mar 2, 2024

1.97K 25

There are hundreds or probably thousands of Python best practices out


there and depending on who you ask, you would get some slight variation on
a given practice.

The internet has given everyone the right to voice an opinion. Including even
me. But in this article, we will be dealing with 50 Python best practices that
are set in stone.

These are practices that even God himself can’t tweak. These practices
differentiate the pro from the amateur and a lot of them can also be adapted
for various programming languages.

Most Python developers need somewhere to quickly test their code or debug errors. I
developed a website called python-fiddle.com which you can use to quickly test out
a code and it uses AI/LLMs to help find solutions to possible errors.
I plan to start posting content on linkedln too so if you’re interested: My Linkedln:
https://www.linkedin.com/in/alexanderobidiegwu

LAW 1: Avoid Comments At All Cost


Comments have a way of being falsely true. They deviate the mind of the
reader from what the code is actually doing to what someone else says it’s
doing.

This can become very problematic as time passes and the code receives
updates or changes. At some point, the comment becomes a lie and
everyone now has to observe the truth through the lens of the lie.

Comments must be avoided at all costs. A comment forces the reader to


inherit your thinking which at best is in the past. When a function or class
changes, most likely, its comments do not change along with it. Most likely,
they block the reader from thinking forward.

A comment signifies that the writer was mentally incapable of providing a


well-descriptive class, function, or variable name. It exposes the lackluster
attitude of the programmer and forces the team to inherit such an attitude.

Avoid comments at all costs.

In Law 14 and 15, you would learn when and when not to use a comment.

LAW 2: Do Not Use Type Attributes As A Name For Variables


Sometimes we want to specify that a particular variable is a string or an int.
Some developers would therefore name the variable like this:
name_of_variable_str or name_of_variable_int .

This can be quite redundant especially if the variable is intuitively a string. A


name variable, for instance, can never be an int type.

But when the variable type isn’t intuitive, rather than specifying the type
when naming the variable, the best way to do this is to use type annotations.

name_of_variable:str = value instead of name_of_variable_str = value .

This way, everyone can tell the variable is a string while keeping the code
neat & concise.

LAW 3: Class Names Should Be Nouns.


It’s always best practice to keep your class names as nouns.
This is mostly because a class object is used to identify or represent a bunch
of characteristics and actions. Similar to how a goat represents some
characteristics like horns and actions like nod_nearby_humans .

It also makes the code very readable and less redundant. For example,
Goat.get_horn_length() instead of GetGoat.get_horn_length() .

LAW 4: Function Names Should Be Verbs


Functions are best named as verbs because they help the neighboring
developer clearly understand what actions they perform.

It also eradicates the need for comments and allows any developer to
mentally conceptualize without having to look at the raw code.

LAW 5: Functions Should Specify The Parameter And Return Type


When defining a function, you want to always specify what the arguments’
types are and also what data type the result of the function returns.

This would help both you and the devs in your team know what to expect
without always having to use print statements to get a visual understanding.

Bad Practice

Run code

Good Practice

Run code

LAW 6: A function Must Perform One Functionality Only


Junior devs are fond of breaking this rule. Having a function perform one
function is crucial because it helps expose where the bugs are located,
enables reusability, and does exactly what the function name says.

You don’t want to do something like this…

(Note that the methods and attributes are just for example purposes.)
Python fiddle

This checks if the address is valid and after checking returns the latitude and
longitude. The function does two things. Checks if the address is valid and
returns the geolocation of the address.

Here is a better way of doing this.

https://python-fiddle.com/saved/bQD3sPFuC4BWeTx1gdLr

The above functions do only one thing and nothing more. Although it may
seem more verbose, it’s a lot more concise and readable.

Knowing exactly what is “one” functionality can be a bit difficult, especially


for new devs. You need to be very specific on what you want a function to do.

Usually, if you can extract or group some of the actions in a function as a


whole other function, then it’s probably doing more than one thing.

Another way you can tell is if it has more than one level of abstraction…

LAW 7: Functions Should Be At The Same Level Of Abstraction


When we talk about functions being at the same level of abstraction, we’re
referring to the idea that a function should perform a single, well-defined
task. That task should be at a consistent level of abstraction throughout the
function.

In other words, the function should focus on a specific level of detail or


complexity, and all the functions’ operations should operate at that same
level.
Search Write

Good Practice

https://python-fiddle.com/saved/ezGiYtWK72HXiVm65azM?run=true

This function has statements that are of a low level of abstraction. Things
like sum , len, etc.

Bad Practice

run code here

This function, for instance, has a bunch of levels of abstraction.


get_numbers() is a high level of abstraction, the list comprehension is an
intermediate level of abstraction, and sum is a low level of abstraction.

Basic REST API Principles That make you a 1% programmer.


And it only takes 10 minutes
medium.com

LAW 8: A Function and It’s Argument(s) Should Be Like Brothers And


Sisters
A function name should be closely tied to its arguments. You don’t want to
have a function that seems to do one thing and the arguments passed do not
correlate with the function name.

Bad Practice
write(True)

Good Practice

write(name)

The second one is more descriptive of what exactly the function is doing. It is
clear to whoever reads this that we are writing a name.

The first one isn’t as explicit as the second. You have to make guesses and
possibly even have to view the entire function.

LAW 9: Functions Should Be Small


A function is meant to be reusable. And the bigger the function gets, the less
likely it is to be reusable. This also correlates to why a function should do
only one thing. If it does only one thing, there’s a high chance it’s going to be
small.

I plan to start posting content on linkedln too. so if you’re interested: My


Linkedln: https://www.linkedin.com/in/alexanderobidiegwu

LAW 10: Avoid Noise/Redundant Words


There are times when devs use words that don’t provide any further
clarification on a variable or function’s meaning. Things like this:

https://python-fiddle.com/saved/BfPEC7YYSEHQhz2xgGTW

Without having prior knowledge of the function’s implementations, a


developer seeing this doesn’t know which function to use.

LAW 11: Do Not Be A Dirty Programmer


Any senior dev would tell you he only feels clean when his codes are clean.
This is because a dirty code makes up a dirty programmer. A clean code
encourages everyone on the team to continue writing clean code. You must
aim to always write clean code.

But what is a clean code? A clean code is well structured and arranged.

A clean code doesn’t hide bugs. It exposes anywhere a bug could hide to the
programmer and makes room for an easy fix without complete refactoring.

LAW 12: Open Closed Principles


The open-closed principle (OCP) states that a class, method, or function
must be open for extension but not modification. This means that any class,
method, or function defined can be easily reused or extended for multiple
instances without changing its code.

Let’s take for instance, we have a class called address.

https://python-fiddle.com/saved/6kfW6eccopYfotqaKlcR?run=true

This fails to adhere to OCP because whenever there’s a new country, we


would need to write a new if statement to complement that. This might
seem simple now but imagine we have 100 or more countries to take into
account. How would that look?

This is where OCP comes into play.

https://python-fiddle.com/saved/AEbfUZvVQ0k55RyHcypB
This is a more robust solution because now we don’t need to modify either
the class or its functions. If we ever want to consider a country and its
capital, we can simply adjust our capital dictionary.

Another common example you would see is using class inheritance.

For example:

This is a wrong method because anytime we want to add a new payment


method, we would always need to modify the PaymentProcessor class.

A better way to do this is:

This way, whenever we need to add a new payment option, say crypto or
paypal, we wouldn’t need to edit or modify any class to achieve this. we could
simply do this:
LAW 13: Liskov Substitution Principle
If we look at the previous principle, when making payments using crypto, we
don’t exactly specify the cryptocurrency we are transferring. We only specify
an amount. So suppose we want to specify a cryptocurrency, we would
usually do something like this:

from abc import abstractmethod

class PaymentProcessor:

@abstractmethod
def pay_tax(amount, crypto):
pass

Then when calling each payment processor, we declare the crypto argument
as a None type or give it a default value to avoid passing in any argument if
Top highlight
not needed. Both cases fail to adhere to the Liskov Substitution Principle.

This is because the parent class or the abstract class, contains an argument
that isn’t relevant to most of our subclasses

The Liskov Substitution principle (LSP) states that “Objects of a superclass


should be replaceable with objects of its subclasses without affecting the correctness
of the program”.

To adhere to LSP, we would need to define the cryptocurrency within the


CryptoPaymentProcessor class to avoid any irrelevant clash with other
subclasses.
class CryptoPaymentProcessor(PaymentProcessor):
def __init__(self, crypto):
self.crypto = crypto

def pay_tax(amount):
print(f'Your {self.crypto} wallet is being processed for tax payment')
print(f'You are to be charged {amount}')

LAW 14: Know When To Use A Comment


Every time you need to use a comment, be ashamed of your inability to
express yourself in code. But there are some situations whereby the use of
comments can actually help to express the underlying workings of a code
than the code itself. Here are 5 best examples of “good” comments.

Informative comments
Making comments informative can always help express the code to the
reader. A comment that highlights the return value of a function, for
instance, would provide more clarity. But comments like this can be made
redundant through the use of well-descriptive functions or variable names.

TODO comments
Comments like this help other programmers know that this is an unfinished
function/task or it requires modification. Maybe there’s a better way to
implement a certain function that wasn’t taken advantage of. Maybe the code
fails periodically.

Regardless of your reason, comments like this provide more value than they
take. TODO comments are also less likely to be left untouched as the code
changes or improves because they are usually remembered to be removed
once the task has been completed or modified properly.

Warning of consequences
Sometimes, we want to tell other developers about potential landmines.
Stepping on these landmines could have some unforeseen consequences.
And we want to all survive through the day. Comments can save the day in
this situation.

Suppose a certain code takes time or has the possibility of overloading


certain systems, a warning like #CONSUMES A LOT OF COMPUTING RESOURCES

would be beneficial to a reader or other programmers.

LAW 15: When Is A Comment Bad?


Noise comments
These are comments that reinstate the obvious. They provide no further
information and only increase the verbosity of the code. A lot of times, we
skip through comments like this when we see one. Examples of noise
comments are:

# adds to animal list


animal.append(dog)

Non Local information


One mistake a lot of programmers make when using comments is giving
information about global information locally. When writing comments,
ensure that it remains relevant only to the function or statement it is
referencing. Anything outside of that should be pruned out.

Unobvious comments
We often write comments that seem obvious to us but not to someone else.
The connection between your comments and the function referenced must
be clear. They must both follow the same step or procedure at sync. You
don’t want your comment to need to have its comment as well.

Short Functions
Most likely we do not need a comment for a short function. The
shorter/smaller the function, the more likely it can be described with a good
name. Hence, they are usually self-descriptive.

3 Ways To Run A Python Function Asynchronously


You would most likely fail as a Python programmer without
understanding this ground concept. Asynchronous Programming.
medium.com

LAW 16: Keep Source Files Short


A source file should be between 100–200 lines with 500 lines at most. Unless
you have very good reasons to choose otherwise. Keeping a source file short
has various obvious benefits such as reusability and readability. They are
also easier to maintain and update since we spend less time scrolling and
trying to connect the dots.

LAW 17: Know When To Use Blank Lines


Blank lines are a way to tell the reader we are progressing into a new and
separate concept. Each group of lines represents a complete thought. It
helps readers understand when a thought ends.

LAW 18: Keep Related Lines Of Code/Functions/Classes Close


Go where you are valued

Can you remember when you had to scroll all the way to the top of the script,
just to find out what a function does and how it relates to where it’s being
called?

The worst part of this is you can’t understand the relation in one glance. It’s a
back-and-forth movement. Once you’ve experienced this, you’ll understand
how valuable it is to keep related code to each other.

A function/Variable should be as close to where it’s needed the most or has


the most importance. It should be furthest away from where it has the least
importance.

LAW 19: Know When To Use White Spaces


We use white spaces to show that two things are not strongly related and no
white space to associate things that are strongly related. For instance when
defining functions…

def create(name):
print(name)

There exists no whitespace between the parenthesis between the function


and the name variable. If there was, it would look very disjointed and
uncoordinated…

def create (name):


print (name)

Arguments passed into a function, should be separated to show that the


arguments are separate.

LAW 20: Obey Team Rules


Almost every developer has his/her style. From the way we name our files, to
the way we write print statements.

But when it comes to working with other devs, you want to dumb down those
personal preferences and adopt the team’s preferences. Not everyone might
be able to see beauty in your code the way you do.

LAW 21: Avoid Magic Numbers


A Magic Number is a hard-coded value that may change at a later stage, but
that can be therefore hard to update.

For example, let’s say you have a Page that displays the last 50 Orders in a
“Your Orders” Overview Page. 50 is the Magic Number here because it’s not
set through standard or convention, it’s a number that you made up for
reasons outlined in the spec.

Now, what you do is you have the 50 in different places — your SQL script
( SELECT TOP 50 * FROM orders ), your Website (Your Last 50 Orders), your
order login ( for (i = 0; i < 50; i++) ) and possibly many other places.

# Bad
SELECT TOP 50 * FROM orders

# Good
NUM_OF_ORDERS = 50
SELECT TOP NUM_OF_ORDERS * FROM orders

LAW 22: Avoid Deep Nesting


Limit the levels of nesting within loops, conditionals, or functions to
improve readability.

# Bad
if x:
if y:
do_something()

# Good
if x and y:
do_something()

LAW 23: Avoid Temporary Variables

# Bad
temp_result = calculate(x, y)
final_result = temp_result * 2

# Good
final_result = calculate(x, y) * 2

LAW 24: Avoid Cryptic Abbreviations


Use descriptive names instead of cryptic abbreviations to enhance
readability.
# Bad
def calc(x, y):
pass

# Good
def calculate_total_price(quantity, unit_price):
pass

LAW 25: Avoid Hardcoding Paths


Refrain from hardcoding file paths or URLs; use configuration files or
environment variables instead.

# Bad
file_path = "/path/to/file.txt"

# Good
import os
file_path = os.getenv("FILE_PATH")

10+ Scalability Laws To Follow In Your Next Project.


Don’t Touch your keyboard without understanding this
medium.com

LAW 26: Always use Try-Catch-Finally Statements


When writing code, it’s always best to include error handling also. This can
help speed up the debugging process and increase the sophistication of the
code while keeping it clean and manageable.

You want to use try-catch statements when a certain code is more likely to
return an error.

Things like API requests, file handling, etc tend to fail or raise errors due to
one reason or the other. Using try-catch statements for multiplication or
division is just uncalled for and creates more problems than it solves.

LAW 27: Provide Context with Exceptions


Whenever you catch an exception, it should provide enough context for
anyone who encounters it to know where the problem is from and debug
accordingly.

Create informative error messages along with your exceptions which can be
done when printing the error. Mention the context in which the operation
failed and the type of failure.
Law 28: Avoid Using Multiple Exception Class
Have you ever seen a code like the one below…

try:
pass
except ValueError:
pass
except TypeError:
pass
except IndexError:
pass
except KeyError:
pass
except FileNotFoundError:
pass

This is extremely bogus and takes away (in verbosity, complexity, and
maintenance) the additional help it provides in error handling.

It’s often better to use a more general exception to catch any sort of error we
might come across. This type of exception, by default, includes the type of
error we got.

try:
pass
except Exception:
pass

Only be specific about the type of error you want to catch, when you want all
other errors to pass through.

LAW 29: A function must either mutate or return something, but not both.
Whenever we are creating a function, we should keep in mind what exactly
that function is supposed to do. Does it mutate the arguments passed? Or
does it need to return something?

If the function mutates the argument(s) passed, we only need to do that in


that function and nothing else.

But what do I mean by mutation? If the function changes the contents of the
argument(s) or changes the data type of the arguments, it mutates.

def changed(array):
array.append('hello')
If the argument(s) is used to create another variable, then it doesn’t mutate.
For instance, if an argument called time was used to calculate a distance ,

then it doesn’t mutate, which means distance can be returned in that


function.

def calculate_distance(time, speed):


distance = speed * time
return distance

But there’s a way to get the best of both worlds. You can copy the argument(s)
of the function and perform mutation on those. This way we avoid any side
effects.

def changed(array):
array_copy = array[:]
array_copy.append(4)
return array_copy

LAW 30: Not all function names should be verbs


Yes, I know. I previously said all function names should be verbs, which is
true generally, but there are times when a function name should take the
form of a noun. And knowing when it should take either is based on the
previous law/ law 29.

If a function returns something without mutating its arguments, the


function’s name should be a noun. If a function mutates the arguments and
returns none, it should be a verb.

This is a common convention built into Python itself. Methods such as sort,
and append are verbs because they mutate the data type and return None

while methods like sorted, sum, product are all nouns because they don’t
mutate any arguments passed and return a new copy of the data.

There are obviously exceptions to this and whenever you feel you’ve
encountered one, feel free to fall back on using verbs.

LAW 31: Classes should be small


Yep! Classes should be as small as possible. Just like functions.

The only difference is that in functions, size is determined by the number of


lines in that function while in classes, it is determined by the number of
responsibilities in that class.
Usually, a class name represents the kind of responsibilities it might possess
but when the name is ambiguous or too general, most likely we are giving it
too much responsibility.

This takes us back to SRP (single responsibility principle) which states that a
class should only have one reason — one responsibility — to change.

LAW 32: Classes should have a small number of instance variables


Instance variables, in case you don’t know, are variables that are defined
when the class is defined or instantiated.

class Animal:
def __init__(self, name):
self.name = name #instance variable

If all our functions are related to the class responsibility, there’s no reason
why we should have a lot of instance variables.

When we begin to have tons of instance variables, is when certain functions


in the classes deviate away from the core responsibility of the class.

These functions tend to come with their own variables that other functions
in the class do not need.

LAW 33: Your classes should be cohesive.


All the functions in your class should contain one or more of the instance
variables. The more your functions relate to or contain the instance
variables in your class, the more cohesive your class is.

LAW 34: Use the with Statement for Resource Management


Use the with statement to automatically manage resources like files or
database connections, ensuring they are properly closed or released.

# Bad
file = open("example.txt", "r")
data = file.read()
file.close()

# Good
with open("example.txt", "r") as file:
data = file.read()

LAW 35: Avoid Complex Ternary Expressions


Refrain from using overly complex ternary expressions; favor readability
over brevity to make code more understandable.

# Bad
result = "even" if number % 2 == 0 else "odd" if number % 3 == 0 else "neither"

# Good
if number % 2 == 0:
result = "even"
elif number % 3 == 0:
result = "odd"
else:
result = "neither"

10 Hard Python Projects For Intermediates To Boost Your Python


Skills & Portfolio.
Timeline to finish each project — 1 month
medium.com

LAW 36: Use ‘is’ and ‘is not’ for Identity Comparison
Most of the time, we use == to check the comparison between two variables.
This is usually okay for immutable data types like strings or integers because
immutable objects with the same value are usually stored in the same
memory location, so a memory location check is not needed.

But when dealing with mutable data types, such as list, dicts and custom
objects, it’s often better to use the is comparator because it checks the
subtype of the variable and the memory location.

The memory location of mutable objects are usually not the same due to the
way Python works. Python stores mutable objects in different memory
locations because they can be changed at any time and each of them must be
independent of one another even though.

Strings, tuples, and integers cannot be changed once created.

Run this using the link below:


https://python-fiddle.com/saved/nV6iEIyBuHm2mevD9Bhg

# Example 2: Checking if two lists refer to the same object


list1 = [1, 2, 3]
list2 = [1, 2, 3]

# Less preferred: Using ==


if list1 == list2:
print("Lists are equal in value")

# Preferred: Using is
if list1 is list2:
print("Lists are the same object")

# Note: In this case, list1 and list2 are different objects with the same value,
# so using `is` would give a different result than `==`.

LAW 37: Dependency Inversion Principle


The Dependency Inversion Principle (DIP) is a fundamental principle of
object-oriented design that promotes loose coupling between components
and facilitates easier maintenance and extension of software systems.

It states that high-level modules should not depend on low-level modules,


but both should depend on abstractions.

In other words, classes should depend on interfaces or abstract classes


rather than on concrete implementations.

# Bad
class Logger:
def log(self, message):
with open('log.txt', 'a') as f:
f.write(message + '\n')

class Calculator:
def __init__(self):
self.logger = Logger()

def add(self, x, y):


result = x + y
self.logger.log(f"Added {x} and {y}, result = {result}")
return result

In the example above, we define the class Logger and directly create a new
instance of it in our Calcuator class. This means that Calculator now
depends on Logger class and if for any reason we change Logger class, we
now also have to modify Calculator class.

And as you can see this also fails to adhere to the open closed principle
(open for extension, closed for modification).

This tight coupling makes the code harder to test because we can no longer
simply use a fake logger class when testing.

# good
from abc import ABC, abstractmethod

class LoggerInterface(ABC):
@abstractmethod
def log(self, message):
pass

class Logger(LoggerInterface):
def log(self, message):
with open('log.txt', 'a') as f:
f.write(message + '\n')

class Calculator:
def __init__(self, logger: LoggerInterface):
self.logger = logger

def add(self, x, y):


result = x + y
self.logger.log(f"Added {x} and {y}, result = {result}")
return result

This promotes modularity because changes to one component do not


necessarily require changes to other components as long as the interface
remains consistent.

This modularity enables easier understanding, modification, and extension


of the codebase.

LAW 38: Avoid Using ‘assert’ for Data Validation


Use assert statements for debugging and development purposes only; avoid
using them for data validation in production code.

# Bad
assert x > 0, "x should be positive"

# Good
if x <= 0:
raise ValueError("x should be positive")

LAW 39: Avoid Hard-Coded Numbers


Use named constants instead of hard-coded values. Write constants with
meaningful names that convey their purpose. This improves clarity and
makes it easier to modify the code.

def calculate_discount(price):
discount = price * 0.1 # 10% discount
return price - discount

The example below uses the hard-coded number 0.1 to represent a 10%
discount.

This makes it difficult to understand the meaning of the number (without a


comment) and adjust the discount rate if needed in other parts of the
function.

def calculate_discount(price):
TEN_PERCENT_DISCOUNT = 0.1
discount = price * TEN_PERCENT_DISCOUNT
return price - discount

The improved code replaces the hard-coded number with a named constant
TEN_PERCENT_DISCOUNT . The name instantly conveys the meaning of the value,
making the code more self-documenting.

LAW 40: Follow the DRY (Don’t Repeat Yourself) Principle


Avoid writing the same code more than once. Instead, reuse your code using
functions, classes, modules, libraries, or other abstractions. This makes your
code more efficient, consistent, and maintainable.

It also reduces the risk of errors and bugs as you only need to modify your
code in one place if you need to change or update it.

# Bad

def calculate_book_price(quantity, price):


return quantity * price
def calculate_laptop_price(quantity, price):
return quantity * price

# Good

def calculate_product_price(product_quantity, product_price):


return product_quantity * product_price

LAW 41: Follow Established Code-Writing Standards


It’s important to follow commonly accepted conventions in terms of spacing,
comments, and naming. Most programming languages have community-
accepted coding standards and style guides, for example, PEP 8 for Python

Some common conventions are:

Use snake_case for variable, function, and class names.

Use spaces over tabs for indentation.

Use 4 spaces per indentation level

Limit all lines to a maximum of 79 characters.


Break a line before a binary operator

LAW 42: Law of Demeter


The law of Demeter, in simple terms, means that a module/function/class

can have knowledge or make reference to another module/function/class

immediate neighbors but should not have any knowledge further than that.

By immediate neighbors, this means methods or functions or variables that


can be directly accessed.

An example should clear this up…

class Order:
def __init__(self, customer):
self.customer = customer

def get_customer_name(self):
# Violation: Order knows too much about the customer's structure
return self.customer.get_profile().get_name()

In this example, the Order class directly accesses the customer’s profile to
retrieve the customer’s name. This violates the Law of Demeter because
Order is reaching into the internal structure of the Customer object to access
its profile and name.

It has gone past an immediate neighbor and now knows too much about the
customer’s object.

class Order:
def __init__(self, customer):
self.customer = customer

def get_customer_name(self):
# Adherence: Order only interacts with its immediate collaborator
return self.customer.get_name()

In this adherent example, the Order class only interacts with its immediate
collaborator, the Customer object, and calls a method directly on it to retrieve
the customer’s name.

It does not reach into the internal structure of the Customer object, thus
following the Law of Demeter.

LAW 43: Readability over conciseness


Code needs to work and be understood by the machine executing it.
However, other developers also need to be able to understand the code,
especially if you are working on a project with multiple people.

That is why the readability of code is always more important than its
conciseness when it comes to software development.

There is no point in writing concise code if other developers cannot


understand it.

LAW 44: Keep Imports Clean


Import only the necessary modules and symbols to keep the import section
clean and improve readability. When we import everything (*) from a
module, all variables, functions, and classes are also imported which can
make it very difficult to know where a certain function/class originated from
and can also be a pain when using modern IDEs.

Imagine you want to write a function with the name get_file . You click g

and your IDE recommends you a list of functions/classes/variables that start


with the letter g. It can become quite chaotic.

This becomes more of a pain when you want to call that function. Your
function name could be lost in between the recommendations and now your
IDE becomes more of a problem than an efficient solution.

# Bad
from module import *

# Good
from module import symbol1, symbol2

LAW 45: Do Not Return Null/None


Usually, when we define functions, by default they return None if no return
value is specified. But when we explicitly return None , we are indirectly
telling the reader that the function can return something else except None .

And if this is not true, it can cause a lot of miscommunications.

LAW 46: Separate Construction From Its Use


Separation of concerns has been a very fundamental principle in software
engineering. We need to know how to separate the construction of our
software from how it’s being used.

This often means separating the startup process, — which is when our
dependencies and objects are wired together — , from the run time logic, —
which is when the logic of the application executes based on inputs from the
user or other triggers — .

One common way to separate construction from its use is to construct the
application logic in a file/function/module called main .

The main function builds the objects necessary for the application to run
smoothly. This frees other modules from being tightly coupled to the
application and promotes reusability and modularity.

LAW 47: Simple Design Contains All These Rules


Runs all the tests: A system might have a perfect design on paper but if
there’s no way to verify that the system actually works as intended, then the
design on paper becomes questionable.

Contains no duplication: Duplication is the primary enemy of a well


designed system

Expresses the intent of the programmer

Minimizes the number of classes and methods

LAW 48: Avoid Nested Try-Except Blocks


Refrain from nesting try-except blocks excessively to prevent overly
complex error handling logic.

# Bad
try:
try:
# Code that might raise errors
pass
except ValueError:
# Handle ValueError
pass
except Exception as e:
# Handle any other unexpected errors
pass

# Good
try:
# Code that might raise errors
pass
except ValueError:
# Handle ValueError
pass
except Exception as e:
# Handle any other unexpected errors
pass

LAW 49: Use Concurrency Only When Needed


It’s very easy to write bad code when implementing concurrency
functionality.

It’s also very easy to write clean code when implementing very faulty
concurrency functionality. Usually, you might not even be aware that it is
faulty until a lot of stress is put on the system.

You want to pick your battles very smartly.

There are multiple reasons why your concurrency code might fail. Here are
some:

Starvation: Starvation occurs when a thread or process is unable to gain


access to a shared resource indefinitely, despite attempting to do so. This can
happen when other threads or processes continually acquire and hold the
resource, preventing the starving thread from making progress.

Deadlocks: Deadlocks occur when two or more threads or processes are


blocked indefinitely, waiting for each other to release resources that they
need. This can happen when each process holds one resource and waits for
another resource held by another process, creating a cyclic dependency.

5 Concepts Every Python Engineer Should Know in 2024


In computer science, understanding how the hardware works hand
in hand with software is extremely critical…
medium.com

LAW 50: Follow The 49 Rules


These laws are only there to guide you on your journey as a software
engineer. You should abide by them whenever needed.

But as you grow in experience and skills, you want to be able to decide when
it’s best to follow a certain rule and when it’s not.

This gut feeling/intuition only comes to those who have mastered their craft
and if you’re a newbie or you just started your career 2 years ago, it’s usually
best you follow these laws like it’s your only ticket to heaven.

Most Python developers need somewhere to quickly test their code or debug errors. I
developed a website called python-fiddle.com which you can use to quickly test out
a code and it uses AI/LLMs to help find solutions to possible errors.
Programming Python Software Engineering Clean Code Data Science

Written by Alexander obidiegwu Follow

1.7K Followers

Explaining foundational concepts and principles of Python, SQL and Mathematics.

More from Alexander obidiegwu


Alexander obidiegwu Alexander obidiegwu

10 Hard Python Projects For Basic REST API Principles That


Intermediates To Boost Your make you a 1% programmer.
PythontoSkills
Timeline finish & Portfolio.
each project—1 month And it only takes 10 minutes

5 min read · Dec 25, 2023 11 min read · Jan 29, 2024

1.2K 7 81

Alexander obidiegwu Alexander obidiegwu

3 Months Of Google Data Analytics 3 Ways To Run A Python Function


Course Summarized in 18 Minutes Asynchronously
Digest 3 months’ content in 18 minutes You would most likely fail as a Python
programmer without understanding this
ground concept. Asynchronous
18 min read · May 13, 2024 · 8 min read · Dec 15, 2023
Programming.

33 2 400 1

See all from Alexander obidiegwu

Recommended from Medium


KayDee in Predict Vinuki Vidhara in SoulSync

You Need To Learn AI in 2024! (And How I Tricked My Brain To Like


Here Is Your Roadmap) Doing Hard Things [Dopamine
Photo by Maximalfocus on Unsplash Detox]
Why are some people more motivated to
tackle difficult things? And is there a way to
make doing difficult things, easy?
6 min read · Jan 8, 2024 9 min read · Jan 26, 2024

2.5K 55 11.5K 154

Lists

Coding & Development Predictive Modeling w/


11 stories · 639 saves Python
20 stories · 1252 saves

General Coding Knowledge Practical Guides to Machine


20 stories · 1270 saves Learning
10 stories · 1507 saves
LORY Hallel K. in Practice in Public

A basic question in security Use the “1 Hour Rule” to Catapult


Interview: How do you store Yourself into the Top 1% of Income
passwords
Explained in the database?
in 3 mins. Earners.
#1. Don’t be cheap.

· 7 min read · May 12, 2024 5 min read · Feb 9, 2024

2.8K 38 6.2K 100

Grant Piper Alexander Nguyen in Level Up Coding

Why Can’t Robots Click The “I’m Why I Keep Failing Candidates
Not a Robot” Box On Websites? During Google Interviews…
Clicking a tiny box tells Google all they need They don’t meet the bar.
to know about your humanity

· 5 min read · May 24, 2024 · 4 min read · Apr 13, 2023

2.6K 30 6.8K 198

See more recommendations

Help Status About Careers Press Blog Privacy Terms Text to speech Teams

You might also like