Home

Awesome

Args Kata

Why this Kata?

The Args Kata offers an hour-long hands-on practice on readable and maintainable programming. When practicing alone, it improves a developer's craft. When practicing as a team, it educates and aligns the team on a standard set of best practices and coding styles.

Robert C. Martin gave the Java version of the code before and after refactoring in Chapter 14 of his book "Clean Code: A Handbook of Agile Software Craftsmanship." This repo simplifies the code slightly for Kata purpose and ports it into other languages.

Users' goal is to improve the modularity and readability of the Args class without breaking its functionalities.

How to use this Kata

Args Requirements

A program with command-line interface (CLI) usually takes several arguments. Take curl -v -H content-type:application/json https://google.com for example. It sends a HTTP request to https://google.com. It takes a key-value-pair-like argument: -H (the key, means set a HTTP header) and content-type:application/json (its value, means set a header named content-type to application/json). It also takes a boolean flag: -v. That means verbose mode is enabled and curl will print the HTTP request and the response in detail. Besides, it takes a plain string argument: https://google.com, which is the target URL of the HTTP request.

Most programming languages don't understand what flags and key-value pairs, they just split the arguments by space, like ["curl", "-v". "-H", "content-type:application/json", "https://google.com"]. CLI tool authors need to write code to parse that list of strig to something meaningful like key-value pairs and flags. It's a common and tedious work, therefore people created libraries like oclif and cli.

Args is a simple CLI argument parser library. The constructor of Args takes a schema string and a list of string arguments args. The schema defines the parsing rules of the string list. The syntax of schema is

Once Args parsed the argument list, it provides methods for querying

When parsing runs into a problem, it throws an exception. The exception should implement an errorMessage() method that returns a string message and getErrorCode() method that returns an enum.

Here is a list of error scenarios and their corresponding error codes and messages (replace ${key} with the value of key):

ScenarioError CodeMessage
Found an argument that is not presented in the schemaUNEXPECTED_ARGUMENTArgument -${problematicArgName} unexpected.
Found an argument whose value should be an integer but it's notINVALID_INTEGERArgument -${problematicArgName} expects an integer but was '${problematicArgValue}'.
Found an argument whose value should be a double but it's notINVALID_DOUBLEArgument -${problematicArgName} expects an integer but was '${problematicArgValue}'.
There is a string argument at the end of the argument list with no value, like a single -sMISSING_STRINGCould not find string parameter for -${problematicArgName}.
There is an integer argument at the end of the argument list with no value, like a single -iMISSING_INTEGERCould not find integer parameter for -${problematicArgName}.
There is a double argument at the end of the argument list with no value, like a single -dMISSING_DOUBLECould not find double parameter for -${problematicArgName}.
Found an argument whose name is not a single letter (a-z, upper or lower cases)INVALID_ARGUMENT_NAME'${problematicArgName}' is not a valid argument name.
Found an argument that doesn't start with -INVALID_ARGUMENT_FORMAT'${problematicSchemaValue}' is not a valid argument format.
Found an argument with unknown type syntax, like p#*INVALID_ARGUMENT_FORMAT'${problematicSchemaValue}' is not a valid argument format.
Not an error, this should never happenOKTILT: Should not get here.

Solution

There is a solution provided in after-refactor/. It is one of the many ways to improve the code. It follows the practices mentioned in the Clean Code book, to name a few: