开源日报 每天推荐一个 GitHub 优质开源项目和一篇精选英文科技或编程文章原文,坚持阅读《开源日报》,保持每日学习的好习惯。
今日推荐开源项目:《世界披萨 pizza》
今日推荐英文原文:《Here is how to debug everything》
开源日报第538期:《世界披萨 pizza》
今日推荐开源项目:《世界披萨 pizza》传送门:GitHub链接
推荐理由:世界上有无数国家,无数城市,自然也有无数美食。这个项目收录了地球上某个城市里值得一去的披萨店,在出国旅游的时候可以作为参考使用。在别的国家有着和祖国不同的风景,人物和美食,有机会的话应该去为自己涨一涨见识,工作可不是生活的全部,毕竟工作的最终目的也是为了获得更好的生活不是吗?
今日推荐英文原文:《Here is how to debug everything》作者:Borislav Grigorov
原文链接:https://medium.com/@Brslv/how-do-you-debug-code-6e54c7701a85
推荐理由:调试的基本步骤和技巧

Here is how to debug everything

Originally published on my blog borislav.xyz.

How do you debug code?

Do you have a process? Do you use debuggers or you do it the old-school-print-statements-everywhere way? Or you just rewrite it from scratch, because you “ain’t got time fo’ dat”?

In this article I’m going to give you some proven techniques and steps for debugging everything in general, plus some code-related specifics. These are the tools and processes in my tool belt that I use on a day to day basis.

It’s going to be an exhaustive list, so fasten your seatbelts and prepare to soak some battle tested wisdom.

The process to debug everything – meta-level tactics

It doesn’t matter if you debug a frontend issue, a backend issue, your car or your productivity. There are some universal approaches, which are valid in every life-situation.

I call these meta-level tactics or steps.

Here are the four meta-level steps, which everyone can apply to their specific problem.
  1. Problem clarification
  2. Research and exploration
  3. Experimentation and application
  4. Iteration

Problem clarification

the deeper the level of awareness about the problem, the better chance to solve it the right way.

That’s the first meta-level step in my four step model.

If you want to fix something, you should first know what’s broken.

In practice, it means that you have to fully, deeply engage with the problem “in front of you”. You must understand it.

I’ll give you an example.

If your car gets broken on the middle of a trip and it suddenly stops, you know there’s a problem right away. You open the hood and see smoke. You know that this smoke is a sign, but do you really know where it’s coming from. Do you know why there is a smoke at all?

Knowing that the smoke is a problem is the first level of awareness. Understanding the reason why there is a smoke is a second, deeper level of awareness – one that you should always strive for.

The general rule is this: the deeper the level of awareness about the problem, the better chance to solve it the right way.

And I’m bolding ” the right way” for a reason. Because everybody can center a div on the page with margins and paddings, but the right way is to center it without absolute values, using a flexbox, CSS grid or whatever, except margin and padding.

So, you should make absolutely sure that you get the problem and the reasons behind it as deeper as you can.

Research and exploration

Now that you know the roots of your problem, you can proceed to the exploration phase.

Most of the times you’ll have to deal with issues that you haven’t dealt with before. But it’s almost 100% possible that somebody has solved most of those problem before. You just have to do the research.

How?

It’s a matter of proper googling most of the times, but other strategies, such as posting on specialized forums, asking colleagues and friends and exploring by yourself (more on this on the third step) are also good to be considered.

Another important thing regarding the research and exploration phase, is that you have to constrain your efforts particularly on collecting and gaining knowledge about the subject of your problem and not get distracted by anything else.

Don’t start working. Just collect ideas and think about possible approaches.

What I usually do is I set a 30 minutes timer. While I’m exploring the topic around my issue I take notes and collect ideas (often on a piece of paper or a new file in my code editor).

When I feel that I’m ready and have enough knowledge about the “thing”, I move to the next, third step of the process.

Experimentation and application

This step is the most creative, but most difficult one to execute. You have to apply the knowledge from the previous two steps and find a working solution for your specific case.

One of the things that I usually do to achieve this, is to isolate the problem as much as I can.

If, for example, I’m solving a problem with some module of the software I’m developing, I do as much as I can to isolate that module from the external dependencies and reproduce the issue just with this single entity.

Isolation is the way to make sure you have control over the “moving parts”.

It’s the same whether you’re fixing your oven, the TV, your computer or even you relationship. It’s just different “modules”, which you have to define and be conscious about.

