ETEC31013 - Python Programming for ET
Functional Design and Problem Decomposition
Purpose: This study guide is designed to help you master functional design (organizing code into modular
functions) and problem decomposition (breaking down complex problems into smaller parts). These skills
are essential for creating clear, maintainable, and reusable code, especially in engineering applications like
data processing. We'll focus on principles from structured programming, including variable scopes
(global/local) and imports (global/local), building on topics like variables, loops, conditionals, lists,
dictionaries, NumPy, and CSV I/O.
By the end, you'll understand how to plan and implement solutions systematically, as practiced in your
in-class project and tutorial exercises.
Section 1: Introduction to Key Concepts
What is Problem Decomposition?
Problem decomposition is the process of breaking a large, complex problem into smaller, manageable
sub-problems. This makes it easier to solve step-by-step, reduces errors, and improves code organization.
● Why it matters in engineering: Engineering tasks, like analyzing sensor data from a CSV, often
involve multiple steps (e.g., reading data, calculating stats, outputting results). Decomposing helps
isolate issues, such as debugging a calculation without affecting file I/O.
● Core Idea: Think of the problem as a puzzle—divide it into pieces (sub-tasks) that can be solved
independently and then assembled.
What is Functional Design?
Functional design (or modular programming) involves structuring your code around
functions—self-contained blocks that perform specific tasks. Each function has a clear purpose, takes
inputs (parameters), and returns outputs.
● Relation to Structured Programming: It uses control structures (if-else, loops) within functions,
while managing scopes (where variables/imports are accessible) to avoid conflicts.
● Why it matters: Promotes reusability (e.g., a stats function can be used in multiple projects),
readability, and testing. In Python, this aligns with "procedural" style but incorporates functional
elements like pure functions (no side effects).
Key Principles Linking the Two
● Modularity: Decompose problems into functions; each handles one sub-problem.
● Abstraction: Hide details—users of a function don't need to know its internals, just inputs/outputs.
● Scope Management: Use global variables sparingly (e.g., constants like filenames) and local
variables for function-specific data to prevent bugs.
● Import Control: Global imports for shared modules (e.g., import csv at top); local imports for limited
use (e.g., import numpy inside a function) to control dependencies.
Section 2: Core Principles of Problem Decomposition
1. Identify the Main Goal: Start with the "big picture." Ask: What is the program supposed to do?
(E.g., Process CSV data and compute stats.)
2. Break into Sub-Tasks: Divide into logical steps. Use questions like:
○ What inputs are needed? (E.g., Read CSV.)
○ What processing occurs? (E.g., Convert data, calculate means.)
○ What outputs are required? (E.g., Display or write to file.)
○ What decisions or loops are involved? (E.g., User menu with if-else.)
3. Sequence and Dependencies: Order sub-tasks. Identify what depends on what (e.g., calculations
depend on reading data).
4. Handle Edge Cases: Consider errors (e.g., invalid input, missing file) early.
5. Iterate: Refine decomposition if sub-tasks are too big—break them further.
Example: For a data processor:
● Sub-task 1: Read CSV → Sub-task 2: Store in dictionary → Sub-task 3: User interaction → Sub-task
4: Compute stats → Sub-task 5: Output.
Section 3: Core Principles of Functional Design
1. Function Purpose: Each function should do one thing well (Single Responsibility Principle). Name
it descriptively (e.g., read_csv_file()).
2. Inputs and Outputs: Use parameters for inputs; return values for outputs. Avoid modifying globals
inside functions unless necessary.
3. Variable Scopes:
○ Global: Declared outside functions; accessible everywhere. Use for constants (e.g.,
INPUT_FILE = "[Link]"). Avoid for mutable data to prevent side effects.
○ Local: Declared inside functions; only accessible there. Ideal for temporary variables (e.g., a
list in a calculation function).
4. Import Scopes:
○ Global: At script top (e.g., import csv); available everywhere.
○ Local: Inside a function (e.g., import numpy as np); limits scope, useful for performance or
isolation (though rare in practice).
5. Avoid Side Effects: Where possible, functions should not change external state (e.g., don't print
inside a calc function; return values instead).
6. Reusability and Testing: Write functions that can be called independently for easy testing.
Example: A calculate_mean(data_list) function takes a list (input), computes mean locally with NumPy, and
returns the result (output). Import NumPy locally if only needed here.
Section 4: Procedures to Develop These Skills
Follow this step-by-step process for any problem, like your project or tutorial exercises.
Step 1: Analyze the Problem
● Read requirements carefully.
● List inputs (e.g., user input, files), processes (e.g., loops, conditionals), outputs (e.g., print, files).
● Brainstorm sub-tasks.
Step 2: Design Phase (Decomposition + Planning)
● Use tools like pseudocode or flowcharts:
○ Pseudocode: Write English-like code (e.g., "If input invalid, print error").
○ Flowchart: Draw boxes for steps, diamonds for decisions, arrows for flow.
● Specify:
○ Functions: Name, parameters, returns, purpose.
○ Variables: Global (e.g., constants) vs. local (e.g., temps).
○ Imports: Where placed and why.
○ Error handling: Use if-else or try-except.
● Explain choices: "This function is separate for reusability."
Step 3: Implementation Phase (Functional Design)
● Write code based on design.
● Start with main structure (e.g., a main loop or function).
● Implement functions one by one.
● Use loops/for for iteration, if-else for decisions, lists/dicts/NumPy for data.
● Comment code: "# Global constant for file" or "# Local var for calc."
● Test each function separately (e.g., print intermediate results).
Step 4: Debug and Refine
● Run incrementally.
● Check scopes: Ensure locals aren't accessed globally.
● Refactor: If a function does too much, decompose further.
Step 5: Practice Iteratively
● Start small (e.g., tutorial Exercise 1).
● Build up to complex (e.g., full project).
● Review: After coding, ask: "Is this modular? Could I reuse parts?"
Section 5: Examples
Simple Example: Average Calculator (From Tutorial Exercise 1)
● Decomposition: Sub-tasks = Get input, Calculate average, Display.
● Functional Design:
○ Global: PROMPT = "Enter numbers:"
○ Function 1: get_input() – Local var for user string; returns it.
○ Function 2: calculate_average(nums_str) – Local list of floats; returns avg.
○ Main calls them sequentially.
Complex Example: CSV Processor (Project Snippet)
● Decomposition: Read file → Build dict → Menu loop → Calc stats → Write output.
● Functional Design:
○ Global: INPUT_FILE = "[Link]", import csv
○ Function: calculate_stats(data_dict) – Local import numpy as np; local arrays; returns dict of
means/stds.
Section 6: Tips, Common Mistakes, and Best Practices
● Tips:
○ Always design first—saves time on rewrites.
○ Use meaningful names (e.g., compute_std_dev not func1).
○ Limit globals to 2-3 per script.
○ For engineering data: Use NumPy in calc functions for efficiency.
● Common Mistakes:
○ Overusing globals → Leads to bugs (e.g., accidental overwrites).
○ Monolithic code → No functions; hard to debug.
○ Ignoring scopes → NameError if local var used outside.
○ Side effects → Functions printing instead of returning.
● Best Practices:
○ Keep functions short (<20 lines).
○ Document with comments.
○ Test with sample data (e.g., small CSV).
Section 7: Practice Recommendations
● Review tutorial exercises: Each practices decomposition into 3-4 functions with scopes.
● Apply to project: Redesign if needed using this guide.
● Additional Drills: Decompose a real engineering problem, like calculating beam stress—break into
input, formula, output functions.
● Resources: Python docs on functions/scopes; books like "Clean Code" (focus on chapters about
functions).
Use this guide alongside your notes. Practice consistently to build intuition—soon, decomposition will feel
natural! If questions arise, discuss in class.