Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 12, 2022 08:01 pm GMT

Problem-solving techniques to avoid yelling at your computer

I have been facing some tough code monsters at work lately. I guess I'm out of shape and my sword isn't sharp enough, because I find myself struggling greatly.

This is the reason I decided to upgrade some of my attributes (especially intelligence and wisdom) in order to help me cope with this struggle. Luckily, I found a great loot: Think Like a Programmer, by Spraul, V. Anton.

Think Like a Programmer

This book explains how we should approach problems in order to solve them in a methodical manner. I have just started reading it, but I have already learned the basics of problem-solving techniques, and I wanted to share them with you.

General Problem-Solving Techniques

1. Always Have a Plan

When working on a solution to a problem, starting by typing code without a clear direction in mind is not a good idea. Sometimes I found myself typing without putting too much thought into it, just for the sake of building something fast and, if Im "lucky", stumbling with the solution to the problem. This is an awful approach.

According to the book, we should always have a plan. In the beginning, the plan usually will consist in how we are going to find the solution to our problem.

Our plan will, most likely, require alterations along the way, and this is OK. Without a plan, we are directionless, we miss on evaluating possible scenarios and different alternatives to find a solution.

I have always found that plans are useless, but planning is indispensable. - General Dwight D. Eisenhower

I prefer to think about a plan as a map that allows seeing all the possible roads to a destination (or even draw new ones as they manifest along the journey).

The book emphasises that plans allow us to set intermediate goals, and achieve them. This is of extreme importance because by achieving these intermediate goals we feel we are making progress towards the solution. As we are usually going to struggle until the solution is found, feeling that we are making progress will help to cope with despair.

2. Restate the Problem

A problem that at first seems incommensurable, could be expressed in other terms, or in a different manner. At first sight, we might think the problem is one way, but upon restating it we can discover that it's something different.

Change of perspective

Restating the problem in new, simpler or more familiar terms, could help us to redefine it and to come up with different solutions (hopefully, easier to implement than what we first thought would be).

Restating the problem could be thought of as one of the planning steps in solving a problem, and if we do restate the problem, we will be making progress towards the solution.

3. Divide the Problem

You dont eat an elephant in one bite but in multiple small bites. Actually, I have never eaten an elephant, and I wouldn't either, as they are one of my favourite animals! But the metaphor is still applicable.

If the problem is too complex, divide it into smaller chunks. If we need to ask for user input, process the data, and store it in a database, start by building a simple input field that prints on the console, and build on top of that.

If we need to build a complex loop, we can start with one line, or a couple of lines, and manually perform the tasks that the loop should do until we have a clear idea of what is needed.

This is the technique I use the most when coding and is the one that helps me to keep my sanity when facing complex problems.

4. Start with What You Know

After dividing the problem into pieces, we can start by solving what we already know how to solve. Later we can focus on the tricky parts of it.

Does our problem require finding unique values? If we know how to use a Set in JavaScript, that could help us to solve it.

By starting with what you know, you build confidence and momentum toward the goal. - Spraul, V. Anton

5. Reduce the Problem

If the problem is too complex or if it cant be subdivided into smaller pieces, we can reduce its complexity by applying (or removing) constraints to it.

Should a user be able to drag and drop tasks in our to-do app? Lets write step by step all that is needed in order to implement this functionality and eliminate (for now) whats too complex. Later we could review what we have left out and ask for help in order to solve those specific aspects of the problem (and not the whole problem).

The author of the book uses an excellent example here:

One never wants to be reduced to saying, Heres my program, and it doesnt work. Why not? Using the problem-reduction technique, one can pinpoint the help needed, saying something like, Heres some code I wrote. As you can see, I know how to find the distance between two three-dimensional coordinates, and I know how to check whether one distance is less than another. But I cant seem to find a general solution for finding the pair of coordinates with the minimum distance. - Spraul, V. Anton

6. Look for Analogies

We are often solving the same problem, but in a different flavour, over and over again.

We should pay attention to similarities between the problem we have in front of us, and other problems we solved in the past.

If the problem is totally new, thats great, because its a great opportunity to put it inside our cookie jar of solved problems for future use.

7. Experiment

If everything looks dark and we dont know why the program is behaving as if it had life on its own, experimenting with it can help us.

I usually use console.log as a probing method to find out whats happening. We can tweak something here and there and see how the output gets modified. Then make hypotheses and put them to the test.

It is important to make a distinction between experimenting and guessing. Experimenting is a controlled process: we gather the information that can help us solve the problem. Guessing is typing code mindlessly and hoping for the best.

8. Dont Get Frustrated

The final technique is more of a recommendation than a technique in itself: don't get frustrated.

I must confess that I had felt frustrated many times, and I can assure you that it didnt help me one bit to solve the problem.

How does the rage you feel inside of you help you solve a problem? Why are you angry? Or a better question even: why do you choose to be angry?

Here is where two maxims of the Stoic philosophy come for our help:

We suffer more often in imagination than in reality. - Seneca

And:

The chief task in life is simply this: to identify and separate matters so that I can say clearly to myself which are externals not under my control, and which have to do with the choices I actually control. Where then do I look for good and evil? Not to uncontrollable externals, but within myself to the choices that are my own - Epictetus, Discourses, 2.5.45

We have to learn to manage how we respond to frustration. As developers, its very likely that we are going to face bugs in our code or complicated features to implement on a daily basis, and a good portion of them are going to be difficult to solve. Hence, its better to learn not to feel frustrated because of this, but rather think of this as a feature of our job.

I often remember this question:

What shit sandwich do you want to eat? Because eventually, we all get served one. - Mark Manson

And then I realise: "I have chosen this struggle, so I shouldn't get mad because of it."

