Developer’s Guide: Avoiding Common Mistakes and Following Best Practices

Nabil Mosharraf Hossain
7 min readSep 29, 2023

--

Things to take note to become better developers

Technical

1. Naming Conventions

Your function and variable names should be descriptive and self-explanatory. This enhances code readability and helps other developers understand your logic more quickly.

Functions should be command or queries but not both

# Good naming
def calculate_total_price(cart_items):
...
# Bad naming
def calculate(tp):
...

2. Handling Function Output

Avoid output arguments, using return values instead. This helps keep functions predictable and easy to understand.

javascriptCopy code

// Good return usage
function calculateSum(a, b) {
return a + b;
}
// Bad output argument usage
function calculateSum(a, b, sum) {
sum = a + b;
}

3. Function Purpose

Every function should serve either as a command (performing an action) or a query (returning data), but not both. Mixing these functionalities can lead to confusing code.

javaCopy code

// Command function
void setAge(int age) {
this.age = age;
}
// Query function
int getAge() {
return age;
}

4. Abstraction

Abstraction is crucial in developing manageable code. However, wrong abstraction can lead to even more complexity. Therefore, it’s important to understand that, sometimes, duplication is better than the wrong abstraction. Read more about this here and here.

Duplication is better than wrong abstraction

Abstraction is a method of simplifying complex systems by breaking them down into smaller, more manageable parts. However, creating the wrong abstraction can complicate your system even further. Thus, it is important to note that in some situations, having some code duplication is actually better than implementing the wrong abstraction.

For example, suppose you have two sections of your code that perform similar, but not identical, tasks. You might be tempted to create a single abstract function that handles both tasks with a flag to differentiate the two cases. This, however, can lead to confusing and hard-to-maintain code. Instead, it might be better to have two separate functions, leading to some code duplication but improving readability and maintainability.

# Wrong Abstraction
def handle_tasks(task_type):
if task_type == "type1":
# handle type1 task
elif task_type == "type2":
# handle type2 task
# Better Approach: Some Duplication but Clearer
def handle_type1_task():
# handle type1 task
def handle_type2_task():
# handle type2 task

To delve deeper into this concept, read this blog by Sandi Metz or this one by Jason Swett.

https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction

https://www.codewithjason.com/duplication-cheaper-wrong-abstraction/

5. Conflict Management in Git

Working on a collaborative project using Git can often lead to conflicts — situations where changes from different branches overlap and Git doesn’t know how to combine them. Handling these conflicts is a crucial part of working with a team.

When you encounter a conflict, Git will mark the problematic area in your file and show you the conflicting changes. Your job is to resolve the conflict by deciding which changes to keep or by merging the changes manually. Once you’ve resolved all conflicts, you can continue with the git rebase or git merge command that led to the conflict.

# Conflict markers in a file
<<<<<<< HEAD
// your changes
=======
// changes from the branch you're merging/rebasing
>>>>>>> branch-name

Remember, the key to managing conflicts well is communication. Understand the changes made by others, discuss overlapping work, and ensure everyone agrees on the resolution.

Git conflicts are inevitable when working in a team. Handle them gracefully by understanding the changes made by others, carefully resolving conflicts, and ensuring the integrity of the codebase.

6. Creating Meaningful Functions and Modules

When writing code, aim to create meaningful functions and modules. Each function should have a clear purpose and ideally perform one specific task. This concept is related to the single responsibility principle and it greatly enhances the maintainability and readability of your code.

For example, instead of having one function to calculate and print a report, divide it into two functions: one for calculating the data and another for printing the report.

// Not ideal
function calculateAndPrintReport(data) {
// calculate report data
// print report
}
// Better approach
function calculateReport(data) {
// calculate report data
return report;
}
function printReport(report) {
// print report
}

Understanding how modules (a group of related functions and variables) work is also important. Try to group related functions into the same module to promote cohesion and clarity.

For a deeper understanding on this topic, you can refer to John Carmack’s perspective on inline code.

When you’re writing code, it’s essential to structure it properly, since if another developer is reading your code, and it’s not well-structured, it will be hard for them to understand everything quickly.

This leads to an unnecessary waste of time, which can easily be avoided, if you just apply proper code structure, which it’s easy for everyone to understand.

https://lvivity.com/how-to-write-good-code

Write meaningful functions and deeply understand how modules work. Each function should ideally do one thing and do it well, making the code easier to maintain and understand. Read about John Carmack’s perspective on inline code for further insights.

