惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
InfoQ
Spread Privacy
Spread Privacy
GbyAI
GbyAI
F
Fortinet All Blogs
小众软件
小众软件
B
Blog RSS Feed
博客园_首页
量子位
Y
Y Combinator Blog
美团技术团队
H
Hackread – Cybersecurity News, Data Breaches, AI and More
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
大猫的无限游戏
大猫的无限游戏
Jina AI
Jina AI
T
The Blog of Author Tim Ferriss
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Vercel News
Vercel News
Last Week in AI
Last Week in AI
F
Full Disclosure
Stack Overflow Blog
Stack Overflow Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
宝玉的分享
宝玉的分享
Microsoft Azure Blog
Microsoft Azure Blog
有赞技术团队
有赞技术团队
A
About on SuperTechFans
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
The Cloudflare Blog
Hugging Face - Blog
Hugging Face - Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Tenable Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Project Zero
Project Zero
C
CXSECURITY Database RSS Feed - CXSecurity.com
Engineering at Meta
Engineering at Meta
博客园 - 叶小钗
S
SegmentFault 最新的问题
T
Threat Research - Cisco Blogs
博客园 - 司徒正美
MyScale Blog
MyScale Blog
云风的 BLOG
云风的 BLOG
V
V2EX
酷 壳 – CoolShell
酷 壳 – CoolShell
The GitHub Blog
The GitHub Blog
V
Vulnerabilities – Threatpost
S
Schneier on Security
Latest news
Latest news
I
Intezer
A
Arctic Wolf
T
Threatpost

Secret Weblog

Becoming More Xee: A Modern XPath and XSLT Engine in Rust Looking for new challenges! Repeat Yourself, A Bit The Curious Case of Quentell The Humble For Loop in Rust The Humble For Loop in JavaScript Question Best Practices I Was a 1980s Teenage Programmer Part 5: Achieving Assembly I Was a 1980s Teenage Programmer Part 4: The Call of Assembly The Tooling Shift I Was a 1980s Teenage Programmer Part 3: MSX-2 JavaScript: when you need two ways to do it! Empowering Programming Languages Bloat and Retrofuturism Refreshing my Blog Again Random Rust Impressions Apilar: An Alife System I Was a 1980s Teenage Programmer Part 2: Olivetti M24 I Was a 1980s Teenage Programmer: the Alphatronic SolidJS fits my brain Is premature optimization the root of all evil? Framework Patterns: JavaScript edition Roll Your Own Frameworks Framework Patterns Secret Weblog Highlights Refactoring to Multiple Exit Points mstform: a form library for mobx-state-tree Seven Years: A Very Personal History of the Web Morepath 0.16 released! Is Morepath Fast Yet? Introducing Bob Strongpinion Punctuated Equilibrium in Software Morepath 0.15 released! Impressions of React Europe 2016 Morepath 0.14 released! Morepath 0.13 now with Dectate Dectate: advanced configuration for Python code JavaScript Dependencies Revisited: An Example Project The Incredible Drifting Cyber A Brief History of Reselect The Emerging GraphQL Python stack Thoughts about React Europe Build a better batching UI with Morepath and Jinja2 GraphQL and REST Server Templating in Morepath 0.10 10 reasons to check out the Morepath web framework in 2015 A Review of the Web and how Morepath fits in Morepath 0.9 released! Better REST with Morepath 0.8 Morepath 0.7: new inter-app linking They say something I don Life at the Boundaries: Conversion and Validation BowerStatic 0.4 released! Morepath 0.6 released! Morepath 0.5(.1) and friends released! New HTTP 1.1 RFCs versus WSGI Against On Naming In Open Source My visit to EuroPython 2014 Morepath 0.4.1 released (with Python 3 fixes) Morepath 0.4 and breaking changes Announcing BowerStatic Morepath 0.3 released! Morepath 0.2 Morepath Python 3 support The Call of Python 2.8 Morepath 0.1 released! WebOb and Werkzeug compared Morepath: from Werkzeug to WebOb Racing the Morepath: SQLAlchemy Integration The Centre Cannot Hold Breaking Morepath Changes Morepath Update How to do REST with Morepath Morepath Security the Gravity of Python 2 #python2.8 discussion channel on freenode Alex Gaynor on Python 3 Morepath Documentation Starting to Take Shape Back to the Center Morepath App Reuse Implementing Grok Grok: the Idea Why Linux Works for Me On the Morepath Reg, Now With More Generic! The New Zope as a Web Framework Jim Fulton, Zope Architect Renewing Zope Object Publishing The Weirdness of Zope The Rise of Zope My Exit from Zope Reg: Component Architecture Reimagined JSConf EU 2013 impressions Obviel 1.0! JS Dependency Tools Redux Obviel 1.0rc1 released! Succinct data structures
Don
Martijn Faassen · 2024-11-22 · via Secret Weblog