Another good thing to know at this step of the process is that you have to make sure your solution takes care of other possible variations of the problem at hand. This means that you have to ” expand ” it in your head and think a bit more about other “problem-mutations” and whether your solution is solid enough to handle them.

Of course, there’s possibility that you couldn’t solve the problem. In that case, go straight to step four.

Iteration

Just keep grinding!

Everything that you did up to this point is a valuable experience. If you haven’t solved the problem yet, it’s time to iterate.

That means that you should start from step one and dig deeper into the theory behind your problem. After that explore possible solutions and apply those to your particular case until the problem gets solved.

Remember that with every iteration you’re closer to the happy outcome. Just keep grinding!

Now, having this knowledge, let’s apply it specifically to the field of software development and see what we can learn.

But first, some…

Precautions

Don’t be clever

Code is like humour. When you have to explain it, it’s bad. Cory House

It’s funny how we keep forgetting the most important rule of debugging – debugging is inevitable.

I’m intentionally stressing this, because being conscious about the fact that the code you’re writing right now is going to break sooner or later, definitely will influence the way you do write it.

That’s why the first and most important thing, before even starting to debug, is to make sure that you’re writing clean, simple and understandable code.

Remember, your code editor is not the right place to be clever.

Use tools

In order to prevent all kind of bugs, use the proper tools for your language. In the JavaScript land, for example, there are linters, various code style checkers and formatters, etc.

If you’re developing in JavaScript I strongly suggest you to use strongly-typed “language extension” like flow or TypeScript. It gives you a huge advantage as the confidence that you’re going to get out of using those types is enormous. Refactoring turns into a much more pleasant experience, the code becomes the documentation and you get all the benefits of the compile type error checking, which, once you try, you’ll love.

For the guys that already develop in such an environment or their language enforces it – you got that point covered.

Do code reviews

If you work in a team, the number one thing you should do in order to avoid future problems with your codebase, is to enforce a practice of regular code reviews.

This ensures three things:
  • That the developer who wrote the code didn’t miss a thing or did a thing that’s not needed at all (system coherence, enforced by the team)
  • That other developers understand the code and feel confident to maintain/extend it.
  • That all the team members are on the same page regarding the system and it’s features.
There’s one more benefit, though. It’s more of a side effect, a thing that you don’t explicitly realise when you do the code review itself. And that’s that you and your team constantly look after the codebase, which prevents possible bugs.

So, do your code reviews to save you some hard times down the road.

Be a Boy Scout – The DSC formula

Have you heard of the “Boy Scout” rule?

It’s a simple rule, coined by the great Martin Folwer. It says that we should always strive to leave the code we’re touching a little bit better than it has been before us touching it.

Rename a variable, extract a method, simplify an if statement, remove duplication. Those are all quick wins, which make your code one step closer to perfection.

The benefits from doing these are not immediately measurable. The key thing here is the compound effect. If you do this consistently, you’ll start to see positive results – more maintainable, readable and clear code.

Follow the DSC formula, when you’re in the mode of refactoring.
  • Remove Duplications
  • Simplify what’s overly complicated
  • Clarify what’s not clear
Ok, we have covered some basic preventative tips.

Let’s take a quick look at what we can do, when in “debug mode”, in order to be productive and quickly resolve the issues.

Debugging consciously – the mindset

The time to debug has come and you probably feel a bit anxious. A little bit of uncertainty and nervousness are arising and you don’t know where to start from.

This is the time to stop, take a deep breath and switch your mental model.

The crucial thing about debugging is to stay calm and positive. The moment you start to doubt and to let anxiousness and negativity enter the scene is the moment you have lost half the battle.

Try to view the problem in front of you as a learning experience.

One thing that helped me is to approach the bug with an eye of a scientist. Think about how a scientist approaches a problem. Think empirically. Collect data. Analyse it and try things. Take notes on the results and adjust accordingly until the desired outcome.

Turn it into a game, if you wish.

It’s all about the mental foundation and the words you say to yourself.

The process of debugging code – the practical guide

Now that we have covered the meta-level steps to debugging every problem and some specific precautions for developers to prevent bugs popping, let’s get into the details of debugging programming problems (bugs).

Problem clarification – how developers should do it

Since we have covered the generic part of this step above, it’s time to see what we can do as developers to improve our understanding of the problem at hand.

There are three main advices that I can give you here.

RTE – Read The Error

