4.4.1.9–4.4.1.11 - Decomposition, composition and automation (Python)

4.4.1.9–4.4.1.11 - Decomposition, composition and automation (Python)

Break a problem into identifiable tasks, combine procedures and data into useful abstractions, then put a model into action. Use a small stock-control system to see how these choices become executable Python.

Procedural decomposition

Decomposition makes a large problem manageable by giving each sub-problem an identifiable responsibility.

Procedural decomposition

Procedural decomposition breaks a problem into sub-problems, each accomplishing an identifiable task; a sub-problem may be subdivided further.

Consider a shop's task “produce today's reorder report”. Separate it into obtaining stock records, deciding which products need an order, calculating order quantities and presenting the report. “Decide which products need an order” might itself separate into looking up the minimum quantity and comparing current stock with it. Each task should have a clear input and output, rather than a vague heading such as “do processing”.

A subroutine boundary lets you change one decision without rewriting the entire process. For example, needs_order(quantity, minimum) can return a Boolean; it need not also print a report or read a keyboard. Its interface tells callers what they supply and receive. If current quantity is guaranteed a non-negative integer, state that guarantee rather than inventing validation inside every helper.

Good decomposition follows the problem, not an arbitrary demand for one procedure per statement. Splitting “add one to count” into a separate procedure would rarely create a useful abstraction. Conversely, a single procedure that reads, validates, stores, calculates and formats everything makes responsibilities difficult to test independently.

Procedural composition

Composition builds a compound procedure by arranging smaller procedures so their results perform a larger task.

Decomposition works from a whole towards parts; composition abstraction builds a new whole from those parts. The caller can use report(items) without knowing the details of each comparison or line format. The abstraction is useful because its behavior remains clear at its interface.

Predict which products appear, run this example and then change the reorder rule to include quantities equal to the minimum. Notice that changing one helper changes the compound procedure's behavior.

Compose a stock report

{"code":"def needs_order(quantity, minimum):\n return quantity < minimum\n\ndef report_line(item):\n return item['name'] + ': ' + str(item['minimum'] - item['quantity'])\n\ndef report(items):\n lines = []\n for item in items:\n if needs_order(item['quantity'], item['minimum']):\n lines.append(report_line(item))\n return lines\n\nitems = [\n {'name': 'Pens', 'quantity': 3, 'minimum': 8},\n {'name': 'Pads', 'quantity': 5, 'minimum': 5},\n {'name': 'Clips', 'quantity': 9, 'minimum': 6}\n]\nprint(report(items))\nprint(report([]))\n","instructions":"Predict the report and empty report, then run. Change the comparison in needs_order from < to <=, run again and explain the zero quantity in the new Pads line. Decide whether ordering zero items is suitable for the shop's intended report.","files":[],"original_filename":"main.py","runtime_profile":"python-console-v1","file_mode":"fresh"}

The original returns ['Pens: 5'] and []. The changed rule adds 'Pads: 0'. That is a valid execution of the modified rule, but may reveal an unsuitable requirement. Composition does not automatically make a system correct: the helpers' interfaces and assumptions must agree, and the combined result must meet the larger requirement.

Continue this lesson.

You’re previewing NovaLearn without an account. Create a free account to read the rest.

Create free account