#026 - Programmatic Thinking: For Engineers
First, solve the problem. Then, write the code. An overview of the fundamental principles involved in developing a computational mindset.
As an engineer, you're trained to approach problems systematically and logically. Programming requires the same fundamental skills, breaking down complex problems into smaller steps and using logical operations to solve each part. Thinking programmatically means applying that same analytical engineering mindset to writing code.
Often, we put the cart before the horse and start obsessing over the language, the syntax, the packages we need, or how we structure our data.
Whether you're new to programming or have been coding for years, adopting a programmatic way of thinking is a requirement for writing efficient, maintainable, and scalable code. This guide will walk you through some key programming concepts that are language-agnostic.
Pseudocode
Algorithms
Problem Decomposition
Variables
Control Flow
Logic
Functions
Understanding these concepts will allow you to "think programmatically" and develop robust solutions before ever worrying about the syntax of a specific language.
"Everyone should know how to program a computer because it teaches you how to think." โ Steve Jobs
Steve has many critics but I agree with him on this point. Thinking well is important.
Pseudocode
Before writing a single line of code, the first and most crucial step is clearly defining the problem you're trying to solve and mapping out the solution using pseudocode and algorithms. This may seem obvious, but itโs often overlooked or rushed through. Skipping this stage is a missed opportunity.
Pseudocode is a plain language description of the steps needed to solve a problem - essentially writing out the instructions as you would explain them to somebody else. Expressing a solution out loud or in writing, walking through it from start to finish, commonly reveals oversights or inconsistencies that were previously concealed when simply thinking about the problem. This is all too common for me; as soon as I start talking, I find that I need to stop.
As engineers, you know that a problem well-defined is a problem half-solved. When we only rely on the mental models in our heads, our designs and ideas can seem flawless, efficient and majestic. But once we start to verbalize or sketch out those concepts, the cracks and shortcomings become glaringly apparent. Pseudocode forces you to confront those blind spots up front.
Hereโs a simple example of some pseudocode for a simple calculation of concrete volumes for a floor slab pour.
It's easy to read and understand this code once you understand that functions require inputs (denoted by the parentheses). Now, we can implement it in Python or any other language. Let's add a couple of extra steps to account for real world conditions.
Algorithms
Algorithms take this a step further by describing the precise logic and sequence of steps in a more formal notation. You don't need complex mathematical symbols, the key is clearly laying out the procedural flow using basic statements, conditions, loops, and functions.
An interesting distinction between โformulasโ and โalgorithmsโ:
Formulas directly calculate a single output, e.g.
Algorithms can encompass multiple formulas, logic, and even create new formulas on the fly to adapt to input data.
In this example, we add a condition to make the function more robust.
As an engineer, you're already familiar with flowcharts for mapping processes, equipment, operations, etc. Pseudocode and algorithms serve the same purpose but for coding. Rather than jumping straight into language syntax, pseudocode and algorithms allow you to plan your programmatic approach methodically. This up-front work avoids getting bogged down in code while simultaneously practicing the crucial skill of decomposing complex problems into methodical steps.
Investing the time to define the problem statement and sketch solutions using pseudocode and algorithms may seem tedious. However, this fundamental planning stage, emphasizing clear communication and systematic logic, is arguably the most critical part of adopting a programmatic mindset. Mastering this concept will streamline your coding efforts while producing more robust and maintainable solutions. Understanding and leveraging pseudocode/algorithms is a game-changer.
Problem Decomposition
Complex engineering problems rarely have a single solution that can be implemented in one shot. Breaking the problem down into more manageable sub-problems is part of developing a programmatic mindset. Once decomposed, each sub-problem can be tackled methodically through algorithms and data structures.
When decomposing problems, look for distinct tasks or processes that can be isolated. Each of these sub-problems can then be worked on individually while contributing to the overall solution. This compartmentalized approach simplifies the programming effort and allows easier debugging and code maintenance.
Variables, Control Flow, and Logic
Even outside of programming, variables are used extensively in engineering to represent and track values through equations and calculations. In coding, variables allow you to store data and information that can be referenced and manipulated as needed.
Length, yield strength, and temperature are all variables.
While the concept of variables holding simple values is a useful starting point, the rabbit hole goes much deeper. Variables can represent complex data structures (strings, arrays, lists, dictionaries dataframes, etc.), and understanding these structures enables strategic choices about data storage, manipulation, and algorithmic efficiency.
Control flow refers to the sequence of operations that allows programs to make decisions based on certain conditions, loop through repetitive tasks, and control the overall logic and pathways followed. Concepts like if/else statements, for/while loops, and switch cases are fundamental to coding.
Being able to think through logical operations, mathematical expressions, and control structures is critical for developing solutions systematically rather than relying purely on trial-and-error coding.
Remember, while your engineering design calculations often incorporate logic, I'm referring to a broader level of abstraction โ the flow and structure of your overall design intent and workflow. This is where the value of programmatic thinking is most evident.
Functions
In programming, functions are reusable blocks of code that perform a specific task. They promote modular programming by allowing you to compartmentalize logic into self-contained units.
As an engineer, you already use functions extensively in the form of engineering calculations, equations, correlations, and other formulas. Programming functions work in a similar way, they accept inputs, perform operations based on that input, and return an output.
By breaking down your solutions into individual functions that handle distinct tasks, you make your code more organized, easier to read and maintain, and simpler to test and debug. Thinking in terms of functional units is a key part of the programmatic mindset.
Practical Approaches
Start with the problem statement: Clearly define the problem you are trying to solve, the known information, constraints, and expected outputs. Having crystal clear requirements makes it easier to develop a solution programmatically.
Decompose, don't dive in: Never start coding without first decomposing the problem into sub-tasks and mapping out your approach with pseudocode or algorithms. Decomposing up-front avoids getting tangled in language syntax.
Take a step back: If you get stuck on a sub-problem, take a step back and re-examine your problem decomposition and logic. Sometimes, reinspecting the overall approach reveals simpler ways to solve parts of the problem.
Start coding at the edges: Rather than trying to develop the overall solution in one go, start implementation on the cleanest sub-problems first and work your way towards more complex areas. This incremental approach prevents getting overwhelmed.
Explain your code to yourself or to a cup of coffee. Explaining your code line-by-line to an inanimate object forces you to think programmatically about your logic rather than making leaps. Be careful about who sees this.
Write pseudocode as you code: Don't just dive into syntax. Write out the intended logic as pseudocode comments before coding each function or algorithm. This ties your implementation back to the programmatic plan. Rather than thinking about how comments can explain your code, think about how your code explains your comments.
Learn to divide and reuse: Functions are the bread and butter of modular programming. Get in the habit of dividing your solution into small, reusable functional units with well-defined inputs and outputs.
Review worked examples: Study how experienced programmers have approached and solved similar engineering problems programmatically. Their code can provide insights into effective decomposition and programmatic techniques. People say you donโt need to reinvent the wheel but Iโm still glad I have pneumatic tires.
The core skills of engineering - problem decomposition, logical thinking, process mapping, and analytical rigor - translate remarkably well to the world of programming. By adopting a programmatic mindset focused on pseudocode, algorithms, control flow, data structures, and functional modularity, you'll write more robust, maintainable, and efficient code while reinforcing engineering fundamentals.
With practice, you will begin to think programmatically about everything. All engineers can benefit from improving this skill, whether theyโre writing code or not.
The Flocode community is growing. Thank you all for your time, support, and patience. We are now up to 97 countries. Greenland is still holding out.
See you in the next one.
James ๐