People tend to look down on print debugging as it's not using sophisticated tools at all. You're not using debuggers, fancy loggers, or profilers.

You're just using the humble print statement. Or print() function. or console.log(), or println!() or whatever your language calls it.

Print debugging is awesome and you should feel no shame in using it! It's the tool that works for all languages 1. It's easy to understand and easy to implement. It focuses the mind on thorough reading and understanding of code, rather than getting lost in a forest of data.

Print debugging is really effective in many cases.

Print debugging is not the same as logging. You put in the print when you try to figure out what went wrong, and you take it out again once you figured it out, preferably before you commit!

A bad practice?

People feel print debugging is a bad practice.

The internet is full of advice to avoid print debugging in favor of other things. I'll throw in some random headlines without linking, to demonstrate the vibes:

  • "why you should not use console.log( ) for debugging"

  • "Do not use Print. Master Python Logging"

  • "STOP using simple console.log in JavaScript. Try this instead"

  • "Stop using Print, and start Debugging"

  • "Stop Using 'Print' and Start Using 'Logging",

  • "No-Print Python. Stop using print to debug"

  • "Stop console.log(). There are better ways!".

I'll grant some of these articles try to get you to adopt some library that introduces a smarter print which adds debugging output. I'm all for it, though there's still a huge benefit to print just being there. 2

We should instead label print debugging a good practice3.

So to be absolutely clear, here's the workflow:

  • Discover problem
  • Add in print statements in strategic locations where you want to check your assumptions.
  • Look at what happens. Are your assumptions correct? Change prints around for a while. Think.
  • Fix the problem.
  • Take out all the print stuff again.
  • Done

The Power of print

You can use expressions to process data! You can format data for readability! You can use if statements and loops and whatever you want! Even just a dumb print("here!") is good enough to see whether something gets called at all. And it's all in the programming language you already know.

Even More Power

You can write automated tests for some fraction of your codebase 4. You might even write them before you write your code!

Now you isolate your problem as a failing test. Figure out how to use your test runner to isolate it so you run just that one.

Then use the print debugging workflow for just one test, not the whole program! So if your test is only exercising part of your behavior, or better yet, only touching part of your codebase, you know that any printed output is because of that test only, which is extremely helpful in finding the bug.

I suspect part of the reason people go for a debugger more often is because they don't build up automated tests along with their codebase. Then in the end you have to debug something very complicated all at once. If you build up tests, you debug most things as you write them. It's much easier when you know you broke stuff in the few new lines of code you added or changed rather than everything everywhere all at once.

Wait

Before this somehow morphs into a deadly best practice, I'm not saying that using more sophisticated tools is bad. Use them if they're there and they fit your goals. Just don't dismiss print.

P.S. Not the first

I'm not the first person to point out print is good:

“The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.” — Brian Kernighan, “Unix for Beginners” (1979)

Many are apologetic or mixed up about it though:

I sourced that Kernighan quote from this article which does go on to conflate it with logging.

And this article goes into why print debugging can be so good, but then has to buy into the shame by saying:

I'm not saying that print debugging is the best end state for debugging tools, far from it. I'm just saying that we should reflect deeply on why print debugging is so popular, beyond mere convenience, and incorporate those lessons into new tools.

I am however saying print debugging works so well that while new tools may be able to add value, they inevitably are less universal and less simple, a great benefit of print debugging. Maybe print debugging is actually an optimum for a whole lot of scenarios?

The article "The Evolution of Debugging: From Print Statements to Modern Tools" has a good analysis of the trade-offs, and even though the title implies print debugging is an antiquated, primitive tool, it ends with "Don't dismiss traditional debugging methods".

And here we are, an unbashedly unapologetic article like mine: "'Print' Is the Only Debug Tool You Need". Just to show I'm not being original.

1

Even Haskell, which frowns on side effects, has an impure function called traceShow.

2

Like in Rust, for which I can find few articles agitating against println!. There's this one which steers you towards using dbg!(), which is built-in and very useful, but I still use println!() as well as I can control the output better and it's less noisy.

3

Or a best practice, but that's a problematic term, I think.

4

It helps to have decoupled code. Like, you split your codebase up into parts that you can understand and debug independently. But even for a huge fraction of your codebase print debugging can still be useful.

5

Some testing tools are helpful in that they don't print out anything for tests that succeed, only the failing one, though sometimes that's annoying and you have to learn how to disable it.

Comments

You can use your Mastodon account to reply to this post. Learn how this is implemented here.

Reply to this post

With an account on the Fediverse or Mastodon, you can respond to this post. Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.

Copy and paste this URL into the search field of your favorite Fediverse app or the web interface of your Mastodon server.

Copied! Copy code to clipboard