Pragmatic minimalism as a software design tool

About me




  • My name is Chris Down
  • 5th most trusted user in the world on Unix & Linux Stack Exchange
  • Sysadmin at Regent Markets Group
  • Sysadmin/programmer at Initiatives of Change
  • Tech lead at zenu.ca
  • Minimalist

Considerations when designing software


  • Is software the right way to fix this problem?
  • What are the minimum requirements of this software?
  • What areas of flexibility do there need to be to allow this software to adapt to change and improvement?
  • What is the simplest correct way to achieve this software?

The simplest correct way


Not just about code, but tools.

  • Language
  • Libraries/modules
  • Code structure
  • Implementation decisions
  • Design decisions

What is minimalism?


  • Minimalism is not so much a process as it is a goal
  • Things which may seem "simple" in the short term may not be in the long term
  • Subjective depending on the person
  • Removal/rejection of that which hinders achieving what you want
  • Addition of that which makes it easier to achieve what you want

What is it that is wanted?


  • Less code maintenance
  • Fewer bugs
  • More understandable code
  • Better understanding of interlinking parts

Minimalism does not mean the removal of useful functionality


  • If a constituent part of something is not useful, then the very act of removing it often improves other parts implicitly
  • In determination of what is not useful, with modern version control systems, it is much less costly to liberally remove currently not useful code, with the knowledge that if you want it back later, you can do so
  • Reduction in maintenance cost

Minimalism does not mean the removal of dependencies


  • Support from others often helps you to get where you need by working in concert with their ideas
  • In code, this manifests as willingness to use and give back to libraries and modules that are maintained outside of your control
  • Minimalism does not mean the removal of dependencies, but such is often a useful side effect of its implementation
  • Do not reinvent the wheel!
    Usage: my_program tcp <host> <port> [--timeout=<seconds>]
           my_program serial <port> [--baud=9600] [--timeout=<seconds>]
           my_program (-h | --help | --version)

Raw

    """
    Usage: my_program tcp <host> <port>[--timeout=<seconds>]
           my_program serial <port> [--baud=9600] [--timeout=<seconds>]
           my_program (-h | --help | --version)
    """

    import sys

    if len(sys.argv) >= 4 and sys.argv[1] == "tcp":
        mode = "tcp"
        host = sys.argv[2]
        port = sys.argv[3]
        if len(sys.argv) == 5 and sys.argv[4].startswith("--timeout")

    [...]

optparse

    """
    Usage: my_program tcp <host> <port>[--timeout=<seconds>]
           my_program serial <port> [--baud=9600] [--timeout=<seconds>]
           my_program (-h | --help | --version)
    """

    import sys
    import optparse

    parser = optparse.OptionParser()
    parser.add_option("--timeout")
    parser.add_option("--baud")

    options, args = parser.parse_args()

    if not args:
        sys.exit(1)

    command = args[0]

    if command == "tcp"
        if len(args) != 3 or options.baud:
            sys.exit(2)
        host = args[1]
        port = args[2]
    elif command == "serial"
        if len(args) != 2:
            sys.exit(3)
        host = None
        port = args[1]
    else:
        sys.exit(4)


argparse

    """
    Usage: my_program tcp <host> <port>[--timeout=<seconds>]
           my_program serial <port> [--baud=9600] [--timeout=<seconds>]
           my_program (-h | --help | --version)
    """

    import argparse

    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers()

    parser_tcp = subparsers.add_parser("tcp")
    parser_tcp.add_argument("<host>")
    parser_tcp.add_argument("<port>")
    parser_tcp.add_argument("--timeout", nargs="?")

    parser_serial = subparsers.add_parser("serial")
    parser_serial.add_argument("<port>")
    parser_serial.add_argument("--baud", nargs=1)
    parser_serial.add_argument("--timeout", nargs="?")

ArgumentError: argument --timeout: conflicting option string(s): --timeout

argparse

$ wc -l argparse.rst
1932

$ wc -l argparse.py
2373
    Usage: my_program tcp <host> <port> [--timeout=<seconds>]
           my_program serial <port> [--baud=9600] [--timeout=<seconds>]
           my_program (-h | --help | --version)

WA LAU WEH, IT'S POSIX!!!




What is the proper way to represent this usage message in code?



    Usage: my_program tcp <host> <port> [--timeout=<seconds>]
           my_program serial <port> [--baud=9600] [--timeout=<seconds>]
           my_program (-h | --help | --version)

docopt

   
    """
    Usage: my_program tcp <host> <port> [--timeout=<seconds>]
           my_program serial <port> [--baud=9600] [--timeout=<seconds>]
           my_program (-h | --help | --version)
                                 
    """                                                                            
                                                                                   
    from docopt import docopt                                                      
    docopt(__doc__)    


  • 350 lines of code
  • No dependencies
  • Easily memorable syntax (superset of POSIX)

Making sensible design decisions


  • It can't do X, but it can do Y 
  • Design decisions solely supporting little used functionality are (generally) not worthwhile
  • Overengineering is one of the worst things you can do
  • Underengineering is one of the worst things you can do

Commonly missed complexity issues


  • Code complexity does not scale linearly with lines of code
  • Each new piece of code has to interact with the entire codebase
  • Not all complexity issues are in your codebase
  • Some libraries try to do too much, and may limit your ability to use them effectively
  • Some libraries actively slow down development due to their poor design

Summary


  • Think about the language you are using
  • Design in a way that allows flexibility
  • Design in an easily comprehensible way
  • Design in a correct way
  • Design in a simple, minimalist way


Thank you!





chrisdown.name

chris@chrisdown.name

github.com/cdown