Live data from Hacker News

The Grug Brained Developer (2022)

grugbrain.dev

571–580 of 603 posts

Re: The Grug Brained Developer (2022)

#571

Earlier quoted context omitted.

> It's absolutely not an anti-pattern if you have appropriate tools to handle different levels of logging, and especially not if you can filter debug output by area. It is an anti-pattern due to what was originally espoused: I add logging code, that stays forever. For a major interface, I'll usually start with INFO level debugging, to document function entry/exit, with param values. There is no value for logging "fun…

> There is no value for logging "function entry/exit, with param values" when all collaborations succeed and the system operates as intended. Well, I agree completely, but those conditions are a tall order. The whole point of debugging (by whatever means you prefer) is for those situations in which things don't succeed or operate as intended. If I have a failure, and suspect a major subsystem, I sure do want to see a…

>> There is no value for logging "function entry/exit, with param values" when all collaborations succeed and the system operates as intended.

> Well, I agree completely, but those conditions are a tall order.

Every successful service invocation satisfies "all collaborations succeed and the system operates as intended." Another way to state this is every HTTP `1xx`, `2xx`, and `3xx` response code produced by an HTTP service qualifies as such.

> The whole point of debugging (by whatever means you prefer) is for those situations in which things don't succeed or operate as intended.

Providing sufficient context in the presence of errors, or "situations in which things don't succeed or operate as intended", was addressed thusly:

  If detailed method invocation history is a requirement, 
  consider using the Writer Monad and only emitting log 
  entries when either an error is detected or in an 
  "unconditionally emit trace logs" environment (such as 
  local unit/integration tests).
> If I have a failure, and suspect a major subsystem, I sure do want to see all calls and param values leading up to a failure.

See above.

> In addition to this point, you have constructed a strawman in which logging is on all the time.

No, I addressed your original premise in the context of a production web application, where logging is configured during deployment.

See also your own contradiction by previously asserting, "I sure do want to see all calls and param values leading up to a failure."

So which is it?

Did I construct a strawman "in which logging is on all the time"?

Or do you "want to see all calls and param values leading up to a failure", which requires "logging is on all the time"?

> Have you ever looked at syslog?

This is a strawman. Syslog is a component for logging and has nothing to do with the programs which use it.

> The large distributed system I worked on would produce a few GB per day, and the logs were rotated. A complete non-issue.

If this is the same system you described in a different comment also in this thread, I identified a standard industry practice of log entries produced by application nodes in a production environment being unconditionally sent to a log aggregator and not stored in a local file system. The reasons for this are well documented.

Re: The Grug Brained Developer (2022)

#572
post #208

Earlier quoted context omitted.

There was a good discussion on this topic years ago [0]. The top comment shares this quote from Brian Kernighan and Rob Pike, neither of whom I'd call a young grug: > As personal choice, we tend not to use debuggers beyond getting a stack trace or the value of a variable or two. One reason is that it is easy to get lost in details of complicated data structures and control flow; we find stepping through a program les…

On the other hand, John Carmack loves debuggers - he talks about the importance of knowing your debugging tools and using them to step through a complex system in his interview with Lex Friedman. I think it's fair to say that there's some nuance to the conversation. My guess is that: - Debuggers are most useful when you have a very poor understanding of the problem domain. Maybe you just joined a new company or are e…

The thing about print statement debugging is that it's trivial to replicate in a debugger - just put break points in those few areas where you're curious. It's a tiny bit faster than writing the print statements.

Re: The Grug Brained Developer (2022)

#573

Earlier quoted context omitted.

> ... I disagree with two things: the assumption of incompetence on the part of geophile to not make logging conditional in some way ... I assumed nothing of the sort. What I did was identify an anti-pattern and describe an alternative which experience has shown to be a better approach. "Incompetence" is your word, not mine. > ... and adding the label of "anti-pattern" to something that's evidently got so much nuance…

BTW, your username is a bit too on-the-nose, given the way you are arguing, using "anti-pattern" as a way to end all discussion.

> BTW, your username is a bit too on-the-nose ...

