DudeWhoCode_

DudeWhoCode_

DudeWhoCode_

    Stop writing bad code and follow these simple ways to get rid of them

    Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

    - Martin Fowler, 2008.

    A good employee can deliver the project within a tight deadline, can quick patch and fix the issues in blink of an eye (without longterm thoughts) or can write complex code.

    But what it takes to be a good engineer?. One of the quality traits of good engineer is defined by the good practices they follow. One such practice is writing a readable code.

    Machines have no feelings, you throw a bad code at them, they try to compile and spit back the errors and warnings on your face. But think about the humans who has to go through your code. Imagine a junior developer who is assigned to maintain your code. She should be able to learn something out of going through your code.

    Today you can write a bunch of bad code, finish your project within your deadline, make your managers happy, get a rise and move on. But you have to remember that you are writing the initial version of the code. The code will be given to someone who should maintain it and add new features to it.

    Two things can happen in this scenario:

    1. If the maintainer is a newbie developer. You are affecting their career. Most of the new developers who hasn't seen a production code assumes that this is how it is and do a false start by taking your code as an example.

    2. If the maintainer is a good developer, you are going to piss them off. Because they know the code base is messed up and maintaining that is a pain. Sometimes they will try to fix the code by refactoring it but only if they have spare time apart from their own deadlines.

    Either way, the bad code you wrote that day, that time, is going to affect some developer. It doesn't stop with the developer, in future it will slow down the project making everyone to wonder what the hell happened, ultimately slowing down the growth of the company.

    Let's see some good practices that you can follow to make your code more readable.

    Variables

    tmp = json.load('students.json')
    tmp_1 = json.load('staffs.json')
    result = cursor.execute('SELECT * FROM movies')
    data = cursor.execute('SELECT * FROM geo_locations')
    

    I am pretty sure most of the people reading this will be having a guilty face right now. But it's okay. Everyone who started coding used these kind of meaningless variable names. That includes me too.

    Variables make the basic building block of your code. And in large code base there will be tens and thousands of variables. Imagine all variables having crappy names like these. The developer who reads the code will go haywire.

    Instead see how neat this looks:

    student_list = json.load('students.json')
    staff_records = json.load('staffs.json')
    current_movies = cursor.execute('SELECT * FROM movies')
    locations = cursor.execute('SELECT * FROM geo_locations')
    

    I know this sounds very basic. But I am leaving it here because I have seen developers using random variable names in production code.

    Coding Standards


    Need not worry if you don't get this meme

    Everyone has their own way of writing code. Some developers like to use curly braces in the same line,

    foo() {
    // do something
    }
    

    While the rest like to use curly braces after a line break,

    foo()
      {
        // do something
      }
    

    Some like to use tabs, some prefer using spaces. Few programmers like to use camel case for variable names, while the rest uses underscores. One of the common attitude among the developer is: I like my way, because it's better 🙄.

    Let's say a bunch of developers with this attitude works on a project.
    Now take a step back and imagine how ugly the code base will look like? This is the reason why every programming language has their own standards or style guides.

    Be ruthlessly consistent

    One way to do that is follow the standards of the programming language you use. If you do so, your code will look more cleaner and more readable, less debates in the team and easy project maintenance.

    Stay DRY

    Don't Repeat Yourself.
    This is the most basic software principle that anyone should follow. If you notice that you are writing few lines of code more than once in your code base, put them into a function to avoid redundancy and for better re-usability.

    The repeated code will bloat the project. More the number of lines, more the number of mistakes it's likely to have. This might sound vague, but that's one of the reason why people choose paradigms like functional programming. They are more expressive and easy to read.

    Don't WET yourself 😂
    If you don't follow the DRY principle you are going to Waste Everyone's Time.

    Single responsibility

    Never give more than one responsibility to a function or method. Two reasons:

    If your function has more than one responsibility,

    1. Your code will not be easily testable. Writing unit test cases becomes a pain.
    2. The reader will not be able to understand what's the intention of the function.

    If some one has to scroll down to read the contents of your function, then there is something wrong. Make sure your function is no longer than a single screen/page. If you can't define what the function does in its name, then you should split it.

    Take a look at this function called writer. Read the function name and read the code, is it doing what the function name says?.

    def writer(queue, fname)
        if queue.not_empty():
            f = open(fname)
            for msg in queue.get():
                msg['year'] = '2018'
                first_name, last_name = msg.get('first_name'), msg.get('last_name')
                msg['full_name'] = first_name + ' ' + last_name
                f.write(msg)
         f.close()
    

    Looks vague isn't it?. Because first of all it has a more common, less contextual name: writer. Then it does 3 things, takes data form the queue, transforms the packet and writes them to a file. Writing unit tests for this function will not be easy.

    Because you have to give different combinations of inputs and test the function's responsibility. This function has 3 responsibilities but only one return value or output which is a file. So, it is difficult to test all 3 responsibilities of the function just by the single output it returns.

    Let's see what happens when we abstract the same function into multiple functions and giving only single responsibility to them.

    def pull_msgs(queue, block=True):
        if queue.not_empty():
        for msg in queue.get(block):
            yeild msg
    
    def transform_msg(msg):
        new_msg = msg.copy()
        new_msg['year'] = '2018'
        first_name, last_name = msg.get('first_name'), msg.get('last_name')
        new_msg['full_name'] = first_name + ' ' + last_name
        return new_msg
        # All other data transformation logic goes here
        
    def write_msgs(fname, queue):
        with open(fname) as f:
          for msg in pull_msgs(queue):
            trasnformed_msg = transform_msg(msg)
            f.write(transformed_msg)
    

    Here each function does what it says. pull_msgs is going to pull data from a queue and it is returning what it says it will return. Where as transform_msg function does single operation and returns it's respective output. In this case it is easier to give different inputs and test for all combinations of errors.

    Paradigms and Patterns

    Once you follow the above steps towards writing clean code, follow this one to make your code even more readable. If you are solving an use case, try to use some paradigms that would make the code more abstract, reusable and readable. Say Object Oriented paradigm.

    Emphasizing the importance of object oriented programming is not in the scope of this post, anyone with a basic CS knowledge should know it's advantages and would've studied in CS subjects.

    But there are many other programming languages that are not object oriented, for them you can follow the recommended paradigms by the author or core users of the language. Every language has their own design patterns.

    In simple words, Design patterns are a set of templates on how to solve specific problems. Depending on the problem you are trying to solve, you can choose a design pattern and design your software based on that. For example, any logging framework would've been built with singleton pattern in mind.

    Don't worry if you don't know design patterns. It is something which you don't use on day to day adhoc scripts. But you should know the list of existing design patterns and when you have to design a software, you should know how to choose a right one depending on the problem you are trying to solve. There are many good books on it, one such book is Head First Design Patterns.

    If you follow OOP (or other standard paradigms) and design patterns, the code will look clean as well as the reader will know what approach you've taken to design the software and there will be no surprises while going through the code.

    As a developer it's not only our responsibility to make the consumers happy but also we should make the fellow developers happy. From now on, let's take a vow that we will not write bad code anymore.

    Repeat after me.
    i "your name" will not write bad code.

    After 6 months if open your own code that you write today, there should be way less WTF moments while reading it.

    Naren

    Naren

    A Product Engineer helping startups to scale their backend infrastructures. Apart from coding and being productive, I train for competitive cycling and love eating healthy food.