A tiny example how design decisions affect the implementation

August 1, 2021

This blog post is about how good design decisions lead to clear solutions and how "best practices" bloat the code by example of command line parsing.

Everyone knows dd utility (for those who does not yet, expand your mind now) and knows its unusual command line syntax. Using this utility for almost, or even more than 20 years I never had a thought why they chose such a syntax. What is special in their choice, actually? GNU utilities use their own syntax, MS-DOS used their own, dd uses its own. Nothing bad in diversity. But opening the documentation for argparse (I'm mainly a Python programmer) each time for for each my new script I always have a thought: something is wrong here. Why do I open the documentation each time I want to parse a couple of command line arguments?

And I recalled dd. Why there's no alternative to argparse in Python language? Honestly, I tried to search for alternatives. I might miss them, however.

Anyway, the work in IT accustomed me to revise the basics from project to project. And it was the time to revise such and elementary thing.

The resulting implementation was simply indecent. If I was paid for lines of code I'd be a beggar. Compare the following with more than 2000 lines long argparse:

kvargs = dict()

def parse_args():
    '''
    Parse ``sys.args`` and populate ``kvargs``.
    '''
    for arg in sys.argv[1:]:  # exclude argv[0]
        if '=' in arg:
            key, value = arg.split('=', 1)
            if key in kvargs:
                # multiple occurrences
                if not isinstance(kvargs[key], list):
                    kvargs[key] = [kvargs[key]]
                kvargs[key].append(value)
            else:
                # first occurrence
                kvargs[key] = value

The complete module can be found here: https://pypi.org/project/kvargs/.

I don't know about you, my reader, but as for me the difference is impressive. And there's even no need to memorize how to use it. That's just a dict.

You might argue that argparse does much more work, such as handling positional arguments, transforming data type, displaying help, etc. Well, that's all good, but I'd prefer a general-purpose validating library for the last two points. And there's a lot of ways to handle positional arguments with minimal modifications, for example kvgargs.

And I wouldn't write this blog post at all if I recently hadn't not found that I'm not alone. Here is a snippet of a respectable W3C Markup Validator's codebase. Thesey seem to be in the process of revising the basics in their own way. I don't know their motivation, just take a look. No argparse at all:

W3C Markup Validator code sample

Okay, okay. I added more lines to my code, to make it bigger. These lines are implementation of ModuleProxy to avoid such silly things as:

from kvargs import kvargs

Instead, you just

import kvargs

and use kvargs module as a ordinary dict. Unfortunately, your code will be shorter so they may pay less to you. Use with care.