Resorting to an ad hominem and non sequiturs are we? Really?

C'mon, you are better than that.

Re: The Grug Brained Developer (2022)

#574

While I agree that complexity is bad the fact that we don't really have a shared understanding of what complexity is doesn't help. At worst, it can be just another synonym for "bad" that passes through the mental firewall without detection. For instance is having multiple files in a project "complex"? If I am unfamiliar with a codebase is it "complex" and I therefore have to re-write it?

I think you hit the nail on the head. This article is definitely biased against modern front-end development for example and recommends HTMX as less "complex", but from what I've seen, using HTMX just trades one form of complexity for another. This part: > back end better more boring because all bad ideas have tried at this point maybe (still retry some!) I entered a Spring Boot codebase recently, and it was anything…

The main thing with modern web applications is that everyone wants to move complexity away from the backend into the front end. The problem with this is that nobody asks if it can be done, they just start doing it. The result is that you still end up with a complex backend, but now you also have a monstrous front end. And now you need to reconcile state between two different places - good luck! That problem right there - reconciling state from different places - is one of the hardest ones in software engineering.

Re: The Grug Brained Developer (2022)

#575

Earlier quoted context omitted.

> A point that may be pedantic: I don't add (and then remove) "print" statements. I add logging code, that stays forever. For a major interface, I'll usually start with INFO level debugging, to document function entry/exit, with param values. This is an anti-pattern which results in voluminous log "noise" when the system operates as expected. To the degree that I have personally seen gigabytes per day produced by emp…

I don't quite like littering the code with logs, but I understand there's a value to it. The problem is that if you only log problems or "important" things, then you have a selection bias in the log and don't have a reference of how the log looks like when the system operates normally. This is useful when you encounter unknown problem and need to find unusual stuff in the logs. This unusual stuff is not always an err…

> The problem is that if you only log problems or "important" things, then you have a selection bias in the log and don't have a reference of how the log looks like when the system operates normally.

A case can be made for only logging the steps performed up to and including an error. This even excludes logging "important things" other than those satisfying system/functional requirements (such as request/response audit logs).

It is reminiscent of "the Unix philosophy", but different in important ways, and is essentially:

  Capture what would be log entries if a there is a
  future unrecoverable error.

  If an error is encountered, emit *all* log entries starting
  from the earliest point (such as receiving an external
  event or a REST endpoint request) up to and including the
  information detailing the unrecoverable error.

  If the workflow succeeds, including producing an expected
  failed workflow response (such as a validation error),
  discard the deferred log entries.
What constitutes the deferred log entries accumulated along the way is specific to the workflow and/or domain model.

While using a functional programming language and employing referentially transparent[0] abstractions (such as the Writer Monad) usually makes implementing this pattern much simpler than when using an imperative language, it can be successfully done with the latter given sufficient discipline and the workflow implementation being referentially transparent[0].

An important complement to the above is to employ other industry standard verification activities, such as unit/feature/integration tests.

0 - https://en.wikipedia.org/wiki/Referential_transparency

Re: The Grug Brained Developer (2022)

#576
post #424
post #208

Earlier quoted context omitted.

On the other hand, John Carmack loves debuggers - he talks about the importance of knowing your debugging tools and using them to step through a complex system in his interview with Lex Friedman. I think it's fair to say that there's some nuance to the conversation. My guess is that: - Debuggers are most useful when you have a very poor understanding of the problem domain. Maybe you just joined a new company or are e…

I still don't understand how, with a properly configured debugger, manually typing print statements is better than clicking a breakpoint at the spot you were going to print. Context overload might be an issue, but just add a 'watch' to the things you care about and focus there.

while inspecting some code inside loop, i prefer to put print and see all iterations at once in my screen, instead of countless clicking "continue" in debugger.

Re: The Grug Brained Developer (2022)

#577

Earlier quoted context omitted.

I think mostly this is to brake down the system between teams. This is easier to manage this way. Nothing to do with technical decision - more the way of development. What is the alternative? Mono-repo? IMHO it is even worse.

