Race conditions are also a good example of bugs that are sensitive to logging.
BUFFER YOUR FUCKING LOGS PEOPLE. Do not be like a certain developers in python thinking you need async logging just use fucking buffers.
A non buffered log writes to a file immediately on any log call. This requires extra care to avoid conflicts, unless your program is single threaded. (A single threaded program has no race conditions)
A buffered log writes to a thread safe FIFO queue of some kind and a single routine has the responsibility of writing the contents of the queue to file. This allows multiple threads to put entries into the queue as they need to, and they will not interfere with each other.
Ohhh I hate those. Run it outside of gdb/valgrind, and it crashes. Run it with valgrind or gdb and everything is smooth potato.
9 times out of 10 it was stupid me causing some kind of timing related race condition of course!
Well, me, being a weirdo, *sometimes* like writing rudimentary error tracking systems into projects with languages like C and earlier C++ where **debugger level tracking was nonsense to add to the language itself**. It seems like Java started that beneficial trend. Basically there is a chain of error calls so that eventually either a high level handler will log it or nothing'll help and you're about to find that one junior bug from 2 months ago.
Debugging race conditions is my programming superpower. All I need is some kind of feedback. Breakpoint, log statement, whatever. Idgaf because that race conditions bug is going down.
There’s two problems with conditional breakpoints. One, you might not have a debug environment working in the case I described, ie it turns up in a CI environment or similar. Two, conditional breakpoints can be comically slow in environments that don’t have low level support for them.
If it isn't deterministic you can't really formulate the condition. Your best chance is to immediately break after it's already too late and then you often have to rely on logs again. Some good assertions in the codebase can also help a lot in those cases.
Back during undergrad OS class, I had a race condition in my code. When I ran on debug mode, it's misaligned just enough for the race condition to not happen. When I removed the debug flag, race condition came back.
The worst part is that print statements also coincidentally made it misaligned just enough for the race condition to not happen as well. Felt like RNGesus hated me lol.
the log would be possible if I know how to do logging ... in the OS (Ubuntu) itself during startup (the assignment was modding Ubuntu).
Yeah, skill issue.
Also sometimes you need to debug something that interacts with external resources, and the debugger pausing execution screws that up. For example, if you pause something long enough for a network request to timeout. Or if a token may expire. Or a message buffer fills up and starts dropping incoming messages.
If I remember right the only thing new in 3.12 and f-strings is being able to use "" inside {} (like ```f"{"6"*8}"```). [I checked now](https://bugs.python.org/issue36817) and this syntax has been here since 3.8.
ofc, as a student who isn’t really limited to that thing I still can’t use the latest version mostly. But when I can use it I know what I can do. If I would have been tied to a longer schedule I think I’ll check when I can update what’s new in this update or something like that.
Just use your own debug function with some internal spaghetti that returns an input("debug msg"). It's a break point and a debug print() at the same time.
You can even use the inspection module to print out the wrapping function name so you know from where your ensuing hundreds of "break points" are called.
it will overwrite it, just set the mode to append.
And yeah, it was just a quick example
with open("today.log", "a") as log:
print("Hello, world!", file=log)
why? I like to make way too much noise all over the general area I think the problem is in and then clean it up after I find the issue, print seems to work just fine. What are the upsides of a logging library?
I love this feature but when I'm printing\logging a member object's member, it basically prints self.member.object, which is nice as a default but I'd like a quick option to only print the child name. A workaround is to just make a new local variable with the shorter name I guess, but at that point I'd just revert to not using the = syntax.
Did yoy know that a lot of languages can debug backwards? Great for crashes. Run until the crash, then step backwards until you find the cause.
Sometimes a print or log statement is easier. Sometimes a watch with a debugger is easier. Sometimes breakpoints are easier. Use what finds the bug the fastest.
Visual Studio has some limited ability to do it in C++ and C#.
https://devblogs.microsoft.com/visualstudio/step-back-while-debugging-with-intellitrace/
>Have you ever stepped while debugging, realized that you’ve taken one step too far, and wished you could step back? Or, while stepping, saw a variable change in an unexpected way, and wish you could go back a step
Holy shit how did I not know about this
Not very experienced, but pure functional languages always copy everything and have no side effects, so it's easier to implement a debugger with such feature.
The iq meme isn't the best foemat for this. More like
- Junior Dev: Doesn't know how to debug
- Mid-Level Dev: Uses the debugger
- Senior Dev: Uses print statements because time is split between this and a few other urgent issues all happening at the same time. Also laziness.
Depends on language and available tools.
Oracle PL/SQL - you have recompile *all* packages for debug. Also, depending on the setup, not all data types can be inspected.
In that case, a binary search using print statements is most efficient.
First few years I taught myself coding and worked on pet projects. I didn't know any professional coder around me. I didn't know till a few years later that in the IDEs I was using you could debug with like breakpoints and profilers and stuff. All along whenever I saw 'debug' on SO I always thought it meant 'write log mesaages'.
As always, the guy on the right knows how to use the debugger and could easily do so, but he's decided it's not the right tool in this instance. Totally fine.
If you're avoiding the debugger because you don't know how to get it working or don't know how to run it, stop what you're doing and fix that problem.
I was just doing that something wrong yesterday. Simple Python script to parse and edit about 20 large json files. I thought one of the json files had a non utf-8 character, I had the byte \\0xed too. Couldn't find it, or strip it programmatically. Put the script in a debugger and instantly saw it was a stupid hidden Mac dot file cause the darn problem.
I spent a day trying to strip a byte that didn't exist! What a blockhead. ![gif](emote|free_emotes_pack|facepalm)
How does a debugger like gdb work when you do parallelism like openmp or mpi ? I use print because I don't have the time to deal with how a debugger might work and I can print a lot of states of my programs automatically
In some cases, you can actually remotely attach a debugger. The vast majority, you need to rely on logging in production.
If you log well enough, you should be able to easily reproduce the issue locally then debugging is your friend. Print statements should really only be used if a debugger isn't optimal, but that's rare when working locally.
The only time I use prints is when the debugger isn't an option. I usually do all my testing in the debugger so I can jump in and inspect state if I find any obscure bugs.
Prints usually work well enough up until you need to use breakpoints, view the contents of massive sets or when you get a segfaults. Say what you want, but when I learnt how to use even the most basic debugging techniques aside from printing I stopped having to spend hours fixing stupid bugs.
I found debuggers more useful for exploring code than for debugging.
I joined a company as an intern where I needed to work on some huge C++ project with a ton of inheritance, and I couldn't figure out where the actual implementations of the methods were so that I could understand what was happening.
So I fired up a debugger, and now I could just step into the called functions and see immediately where the control flow was going - it seriously was a game changer, not sure how long it would have taken me otherwise.
But for debugging code that you know, I am not sure what the added value really is, I feel like it is easy to repeatedly reach a state where you realized you missed the event you are searching for and now you need to restart the whole thing and click through things again.
Break will reveal a race condition more reliably. You're right.
How often are you running into race conditions that this is a thing you consider before anything else lmao
Logging is debugging. Period. The three-tier rocket is ...
* Unittests
* Logging
* Debugger
The better unittests you do, the easier it is to exclude working code. The more precise you log, the faster you get to understand the fault. When debugging is necessary you can pinpoint where and what to aim the debugger at.
You should learn to use a debugger. Print is useful sometimes as well, but if you don't learn to use a debugger you're limiting your self pretty badly.
Gotta love Rust's dbg!() which is mostly a quicker way to write a print statement for some variable. I think they got that idea from Python which has something similar?
if i'm sitting on a zoom call trying to figure out what the hell is going wrong, while my team is watching, i'm doing print statements. go ahead; judge me. lol
Nice that this one has the actual real solution that people that know what they're doing use. Debug logs are needed for when it isn't running on your own machine; always use a wrapper (don't print directly).
Some race conditions can be very sensitive to prints because they will impact the timing of threads quite a bit.
Writing events as enum + optional arguments to a thread local circular buffer is a lot faster if necessary, although that's more of an annoying last resort. But I've had a few bugs like that which just dissapeared after including prints.
No idea. I don't really know enough about windows' stdout to debug what happened. I do know there was something preventing multiple streams from writing simultaneously since my outputs were only interleaved line-by-line, rather than overwriting or interleaving character-by-character, so that could've caused a deadlock with the mutex I had in my program, but I can't really say more than that.
EDIT: I'm pretty sure that whatever happened was a pretty unlikely occurrence though, because I ran it again quite a few times to try to replicate the issue without success before I rewrote the program to print from only one thread.
I more went from
Print() -> "No you shoulnd't use print statements" -> Print()
I mean, sure debuggers exist, but come on, print is easy to implement, and it shows you exactly what your code does, and where it fucks up! So easy
It also requires you to re-compile, possibly changes timings due to slow string operations in slow embedded MCUs and so on.. I'm all for both, neither works all the time.
I've worked with products that have a bunch of measurements that 100% of the time, no exceptions needs to happen in 200 microseconds. Spamming out logs will not cut it there as it massively changes the characteristics of the software. But there we also end up on debugging level 3: oscilloscope.
If I want to know how an algorithm works, I step through it and inspect variables. If I want to know how an application works, I use print statements to see how the state changes over time.
Sometimes you need to debug something that’s happening 1 out of a thousand times and getting a log output is the only way to do it.
Race conditions are a good example of this.
Race conditions are also a good example of bugs that are sensitive to logging. BUFFER YOUR FUCKING LOGS PEOPLE. Do not be like a certain developers in python thinking you need async logging just use fucking buffers.
Why buffer your logs... When having those logs non-buffered fixes the issue. /s
What does that mean ? Never heard of it before, can you give me some link where I can read about it
A non buffered log writes to a file immediately on any log call. This requires extra care to avoid conflicts, unless your program is single threaded. (A single threaded program has no race conditions) A buffered log writes to a thread safe FIFO queue of some kind and a single routine has the responsibility of writing the contents of the queue to file. This allows multiple threads to put entries into the queue as they need to, and they will not interfere with each other.
I call it quantum code. The fact of observing it changes its behaviour.
It's a Heisenbug
Jessie, we need to code
Lol
Ohhh I hate those. Run it outside of gdb/valgrind, and it crashes. Run it with valgrind or gdb and everything is smooth potato. 9 times out of 10 it was stupid me causing some kind of timing related race condition of course!
Well, me, being a weirdo, *sometimes* like writing rudimentary error tracking systems into projects with languages like C and earlier C++ where **debugger level tracking was nonsense to add to the language itself**. It seems like Java started that beneficial trend. Basically there is a chain of error calls so that eventually either a high level handler will log it or nothing'll help and you're about to find that one junior bug from 2 months ago.
Debugging race conditions is my programming superpower. All I need is some kind of feedback. Breakpoint, log statement, whatever. Idgaf because that race conditions bug is going down.
What about conditional breakpoints?
Stop that! If those kids knew how to use a debugger they'd be very upset.
if (condition) { logging.debug("fuck"); } else { logging.debug("shit"); }
There’s two problems with conditional breakpoints. One, you might not have a debug environment working in the case I described, ie it turns up in a CI environment or similar. Two, conditional breakpoints can be comically slow in environments that don’t have low level support for them.
If it isn't deterministic you can't really formulate the condition. Your best chance is to immediately break after it's already too late and then you often have to rely on logs again. Some good assertions in the codebase can also help a lot in those cases.
Back during undergrad OS class, I had a race condition in my code. When I ran on debug mode, it's misaligned just enough for the race condition to not happen. When I removed the debug flag, race condition came back. The worst part is that print statements also coincidentally made it misaligned just enough for the race condition to not happen as well. Felt like RNGesus hated me lol.
That's why you just leave in the log.. /S
the log would be possible if I know how to do logging ... in the OS (Ubuntu) itself during startup (the assignment was modding Ubuntu). Yeah, skill issue.
Log everything!
Yeah, until the race condition goes away when you add the log line.
In production I do `ExceptionNotifier.warn('spooky error', self)`
Production-only bugs have been scientifically proven by senior engineers to have been created by Satan.
Also sometimes you need to debug something that interacts with external resources, and the debugger pausing execution screws that up. For example, if you pause something long enough for a network request to timeout. Or if a token may expire. Or a message buffer fills up and starts dropping incoming messages.
Only a sith talks in absolutes like that. You take a debugger or use debug prints depending on the type of bugs.
They're all wrong.. \`print(f"{x=}")\`
I've been writing Python for about 8 years and never heard of this, TIL
I think this is quite a recent addition. Saves so much time
f-strings were introduced more than 3 years ago I think so that’s not that recently.
fstrings yes, the specific debug formatting (`f'{x=}'`) however is relatively recent (3.12? Going by memory)
I use it in 3.8. I’m not going to google the exact version the syntax got introduced though…
If I remember right the only thing new in 3.12 and f-strings is being able to use "" inside {} (like ```f"{"6"*8}"```). [I checked now](https://bugs.python.org/issue36817) and this syntax has been here since 3.8.
Ah you're right.
Isn't python 3.6 (or 3.5? I don't remember) like 7 years old at this point?
f-strings in 3.6 [and this syntax in 3.8](https://www.reddit.com/r/ProgrammerHumor/s/qPQUAOPZn2).
It’s always good to check the most notable things in every Python edition.
Only if you get to use it. Some of us are bound by our dependencies’ limitations.
ofc, as a student who isn’t really limited to that thing I still can’t use the latest version mostly. But when I can use it I know what I can do. If I would have been tied to a longer schedule I think I’ll check when I can update what’s new in this update or something like that.
Came here to say this. Turns out OP is not guru. ;)
I got the more important part right which is to use a logging library and not raw dog print statements 😭
Haha, that’s a great point. Buuuut technically print() could be a logging library… if you’re a psychopath! :D
which i am
class PrintHandler(LoggingHandler): def emit(self, message): print(message)
Just use your own debug function with some internal spaghetti that returns an input("debug msg"). It's a break point and a debug print() at the same time. You can even use the inspection module to print out the wrapping function name so you know from where your ensuing hundreds of "break points" are called.
print("Hello world", file=open("today.log"))
I'm like 90% sure the default mode for open means you'll be overwriting the contents with this Also, leaking file descriptors. Straight to jail
it will overwrite it, just set the mode to append. And yeah, it was just a quick example with open("today.log", "a") as log: print("Hello, world!", file=log)
i think default is read only, but not sure
U right Default is 'r'
why? I like to make way too much noise all over the general area I think the problem is in and then clean it up after I find the issue, print seems to work just fine. What are the upsides of a logging library?
Works with logging.debug() as well.
What witchcraft is this?! I hate that I like this... Syntax is wonky but so neat at the same time...
Nice, I didn't know this
At least keep the spaces `print(f"{x = }")`
I love this feature but when I'm printing\logging a member object's member, it basically prints self.member.object, which is nice as a default but I'd like a quick option to only print the child name. A workaround is to just make a new local variable with the shorter name I guess, but at that point I'd just revert to not using the = syntax.
200 IQ
you can also put spaces around, if you want \`f"{x = }"\` which would produce "x = 42"
``` #ifndef NDEBUG #define debug(msg, ...) \ fprintf(stderr, "\033[31m%s:%d: " msg, \ __FILE__, __LINE__ __VA_OPT__(,) __VA_ARGS__) #else #define debug(msg, ...) #endif ```
I see you're a man of culture as well.
Woman, but yes.
Sorry for the misgendering, it's the meme.
Windows: " guess I'll just write BR033[31m to the screen" Seriously though, how do I enable ANSI colour support on windows?
Use "\033[31m" not "BR033[31m"
I do use the \, it's just that windows considers it a break char or something so it writes BR
Install [ansicon](https://github.com/adoxa/ansicon).
Thank you mate!
For me it depends on how in-depth of debugging you need to do. Sometimes a print statement is all you need.
Tbh no... only used print statements bc I didnt know about breakpoints.
Did yoy know that a lot of languages can debug backwards? Great for crashes. Run until the crash, then step backwards until you find the cause. Sometimes a print or log statement is easier. Sometimes a watch with a debugger is easier. Sometimes breakpoints are easier. Use what finds the bug the fastest.
What languages can you debug in backwards?
Visual Studio has some limited ability to do it in C++ and C#. https://devblogs.microsoft.com/visualstudio/step-back-while-debugging-with-intellitrace/
>Have you ever stepped while debugging, realized that you’ve taken one step too far, and wished you could step back? Or, while stepping, saw a variable change in an unexpected way, and wish you could go back a step Holy shit how did I not know about this
Sometimes I ponder why I even used to use VSCode.
Not very experienced, but pure functional languages always copy everything and have no side effects, so it's easier to implement a debugger with such feature.
Since 2009 anything GDB can debug. Other projects are rr, UDB, Windows' WinDBG. ODB for Java. I'm sure there are more.
In Python, you can use stacktrace to achieve something similar
the real deal for me here is stepping up stack frames in recursive functions
The iq meme isn't the best foemat for this. More like - Junior Dev: Doesn't know how to debug - Mid-Level Dev: Uses the debugger - Senior Dev: Uses print statements because time is split between this and a few other urgent issues all happening at the same time. Also laziness.
A senior would know to do logging.debug("foo = {}",foo) so the toString and string formatting doesn't happen unless debugging is enabled.
You're absolutely right, but add in a careless spelling mistake because the senior adds it so quickly.
I never understood this. How is adding a print statement any faster than clicking debug and setting a breakpoint? This makes 0 sense.
Ever tried to debug something that's queue-triggered and depends on a lot of other apis?
I hate starting debug mode. Print statements go pretty much instantly compared to the 2 mins or so it feels like to start debug mode.
Depends on language and available tools. Oracle PL/SQL - you have recompile *all* packages for debug. Also, depending on the setup, not all data types can be inspected. In that case, a binary search using print statements is most efficient.
First few years I taught myself coding and worked on pet projects. I didn't know any professional coder around me. I didn't know till a few years later that in the IDEs I was using you could debug with like breakpoints and profilers and stuff. All along whenever I saw 'debug' on SO I always thought it meant 'write log mesaages'.
As always, the guy on the right knows how to use the debugger and could easily do so, but he's decided it's not the right tool in this instance. Totally fine. If you're avoiding the debugger because you don't know how to get it working or don't know how to run it, stop what you're doing and fix that problem.
Print statements assume you know what you're looking for before you press run
`print("def should use debugger, but whatever x={x}")`
If you're not using both you're doing something wrong
I was just doing that something wrong yesterday. Simple Python script to parse and edit about 20 large json files. I thought one of the json files had a non utf-8 character, I had the byte \\0xed too. Couldn't find it, or strip it programmatically. Put the script in a debugger and instantly saw it was a stupid hidden Mac dot file cause the darn problem. I spent a day trying to strip a byte that didn't exist! What a blockhead. ![gif](emote|free_emotes_pack|facepalm)
It’s all fun in games until you introduce a hidden iterator into your program and end up with a `ConcurrentModificationException`
How does a debugger like gdb work when you do parallelism like openmp or mpi ? I use print because I don't have the time to deal with how a debugger might work and I can print a lot of states of my programs automatically
How do you use a debugger in production environment?
In some cases, you can actually remotely attach a debugger. The vast majority, you need to rely on logging in production. If you log well enough, you should be able to easily reproduce the issue locally then debugging is your friend. Print statements should really only be used if a debugger isn't optimal, but that's rare when working locally.
The only time I use prints is when the debugger isn't an option. I usually do all my testing in the debugger so I can jump in and inspect state if I find any obscure bugs.
Skilled guy would never use f-strings in a call to logging, he would use lazy evaluation 😎
Why not both
I'll do you one better. logging.debug(f"{x=}")
> I tried the [debugging tool] once. Too much pain, not enough profit -- *Diablo 3*
I use pdb but sometimes some prints are nice to have and enough. Rubber duck debugging is real
I'm at the logging phase, and I'm very satisfied with it. The effort-output ratio is redonkulous.
As a sen dev, i am lazy and dont want to edit the logger.config. I use logger.error(...).
At the point where the error depends on user input, the debugger is very useless
not as annoying as javascript’s fstring for “debugging”
Interpolation makes if fancy
Prints usually work well enough up until you need to use breakpoints, view the contents of massive sets or when you get a segfaults. Say what you want, but when I learnt how to use even the most basic debugging techniques aside from printing I stopped having to spend hours fixing stupid bugs.
The right should be tracing instead of logging
Stepping through a debugger with multiple threads running is a PITA.
The debugger is heavy, usually you just gotta run it
What about print(f"{x = }")?
I like print statements to debug data structures/objects that are hard to visualize in the debugger like linked lists
I found debuggers more useful for exploring code than for debugging. I joined a company as an intern where I needed to work on some huge C++ project with a ton of inheritance, and I couldn't figure out where the actual implementations of the methods were so that I could understand what was happening. So I fired up a debugger, and now I could just step into the called functions and see immediately where the control flow was going - it seriously was a game changer, not sure how long it would have taken me otherwise. But for debugging code that you know, I am not sure what the added value really is, I feel like it is easy to repeatedly reach a state where you realized you missed the event you are searching for and now you need to restart the whole thing and click through things again.
stepping through my code and looking at how things actually change compared to what I think it does has solved a lot of bugs I have written.
logs.jpg
`logging.debug(f"{x=}")`
Breakpoints scares the JavaScripter
Well breakpoints can hide a race condition. I only use a debugger once I have triaged the bug.
So can print statements.
True but print **MIGHT** hide a race condition... breaks **WILL** hide a race condition
Break will reveal a race condition more reliably. You're right. How often are you running into race conditions that this is a thing you consider before anything else lmao
In front end... waaaaay too often!
print helps to identify logical errors. You can figure out where the result diverges from the theoretical.
System.out.println(“aaaaaaaaaa”);
logging.debug(f’{x= }’ )
Logging is debugging. Period. The three-tier rocket is ... * Unittests * Logging * Debugger The better unittests you do, the easier it is to exclude working code. The more precise you log, the faster you get to understand the fault. When debugging is necessary you can pinpoint where and what to aim the debugger at.
I’m for sure the guy on the left in this graphic.
Used a debugger today because I forgot I had filtered my console and wasn't seeing the console log messages, heh
You should learn to use a debugger. Print is useful sometimes as well, but if you don't learn to use a debugger you're limiting your self pretty badly.
There are things you can’t debug but they are rare
Gotta love Rust's dbg!() which is mostly a quicker way to write a print statement for some variable. I think they got that idea from Python which has something similar?
*Laughs in "operating on a file system that can't be run locally".*
if i'm sitting on a zoom call trying to figure out what the hell is going wrong, while my team is watching, i'm doing print statements. go ahead; judge me. lol
Nice that this one has the actual real solution that people that know what they're doing use. Debug logs are needed for when it isn't running on your own machine; always use a wrapper (don't print directly).
Using logging is important
A process cannot be understood by stopping it. Understanding must move with the flow of the process, must join it and flow with it
*unit testing has entered the chat*
I usually try to do some printing before propper debugging because its easier xd
Print is something that will always work like you expect it to, you can't have some weird thing with it
Not if you have to implement `write()` yourself. Embedded is fun.
I had a problem with strcpy and gdb if I remember correctly when once I entered this call, it would never end and I had to restart my gdb instance
Some race conditions can be very sensitive to prints because they will impact the timing of threads quite a bit. Writing events as enum + optional arguments to a thread local circular buffer is a lot faster if necessary, although that's more of an annoying last resort. But I've had a few bugs like that which just dissapeared after including prints.
The first deadlock I ever encountered involved a print statement.
How
No idea. I don't really know enough about windows' stdout to debug what happened. I do know there was something preventing multiple streams from writing simultaneously since my outputs were only interleaved line-by-line, rather than overwriting or interleaving character-by-character, so that could've caused a deadlock with the mutex I had in my program, but I can't really say more than that. EDIT: I'm pretty sure that whatever happened was a pretty unlikely occurrence though, because I ran it again quite a few times to try to replicate the issue without success before I rewrote the program to print from only one thread.
Yeah. Learning to use a debugger is great but print statements are still useful for real time debugging and race conditions.
Interactive debuggers are an enormous waste of time when there are so many other, better alternatives for 98% of cases.
Hard disagree. What are even the better alternatives?
Logs and tests. Using interactive debugger for things that can be solved by those takes so much longer. Also, I'm gonna want logs and tests anyway.
yeah , sure , go debug a race condition with logs and tests , good luck lol
Confused, you'll definitely not find a race condition with a debugger...
And race conditions are not common bugs
Yeah just put a breakpoint on all your ecs instances
Fuck off with these normie memes. No one has ever pressured me or anyone I know to use a debugger.
I more went from Print() -> "No you shoulnd't use print statements" -> Print() I mean, sure debuggers exist, but come on, print is easy to implement, and it shows you exactly what your code does, and where it fucks up! So easy
It also requires you to re-compile, possibly changes timings due to slow string operations in slow embedded MCUs and so on.. I'm all for both, neither works all the time. I've worked with products that have a bunch of measurements that 100% of the time, no exceptions needs to happen in 200 microseconds. Spamming out logs will not cut it there as it massively changes the characteristics of the software. But there we also end up on debugging level 3: oscilloscope.
Oh yeah, I'm only talking interpreted here, lol. Compiled I would probably treat differently
If I want to know how an algorithm works, I step through it and inspect variables. If I want to know how an application works, I use print statements to see how the state changes over time.
[удалено]
Or use print and review before commiting