I’m really convinced that around 80% of the difference between a junior and a senior developer is in how they read the error and the error stack trace. Most juniors refuse to dig deeper into the error itself. They just see it and start complaining or directly search google etc.

It’s more of a game for the more seniors. Debugging is a game of understanding what went wrong and what the computer is trying to tell you. Read the error again. Track the traces. Don’t be afraid to look inside of the more nested layers of the error stack. There hides a treasure. Be an explorer and you’ll learn more.

RTM – Read The Manual

If you’re working with a third party API or service and you have problems with it, make sure the first thing you do is to read their documentation.

Almost all problems that arise from a third party layer, are problems of inaccurate usage of it.

So, save yourself some time and read everything. You can even find a much better, cleaner and wiser way to do the thing you’re doing.

One bonus tip is to dig into the source of the third party. It never lies.

Use a debugger

Put a breakpoint and investigate the state at that point of the execution lifecycle of your program. Debuggers are sometimes being underrated, which is not fair. It’s the best way to “become” the computer and see the internals of the execution.

Research and exploration

Great creators always reuse knowledge

Here comes the time to explore the different possibilities, the broad range of approaches towards the problem that you have.

Again, what I usually do is I set aside some time (30 minutes or more, if the problem is bigger) and dedicate my entire focus to just collecting different solutions. This is a key thing. You should have a pool of those in order to be able to mix and match and come up with the best for your specific case.

There are countless possibilities for explorations.

One of those is the well known and loved by developers — the StackOverflow forums.

I usually also research medium articles, various blog articles and the entire google in general.

Often there are times that I’d look directly at other people’s code on GitHub.

Asking a colleague is one of the most under appreciated options, but one of the most powerful. It has the amazing “side effect” of building a strong connection with your teammates.

The last suggestion is maybe unexpected one, but one that I usually pick as the “weapon of choice” when it comes to creating/solving something that I know I have solved before. And it’s digging into my old source code. I have tons of it, so there’s a lot of hidden treasure there.

And remember — great creators always reuse knowledge. Don’t be afraid to copy-paste, even from yourself.

Experimentation and application

We know the problem, why it’s happening, when it’s happening and we have a fuzzy idea how to approach it. We might even have a pool of viable ideas and solutions found on the internet or through some other source. Or we have came up with our own original solution. Now it’s time to get our hands dirty.

As I said in the generic section of this step above, the key thing here is isolation. You have to find a way to decouple the problematic area of the system from the things that it depends on.

Here’s what I do.

Let’s say I have a function somewhere in my code, that calculates discount from a price. For some reason this function is broken and it doesn’t calculate the thing properly.

This “module” of our software depends on two things — the base price and the discount percentage. Those are passed into the function as arguments. How to isolate them in order to constrain only on what’s the “core” of this module?

Usually I handle such kind of situations by using some kind of code prototyping/scratchpad tool. For JavaScript there are many — codesandbox, jsbin, stackblitz, even the console of your browser of choice. The most generic tool, which works for almost any language is repl.it.

Anyways. So, I copy the function directly over there (let’s say repl.it) and literally replace the dependencies with hardcoded values. I just isolate the function entirely and mock each of it’s dependencies so I have control over it.

Now, this “isolation” is usually being taken care by automation tests, if you have any (which is more or less a must). But, for a quick and dirty experimentation it does the job. Remember, the thing is not how, but whether you do isolate the moving parts.

Having your problem solved in isolation, you have the wisdom to integrate the solution back to your system. Congratulations.

If you don’t have it yet, though, go back to step one. You know the process now, so just keep pushing it and you’ll get it solved, sooner or later.

Conclusion

Solving problems is a strict process. It starts with gathering enough information and gaining knowledge about the nature of our problem. Understanding it deeply being able to articulate it.

Once we have this, we start looking for solutions and approaches we can reuse, mix and shape to fit our needs. Remember, your problem is one that’s most probably already being solved, so just dig for inspiration.

Now, having a pool of ideas, you have to apply those to your specific case. You do it by isolating your problem and trying a bunch of things in a sandbox-like environment, where each moving part is being captured and controlled by us.

And the most important thing is to not get demotivated. Take a break, go outside for a walk, drink some water. After that iterate. With each iteration you get closer and closer to the solution, whether you see it clearly or not. Just keep pushing.

Good luck and be inspired!
下载开源日报APP:https://openingsource.org/2579/
加入我们:https://openingsource.org/about/join/
关注我们:https://openingsource.org/about/love/