microservices and mono repo are not mutually exclusive. Monolith, is. Important distinction imo, Micro services in mono repo definitely works and ime is >>> multi repo. Of course the best is mono repo and monolith :3

I did not stated that they can be used together. I just meant that they are mainly, for me, work as a tool to allow multiple teams work on a single big project. So the tool is more for work organisation purpose not for architectural one.

If you prefer working on mono repo it s fine though I think micro services are more popular one now.

Re: The Grug Brained Developer (2022)

#578

Earlier quoted context omitted.

You are very attached to this "voluminous" point. What do you mean by it? As I said, responding to another comment of yours, a distributed system I worked on produced a few GB a day. The logs were rotated daily. They were never transmitted anywhere, during normal operation. When things go wrong, sure, we look at them, and generate even more logging. But that was rare. I cannot stress enough how much of a non-issue lo…

> You are very attached to this "voluminous" point. What do you mean by it? I mean "a lot" or more specifically; "a whole lot." Here is an exercise which illustrates this. For the purposes here, assume ASCII characters are used for log entries to make the math a bit easier. Suppose the following: Each log statement is 100 characters. Each service invocation emits 50 log statements. Average transactions per second dur…

7.2G/day doesn't sound terrible. And I'd reduce it by a factor of 25, since in normal operation (i.e., not looking into a problem) I would have either 2 log statements per call (entry, exit), or none at all. It might be more than 2, if I needed detailed logging.

But in normal usage, even in the scenario you describe your argument about log volume is not convincing.

Re: The Grug Brained Developer (2022)

#579
post #465

“Good debugger worth weight in shiny rocks, in fact also more” I’ve spent time at small startups and on “elite” big tech teams, and I’m usually the only one on my team using a debugger. Almost everyone in the real world (at least in web tech) seems to do print statement debugging. I have tried and failed to get others interested in using my workflow. I generally agree that it’s the best way to start understanding a s…

Here is my circular argument against debuggers: if I learn to use a debugger, I will spend much, possibly most, of my time debugging. I'd rather learn how to write useful programs that don't have bugs. Most people believe this is impossible. The trouble of course is that there is always money to be made debugging. There is almost no incentive in industry to truly eliminate bugs and, indeed, I would argue that the inc…

So you think that not knowing how to operate a debugger will exempt your code from having bugs, or you from having to debug them?

Re: The Grug Brained Developer (2022)

#580

Earlier quoted context omitted.

> There is no value for logging "function entry/exit, with param values" when all collaborations succeed and the system operates as intended. Well, I agree completely, but those conditions are a tall order. The whole point of debugging (by whatever means you prefer) is for those situations in which things don't succeed or operate as intended. If I have a failure, and suspect a major subsystem, I sure do want to see a…

>> There is no value for logging "function entry/exit, with param values" when all collaborations succeed and the system operates as intended. > Well, I agree completely, but those conditions are a tall order. Every successful service invocation satisfies "all collaborations succeed and the system operates as intended." Another way to state this is every HTTP `1xx`, `2xx`, and `3xx` response code produced by an HTTP…

I'm not sure what point you are making with your scenario involving HTTP response codes. What if the HTTP server crashes, and doesn't send a response at all?

I don't know from Writer Monads. But if you only emitting log entries on some future failure or request, then that's potentially a lot of logging to keep somewhere. Where? Log aggregator? Local files? Memory? What about log volume? Does this writer monad implement log rotation? It sounds like you are sweeping a lot of the things you object to under this writer monad rug.

Let me be real clear about all calls and param values leading up to a failure.

- In normal operation, turn logging off completely, or turn on some level that produces tolerable log volume, (it seems like your threshold is much lower than mine).

- When a failure occurs: Restart the service with more logging enabled, (hence the all calls an param values), so that you have logging when the failure occurs again.

About local logs vs a log aggregator: The system I worked on was a shared nothing archive. To add storage and metadata capacity, you add nodes. Each node also stored its own log files. I get that this may not be the answer all the time, and that a log aggregator is useful in some scenarios. However, even in that case, your concerns about log volume seem overblown to me.

Post reply on HN