http://number-none.com/blow/john_carmack_on_inlined_code.html

7. SOLID Principles

The SOLID principles are a set of software design principles that help to create maintainable and scalable systems.

For the other SOLID principles (Open-Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion), please refer to external resources to gain a deep understanding.

8. Sharing Information

If multiple functions or modules share similar information, consider bringing them together. Cohesion makes your codebase easier to navigate and understand.

Single Responsibility Principle: A class should have only one reason to change. It’s a common misconception that a class should do only one thing or have only one function. Rather, all the functions of a class should serve one cohesive purpose. Read more about this here and here.

SINGLE RESPONSIBILITY

http://www.softwareonthebrain.com/2022/01/the-misunderstood-single-responsibility.html

https://galiarmero.dev/blog/why-the-single-responsibility-principle-is-often-misinterpreted/#:~:text=The%20common%20misconception%20about%20the,or%20a%20thing%20to%20do.

Bring Together if information is shared

9. Write less code

All code is buggy. It stands to reason, therefore, that the more code you have to write the buggier your apps will be.

Writing more code also takes more time, leaving less time for other things like optimisation, nice-to-have features, or being outdoors instead of hunched over a laptop.

In fact it’s widely acknowledged that project development time and bug count grow quadratically, not linearly, with the size of a codebase. That tracks with our intuitions: a ten-line pull request will get a level of scrutiny rarely applied to a 100-line one. And once a given module becomes too big to fit on a single screen, the cognitive effort required to understand it increases significantly. We compensate by refactoring and adding comments, which almost always results in more code. It’s a vicious cycle.

Yet while we obsess — rightly! — over performance numbers, bundle size and anything else we can measure, we rarely pay attention to the amount of code we’re writing.

10. Readability is important

I’m certainly not claiming that we should use clever tricks to scrunch our code into the most compact form possible at the expense of readability. Nor am I claiming that reducing lines of code is necessarily a worthwhile goal, since it encourages turning readable code like this…

for (let i = 0; i <= 100; i += 1) {    
if (i % 2 === 0) {
console.log(`${i} is even`);
}
}

…into something much harder to parse:

for (let i = 0; i <= 100; i += 1) if (i % 2 === 0) console.log(`${i} is even`);

Instead, I’m claiming that we should favour languages and patterns that allow us to naturally write less code.

Attitude

11. Not focusing on soft skills

It’s important to be able to communicate well with your team, stakeholders, and others in the organization. This helps you understand the business goals, talk to clients, deliver high-quality products, and learn from group discussions. So, don’t forget to work on your communication and interpersonal skills.

12. Not asking for help

Even experienced developers face challenges and don’t always know where to start on a task. It’s okay to ask for help instead of struggling alone. Reach out to your manager, team lead, or coworkers who may have experience in what you’re working on. Respect their time and politely ask for guidance. They will likely be happy to assist you.

13. Lack of Planning Before Starting to Write Code

Before you start coding, it’s essential to set clear goals and understand what you want to achieve. Think about potential problems, how to solve them, and any extra features you want to include. Good planning saves you time and ensures you align with the project’s objectives.

Take a step back, think big picture, avoid going down rabbit holes, help steer others towards their goals. Learn how to prioritize tasks. Learn how to think about pros/cons in any situation and make quick decisions.

14. Doing Only What Is Required

Don’t just focus on completing the tasks assigned to you. Sometimes people may not know exactly what they need, so be proactive. Look for ways to improve the project, even if no one has explicitly asked for it. By delivering an excellent solution and considering the overall user experience, make sure that the users are completely satisfied.

15. Not taking ownership of mistakes

Don’t blame others or deny responsibility when bugs or errors are found. It’s important to take ownership of your mistakes and show professionalism. By acknowledging the issue, committing to resolve it, and learning from it, you demonstrate maturity and gain the trust of your manager. Taking responsibility is crucial for career growth.

Thats All

Be proactive in taking responsibilities and completing them. Address and solve any problems you see. Automate tasks, resolve technical issues, and occasionally handle less popular tasks. Always be dependable and find solutions. Share what you know, guide others, and foster a trustworthy team atmosphere. Helping your teammates benefits the entire team

Hope you liked reading this article

Resources:

https://devrix.com/tutorial/top-21-common-mistakes-web-developers-make/

https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201

https://www.youtube.com/watch?v=104O9Qom_AM

https://www.turing.com/blog/software-development-career-mistakes-to-avoid/

--

--