Something that can help us to get out of a frustrating moment is to iterate on these steps again: build a new plan, restate the problem differently, create different problem divisions and alterations, etc.

Practice time

Now, lets put all these concepts into practice. I have adapted one of the problems presented in the book from C++ to JavaScript for convenience purposes.

By the way, you can get the source code from my repository (I plan on keep adding new problems as I move forward in reading the book): think-like-a-programmer-book-problems.

Write a program that uses a single console.log statement to produce a pattern of hash symbols shaped like half of a perfect 5 x 5 square (or a right triangle):###############Spraul, V. Anton. Think Like a Programmer (p. 26). Adapted from C++ to JavaScript by Damian Demasi.

The plan

We are going to take the problem, divide it into smaller pieces, and start solving the pieces one by one. We are going to search for analogies along the way. In the end, we will put everything together.

Restating the problem

After analysing the problem a bit deeper, we can see that there is a pattern that needs to be printed and that this pattern gets altered on each line. I dont know about you, but this is suggesting iteration to me, so we will use some sort of loop to solve it.

Our restatement could be something like: write a loop that prints a line of hash symbols where each line gets one less hash symbol that the previous one, starting with 5 symbols on the first line.

Divide the problem

We can divide this problem like this:

  1. Print a line of 5 hash symbols
  2. Print 5 lines of 5 hash symbols
  3. Find a way to decrease a number as a count grows
  4. Apply point 3 to point 2

Start with What You Know

Lets start by the easy part: print 5 hashes:

    let halfSquare = '';    for (let i = 1; i <= 5; i++) {        halfSquare += '#';    }    console.log(halfSquare);

Output:

#####

Great! Its not much, but its honest work .

Reduce the Problem

Now, instead of printing five lines with a decreasing number of hashes, let's print 5 lines with the same number of hashes. By doing this we are simplifying the problem and reducing its complexity and constraints.

let halfSquare = '';    for (let i = 1; i <= 5; i++) {        for (let j = 1; j <= 5; j++) {            halfSquare += '#';        }        halfSquare += '
'; } console.log(halfSquare);

Output:

#########################

Look for Analogies

In the previous block of code, we are using something we already know (a loop) to repeat the line of hashes 5 times, resulting in a nested for loop. This is our analogy.

Experiment

Now we need to find a way to decrease a value as the loop increases. In the book, this is referenced as counting down by counting up.

Lets experiment to find this behaviour starting with the easier part: counting up.

for (let i = 1; i <= 5; i++) {    console.log(i);}

Output:

12345

After looking at the expected end result (the triangle of hashes) and comparing it with our experiment, we can think of these numbers as the number of hashes that need to be subtracted on each line plus 1:

LineResult
First line:5 hashes - 1 + 1 = 5 hashes
Second line:5 hashes - 2 + 1 = 4 hashes
Third line:5 hashes - 3 + 1 = 3 hashes
Fourth line:5 hashes - 4 + 1 = 2 hashes
Fifth line:5 hashes - 5 + 1 = 1 hash

If we use 6 hashes, we can get rid of the + 1 part:

LineResult
First line:6 hashes - 1 = 5 hashes
Second line:6 hashes - 2 = 4 hashes
Third line:6 hashes - 3 = 3 hashes
Fourth line:6 hashes - 4 = 2 hashes
Fifth line:6 hashes - 5 = 1 hash

So, as 6 looks like an important number for our purposes, and as the subtracted number looks like the for loop iterating as a new line gets printed, lets see what happens when we subtract the current iteration number from 6:

for (let i = 1; i <= 5; i++) {    console.log(6 - i);}

Output:

54321

This is starting to look good!

So, as the first line will need to have 5 hashes, the iteration should go from 1 to 6 - 1 = 5.

let hashLine = '';for (let i = 1; i <= 6 - 1; i++) {    hashLine += '#';}console.log(hashLine);

Output:

#####

Moving to the next line, to build it our loop will need to change the i <= 6 - 1 condition to i <= 6 - 2 condition. This pattern is pointing to a loop incrementing a value on each iteration, and we already have that loop: its the outer for loop.

When combining these findings with what we already have we can arrive to the conclusion of our problem:

let halfSquare = '';for (let i = 1; i <= 5; i++) {    for (let j = 1; j <= 6 - i; j++) {        halfSquare += '#';    }    halfSquare += '
';}console.log(halfSquare);

Output:

###############

And this is the fruit of the struggle, the thinking and the experimenting.

Closing thoughts

Applying all these techniques at once is not easy for me. I discovered that I have my way of solving problems, but its often not the most suitable way of doing so. As with most new habits, implementing a particular process comes with a certain resistance. This is why Im taking the approach of implementing these problem-solving techniques one step at a time (and Ive noticed that Im going full-on "inception" here, using the division of a problem into smaller pieces as a technique to implement the problem-solving techniques ).

Notion templates, trackers and roadmaps

Psst! Before you go, I have something to share with you. If you are a subscriber of my newsletter, you already know this, but in case you are not, I would like to share with you these 3 free resources:

My Notion template with over 440 pages of web development content, so you can use Notion to organise programming topics.

My HTML Study Progress Tracker and Roadmap Notion Template, so you can keep track of your progress in learning HTML concepts (and review them).

And my CSS Study Progress Tracker and Roadmap Notion Template, to to the same as before but with CSS.

They are totally free for download and use, but I'm always open to donations (I need to buy coffee to transform it into code ).

NEWSLETTER - If you want to hear about my latest articles and interesting software development content, subscribe to my newsletter.

TWITTER - Follow me on Twitter.

Buy Me A Coffee


Original Link: https://dev.to/colocodes/problem-solving-techniques-to-avoid-yelling-at-your-computer-41e9

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To