Breaking Down Programming Problems into Manageable Sizes

Josiah Fordahl
6 min readJan 7, 2021

Combining the Two Layer Approach and PEDAC Framework to Solve Programming Problems

Launch School, where I attend Software Engineering School, talks extensively about when you start out as a programmer that there are two layers to every problem:

Layer 1.) The logic layerLayer 2.) The language syntax layer

The Logic Layer:
In the logic layer you have to figure out what the steps are for working through a problem. Unless you are working on a very simple problem, this logic layer is often unverifiable until you get to the syntax layer. It is helpful here to write logical tests to bolster your understanding of the problem and come at it from different angles.

The Language Syntax Layer:
In the language syntax layer you have to figure out how you are going to represent the above logic in your chosen programming language, using that language’s syntax. This is also where you verify the above logic.

A helpful rule of thumb I have found is that when debugging an error is that if you see unanticipated behavior in your application that is working, you probably have a logic layer error, language syntax errors usually just cause the application to break and generally your programming language points you toward the issue.

Trying to approach a complicated programming problem without first separating the logic from the syntax is often a non-starter for newbies. You often aren’t experienced enough in either breaking problems down logically nor the programming language syntax to feel confident at either.
You immediately feel overwhelmed and can’t really break it down into helpful component parts.

Photo by Sigmund on Unsplash

PEDAC helps you break down problems into manageable pieces…

PEDAC is a problem-solving framework:

Problem: (Understand your problem)Examine: (Examples and test cases)Data structures: (Decide on which one(s) to use.)Algorithm: (How will the problem be solved?)Code: (Code the Algorithm and test it step by step verifying your logic and test cases.)

As I see it, it is helpful to combine these frameworks for breaking problems down in a hybrid model:

- Layer 1.) The Logic Layer:Problem: (Understand your problem)Examine: (Examples and test cases)- Layer 2.) The Language Syntax Layer:Data structures: (Decide on which one(s) to use.)Algorithm: (How will the problem be solved?)Code: (The algorithm and test it step by step.)
Photo by Alvaro Reyes on Unsplash

Let’s break all of this down a bit further:

Here is a bullet list approach to going through the hybrid framework:

1.) The Logic Layer:
Problem — Understanding the problem:

  • Establish the rules/define the boundaries of the problem
  • Assess available information
  • Restate explicit requirements
  • Identify implicit requirements
  • Spend enough time. Don’t rush this step.

When Requirements are explicit:

  • Take notes

Rewrite problem in 2 ways

  • Input (what will be inputted)
  • Output (what will be output) (including error handling)

Edge Cases including:

  • — What happens if the number is 0?
  • — What happens if the number is even/odd?
  • — Should I return a string “\n” delimiters or should I just print on screen?

Requirements that are not so explicit and need to be modeled

  • Requirements are shown with examples
  • Examples need to be described in computational words

Implicit knowledge needs to be captured

  • Convert to explicit rules into computational language

Identifying and defining important terms and concepts

  • Same row; same column; esp. Same diagonal

IF IN A CODE INTERVIEW: ALWAYS ASK QUESTIONS TO VERIFY YOUR UNDERSTANDING BEFORE PROCEEDING.

The Logic Layer Part Two: Examples / Test cases:

Examine: examples and test cases (write test logic)

  • Will help you confirm or refute assumptions.
  • Helps to answer questions about implicit requirement.
  • Act as assertions which help codify the rules and boundaries of the problem.

Input / Output / Error Handling

Test cases serve two purposes:

  • Help you understand the problem
  • Allow you to verify your solution

Happy Paths

  • Combination of requirements; the “obvious” result

Edge cases:

  • Focus on input
  • Emptiness (nil/null, “ ”, [ ], { })
  • Boundary conditions
  • Repetition / duplication
  • Upper case / lower case
  • Data types (strings, integers, floats, etc)

Failures / Bad input

  • Raise exceptions / report errors
  • Return a special value (nil/null, 0, “ “, [ ], etc.

Always ask questions to verify your understanding!

Photo by Reza Namdari on Unsplash

2. ) The Language Syntax Layer:
How will you represent the above logic with your programming language?

Data structures: (Deciding on which ones to use.)
Helps you reason with data logically:

  • Helps interact with data at implementation level
  • Thinking in terms of data structures is part of the problem-solving process
  • Data structures are closely linked to algorithms
  • — A set of steps from input to output
  • — — Involves structuring data in a certain way.

>Input Data

>Rules/requirements as data — encode or store the logic of requirements in the data structure.

>String, array, hash/objects, number (Coding problems are usually always one of these data types.)

With more experience in each of these data type categories, you will find that especially with simpler problems the data structure choice becomes clear and immediate if you have already done most of the heavy lifting with the logic layer above. If you have done that logical heavy lifting, then thinking through the data structures and the pros and cons of the methods available to you with each becomes far more efficient.

If you find yourself bogged down and overwhelmed by which structure or method to use, it is a good signal to go back to the logic layer and do some more work clarifying the logical breakdown of the problem.

Structures and methods to think about:

String

  • — Concat, strip, reverse, etc
  • — Regular expression! split , replace, match, etc

Array

  • — Need to walk through it (iteration)
  • — Index
  • — Abstractions!!
  • — Map
  • — Reduce
  • — Select / filter
  • — All
  • etc …

Hash-(ruby) / object-(JavaScript)

  • Lookup table / dictionary
  • Partition data for more efficient access downstream
  • Digest

Number

  • Math operations
  • Number as string may have advantage over numbers

Compound data structures

  • Array of arrays
  • Hash with array/objects values, etc
Photo by Florian Olivo on Unsplash

Algorithm (Steps you will take to solve the problem)

  • A logical sequence of steps for accomplishing a task or objective
  • — Closely linked to data structures
  • — A series of steps to structure data to produce required output
  • Stay abstract and high level
  • — Avoid implementation detail
  • — Solve the problem, don’t worry about efficiency yet

Algorithms have to be described in the language of the chosen data structure!

  • Then solving it doesn’t count
  • Have to be really fluent with:
  • — String / Regex
  • — Array
  • — Ruby: Enumerable
  • — JavaScript: Higher Order Functions
  • — Hash / Object
  • — How to create — Creation (default values)
  • — How to access — Access (default values)
  • — How to iterate — Iteration

Verify your algorithm with your examples / test cases.

Code (Code the algorithm and Test it step by step)

  • Here we are translating our solution algorithm to code
  • Think about the algorithm in the context of the programming language.
  • — Language features and constraints
  • — Characteristics of data structures
  • — Built-in functions/methods
  • — Syntax and coding patterns
  • Use your test cases to think about your methods from multiple angles.
  • Code with intent — Step By Step (Always Test before you move on to the next step, this makes it far easier to debug.)

A Side Note on Abstraction:

  • Very important, rely on language built in abstractions: string/regex, array, hash/object
  • Avoid solving big problems
  • Always, always, break bigger problems into smaller problems
  • Don’t try to walk through a wall (Take a step back and break the big problem into smaller problems.)
  • Lay out the general steps of an algorithm, without having to go into details
  • Try to solve a problem in 1–2 sentences
  • If you can’t, raise your abstraction
  • Create helper method/functions
  • Push detailed steps to methods/functions

Final Thoughts:

  • Our Hybrid Problem solving model and PEDAC in general is not a completely linear process.
  • Move back and forward between the steps as needed.
  • Switch from implementation mode (language syntax layer) to abstract problem-solving mode (logic layer) when necessary.

Don’t try to problem solve at the code level, solve the logic problem, then code the problem and always test as you go.

--

--