DEV Community

igaurab
igaurab

Posted on

How to write a good function?

Here are my 3 things to look out for while writing a good function. The code examples are given in python but the concept applies across all the programming languages. If you have any other ideas/strategies please mention them in the comments.

Don't Trust The Inputs

Look at the code below and think about what can go wrong.

def process_date(str_date):
    """
       This takes date in format dd/mm/yyyy and returns
       a dict of format {'y':2000,'m':10,'d':19 } as output
    """
    d,m,y = str_date.split('/')
    value = {'y':y,'m':m,'d':d}
    return value

Enter fullscreen mode Exit fullscreen mode

At first glance, the code seems to work fine. If you run the function

process_date(str_date = 10/20/2000).

Then the output of the function will be:

{'y' : 2000,'m' : 20, 'd' : 10}

The function returns an output so everything seems to be working right? But there is a logical error. Months can never be greater than 12. The same goes for days and years. Apart from that what if the user passed negative values-1/-1/-1? Also, what if the user provided an empty string?

Here, we made a mistake of trusting the inputs. We should never trust the inputs. Be skeptical about the parameters and think hard about the edge cases. Make sure to sanitize your input before you perform any computation on them.


Fail Loudly and Clearly

What if you change the format of the date? From 10/20/2000 to 10-20-2000. This would completely break your code.

image.png

So, when the input is not what we want them to be, we want to notify the user about this issue. And if we have to fail, choose to fail loudly and clearly. The above error message is quite not clear compared to the one below, which clearly mentions that the issue is because of the input format of date supplied

regex_date_format = "^\d{1,2}/\d{1,2}/\d{4}$"
if not re.match(regex_date_format, date_str):
    raise ValueError(
        f"str_date: {str_date} should be of the format dd/mm/yyyy "
    )

Enter fullscreen mode Exit fullscreen mode

Also, Most of the time, we tend to simply return None if we get any error.

if error:
    return None

if error:
    return None

some code

return result

Enter fullscreen mode Exit fullscreen mode

This especially causes issue while debugging the program. In above dummy program, if we get a None as output, then which error in particular gave us the None value?
So, being loud and clear about the errors that occurs in program helps other developers and users of the function to understand what it is that is causing the issue/error.


Be consistent with return type

One thing I like about statically typed language is their consistency. If you are using a function then you'll know if that will return an array or a dict or an string etc. This allows us to process the output in some consistent manner and also avoids confusion and bugs in the program.

def return_something( input ):
    if error:
        return 'Error connecting to the server'
    code

    return {"data":"Hello world"}
Enter fullscreen mode Exit fullscreen mode

Suppose someone uses this function in the following way:


response = return_something(inp)
data = response['data']

Enter fullscreen mode Exit fullscreen mode

Here, the code breaks if there is any error while connecting to the server. The right way of checking it would be

response = return_something(inp)
if isinstance(response, str):
    handle_error
data = response['data']

Enter fullscreen mode Exit fullscreen mode

The other way to write the same function would be:

def return_something( input ):
    if error:
        return {"error": 'Error connecting to the server' , "data": "" }
    code

    return {"data":"Hello world", "error": "" }

Enter fullscreen mode Exit fullscreen mode

In both cases we get the same fields, this helps us be consistent with the way we process the data further in out code, and should not worry if we get a string or an array etc.

response = return_something(inp)
data = response['data']
error = response['error']

if error:
   handle_error

if data:
   do_something

Enter fullscreen mode Exit fullscreen mode

This increases the code readability also. In the first example, one could wonder, why is it that we are handling the error if the instance is a string. Whereas in the second implementation it's clear that any response contains two fields the data and error and if we get any error we can do some error handing.


Please provide your feedback

Top comments (0)