Plan B: Lake Max-Eyth in Stuttgart. On the way we encountered plenty of other blocked off raods from the bicycle race and one particular traffic light let only four cars pass at most. It took us 15 minutes alone on that crossing. Then all the myriads of road works, man. It once again proofed that only insane people go to Stuttgart by car. Two bloody hours later at the destination the green-blue algea put its spoke in our wheels. Definitely avoid skin contact with that water. Downwind it smelled horribly.
So then for plan C we hiked a little bit down the riverside (the lake is next to the river) to find a shady place where we could picknick. We finally found a spot among a tree and spent some nice hours.
Yeah, super preparation on our end. But who would think of a bicycle race in the first place?
Today was supposed to rain the whole day, but not a single drop up to this point. Maybe in an hour the weather front will be here. Hopefully!

@prologic The wording is a bit weird: "The James Webb Space Telescope does not send its data as complete pictures but rather column of numbers representing brightnesss values." Now we're wondering what the authors thought how images are transmitted in general. (Or what the uncited source actually meant.)

Luckily, there are still a few channels out there who are not aggressively promoting this shit. They are rare, but they exist. I either skip forward, stop the video or just don't watch these videos anymore if it gets too overboard.

Not sure what's the deal with the red "sold" label on that tiny tree in the forest.
Who spots the frog?
For my needs a central system with the obove stated requirements would completely do it.
Bwahahaahaaahaaaaa, this is great! :-D
feh
, but since macros still need an additional keystroke, I quickly fell back to just o
or 1
or whatever the respective link number is. I read somewhere™ that some terminals might be able to render images, but I never tried it. Need to look into that some day.
* Ocdtrekkie's home and car automation
* Prologic wanted to try some Go Doom clone or something like that
* Fixing darch's
Bad Request
in the conversation view by removing superfluous csrf_token
cookies other than for /
, refactoring plans of CSRF handling in yarnd* How people getting scammed in all sorts of different ways
* Pronouncing Twtxt
* Following YouTube channels
* Subscribing to RSS and Atom feeds with Newsboat, Tiny Tiny RSS and yarnd
* And probably a lot more
All these hot temperatures for weeks made the 20°C today feel quite cold. After lunch I had to wear a jumper, cool air coming in was too much for only a t-shirt when sitting still at the desk. But walking this evening was very lovely. Absolutely perfect in a t-shirt. We thought we will encounter some more rain on our way, so we opted for long trousers. Yet, it remained dry, so we both regretted our choice quickly. The humidity of at least 100% was very tough. However, no comparison to temperatures of last week and the one before.

Noone else was outside, we had everything for us. Met exactly six people in total in those two and quarter hours. In general this was a very silent trip. No birds singing, no traffic on the one road for several minutes. Heard just a bunch of sheep and cows in the distance. Quite weird, but enjoyable for sure.
¹ Last time I checked: "We value your privacy, accept all cookies" No you do not, fuck off.
I reckon two
return
s can be saved in GetUser(…)
. Oh, on further inspection there are even two nested err != nil
checks.Generics were desperately needed. I'm glad they finally introduced them. I stumbled across them last week and gave them a shot. The syntax is probably not the very best, but I will get used to it eventually.

Comet is also not too shabby. ;-)
And now I nearly missed adding the screenshot to this twt! Good thing I proofread it three times.

Just before going to bed yesterday I went outside to take a quick last look at Ursa Major. I wasn't even even standing five seconds there and I saw a meteor for barly half a second. Truly amazing!
Just before going to bed yesterday I went outside to take a quick last look at Ursa Major. I wasn't even even standing five seconds there and I saw a meteor for barly half a second. Truly amazing!
KDE 3.5 had the very best KMail versions ever. Very stable, no bugs I encountered (although the bug tracker was full of bug reports, too). With 4 and 5 lots of little issues got introduced that haven't been there before and plenty are still unresolved today. I sent a couple of bug reports for KDE software, but never got any reactions. Once, six or seven years later a dude came back and asked whether a particular bug had been fixed in the meantime. By then I had long migrated off that program.
With KDE 5 I have to fake
XDG_CURRENT_DESKTOP=KDE
or else with an i3
value, icons are not found in KDE programs anymore. Yeah. Also KMail's message text pane does not have any borders around the header part when I start KMail (left). Opening the settings and closing the dialog with OK without changing anything fixes it. It then decorates the headers properly (right). No idea what's going on there.
Also gave Thunderbird a shot a couple of times, but it never worked out for me. One major issue was the broken rendering of quotes when composing I think. And also a bunch of other things I don't remember anymore.
@movq Absolutely, HTML mails are an invention straight from hell! I even only send plain text mails at work as the only guy.
QTWEBENGINE_CHROMIUM_FLAGS="--single-process" kmail
surpringly works… O_o WTF. This goes in the /usr/local/bin/kmail wrapper script then.
org.kde.pim.webengineviewer: WebEngine render process crashed
being printed to stdout.https://bugreports.qt.io/browse/QTBUG-73293 Closed as invalid.
https://bugs.archlinux.org/task/61534 suggests to
QTWEBENGINE_CHROMIUM_FLAGS="--enable-logging --v=3" kmail
, unfortunately, nothing useful shows up:
[32957:1:0813/153712.828577:VERBOSE1:sandbox_linux.cc(69)] Activated seccomp-bpf sandbox for process type: renderer.
[32491:32555:0813/153712.854714:VERBOSE1:gles2_cmd_decoder.cc(3850)] GL_EXT_packed_depth_stencil supported.
org.kde.pim.webengineviewer: WebEngine render process crashed
Why is there not a single decent e-mail program out there? Anybody using only mutt?
Unwrap()
, Is(…)
and As(…)
is sooooooo much work. Unnecessary work, there must be a better way. Sleeping on this twice, the main issue is probably not carefully thinking about the errors in my APIs. Which kind of errors should be distinguishable by the caller. Does it even make sense to differentiate between them? Can the caller react differently depending on what went wrong? This also depends on the caller, of course. In my combinedlog.parseLine(…)
example it's basically stupid. One generic error is enough.Logging only a single line is often very useful. But apart from access logs in web servers I can't remember seen this implemented anywhere in the wild.
The fundamental error was to enable people making tabs arbitrarily wide. :-)
%w
at the front of the message and not at the end and get exactly what I want: fmt.Errorf("%w '%s'", ErrInvalidSentBytes, sentBytes)
results in "invalid sent bytes '4385743057573509732574375098741128354092547569201274123'" and can be error.Is(err, ErrInvalidSentBytes
-asserted. No idea why I did not think of that. O_o Thanks mate! :-)
The technical details to only produce one log per request were sorted out fairly quickly with a customer logger, that just replaces the last message with the newly logged one and finally at response end actually logs it. When a Java component was completely rewritten in Go they tried it out and I was very surprised that it worked that well for the analysis. I basically never missed any other surrounding logs that would have been produced in the old log flooding style. Over time a few things such as structured context fields were added that turned out to be useful to have for error analysis. It's been a couple of years, but I think we rewrote that logger a bunch of times to optimize even further and try out new API ideas we had.
I remember it as a surprisingly successful experiment. In my current project I also once tried to tell my work mates about that, but – just like me when I heard about it in the first month – they weren't ready for it. :-) To be fair, we have a slightly different situation now than in the other project.
errors.As(…)
just doesn't feel natural. errors.Is(…)
only just. I mainly avoided it. Yesterday evening I actually researched a bit about that and found this article on errors with Go 1.13. It shed a little bit of light, but I still have a long way to go, I reckon.We tried several things but haven't found the holy grail. Currently, we have a mix of different styles, but nothing feels really right. And having plenty of different approaches also doesn't help, that's right. I agree, error messages often end up getting wrapped way too much with useless information. We haven't found a solution yet. We just noticed that it kind of depends on the exact circumstances, sometimes the caller should add more information, sometimes it's better if the callee already includes what it was supposed to do.
To experiment and get a feel for yesterday's research results I tried myself on the combined log parser and how to signal three different errors. I'm not happy with it. Any feedback is highly appreciated. The idea is to let the caller check (not implemented yet) whether a specific error occurred. That means I have to define some dedicated errors upfront (
ErrInvalidFormat
, ErrInvalidStatusCode
, ErrInvalidSentBytes
) that can be used in the err == ErrInvalidFormat
or probably more correct errors.Is(err, ErrInvalidFormat)
check at the caller.All three errors define separate error categories and are created using
errors.New(…)
. But for the invalid status code and invalid sent bytes cases I want to include more detail, the actual invalid number that is. Since these errors are already predefined, I cannot add this dynamic information to them. So I would need to wrap them à la fmt.Errorf("invalid sent bytes '%s': %w", sentBytes, ErrInvalidSentBytes")
. Yet, the ErrInvalidSentBytes
is wrapped and can be asserted later on using errors.Is(err, ErrInvalidSentBytes)
, but the big problem is that the message is repeated. I don't want that!Having a Python and Java background, exception hierarchies are a well understood concept I'm trying to use here. While typing this long message it occurs to me that this is probably the issue here. Anyways, I thought, I just create a
ParseError
type, that can hold a custom message and some causing error (one of the three ErrInvalid*
above). The custom message is then returned at `Error()` and the wrapped cause will be matched in `Is(…)`. I then just return a ParseError{fmt.Sprintf("invalid sent bytes '%s'", sentBytes), ErrInvalidSentBytes}
, but that looks super weird.I probably need to scrap the "parent error"
ParseError
and make all three "suberrors" three dedicated error types implementing Error() string
methods where I create a useful error messages. Then the caller probably could just errors.Is(err, InvalidSentBytesError{})
. But creating an instance of the InvalidSentBytesError
type only to check for such an error category just does feel wrong to me. However, it might be the way to do this. I don't know. To be tried. Opinions, anyone? Implementing a whole new type is some effort, that I want to avoid.Alternatively just one
ParseError
containing an error kind enumeration for InvalidFormat
and friends could be used. Also seen that pattern before. But that would then require the much more verbose var parseError ParseError; if errors.As(err, &parseError) && parseError.Kind == InvalidSentBytes { … }
or something like that. Far from elegant in my eyes.
Although there are a bunch of Ukrainian license plates around here, I never wondered why I actually could read all of them without issues. Nice trick to just limit the Cyrillic script to the ones that look like Latin letters.
Also the bad switch dropping a byte every now and then and this way producing Chinese characters was really fun. Good to know, it would have never occurred to me. Not in a hundred years.
I'm sure there are many more things I learned and already forgot again. :-)

We saw a super nice, large, orange moon raising over the horizon. But my camera couldn't pick it up.
time.RFC3339
or time.RFC3339Nano
constants and don't worry about it.Maybe the positive effect is that you're forced to always go to the docs to look everything up when writing the special time pattern, because there's no chance of remembering anything at all (maybe except the year 2006). With the letter system you might think you know what you do and then skip that check in the docs and finally fail because it was the other way around again. If the Go maintainers wanted to prevent that, then they actually succeeded.
It really depends on the ecosystem you're in. The lower date and upper time rule e.g. doesn't work for Java:
yyyy-MM-dd'T'HH:mm:ssSSSXXX
(not sure on the exact number of X
s though).
No doubt, writing good error messages is an art in itself and often takes a minute or two (or even more) to come up with something short and still precise. But in the end it will always pay off to provide some quality message. Same with logging in general, of course. But errors returned to somebody else are more important than internal logs.
In a previous commercial software project the customer wanted to have a complete catalog of all info log messages and above. An additional description with more context had to be provided what that log ID and message meant. I think with warning level and above both a solution and verification was required on how to fix it and then validate that it actually worked. Error and fatal included even more stuff I can't remember anymore.
For us developers that was incredibly annoying, but when we then finally also had to operate that software, this was absolutely awesome to have! Man, did I suddenly understand what all this effort was for. It immediately paid off. There was one guy inhouse just analyzing logs from our different systems all day long and trying to categorize and correlate things. Even with the log message catalog he often had some detail questions to use developers. Can't imagine what would have happend without that catalog.
That experience was truely an eye-opener for me. I can also see it with my current work mates. Only if you had been forced to analyze yourself with nothing else but the logs what was going on or went wrong, you will appreciate and also write good messages yourself. If you haven't been in that situation before, there's basically no way you'll be in a position to write decent logs. And even then you realize that important context is missing when you have to analyze something. :-)
I'm on the fence with testing log entries. In a previous project we quite often did. But there were also hard requirements to produce certain logs, so then it made sense. Usually I don't unless there are some weird circumstances. Can't think of any such situation off the top of my head right now, though.
Just a few weeks back I had basically the same idea with inventing a more generic mock implementation for our storage layer at work. Previously, we had tons of new test storage types each implementing another hardcoded behavior based on the exact input. For a start that works well and is incredibly easy, but over time it quickly becomes unmaintainable and also reading the tests is extremely hard. Why is that weird value used as an argument over here? Quite some time later one realizes: Oh, right, it will then trigger that and that.
So my approach basically boils down to the exact same thing Jessica does. To be able to set a mock function in the mocked object that will then do whatever is needed. Setting up more involved tests is now concise and readable. It's still not perfect, but a large improvement even so. My implementation goes a bit further than Jessica's and falls back to the real functionality, if not overridden explicitly. This has the advantage to just throw together a bunch of tests without mocking *everything*, since there are often a lot of steps needed to build the actual scenario.
In Kraftwerk v2 I extended the mock storage to be able to be initialized even more easily with this automatic
init()
. At work where this mock.Storage
type *inherits* (and not just contains a) memory.Storage
forces us to also explicitly create a memory storage for each and every mock.Storage{Storage: memory.NewStorage(…), …}
. One day, if I have some time, I'll refactor the day-job code and apply this simplification, too. Ideally, Go would allow me to write some constructor thingy where I could set up and propagate initial data to the backing memory implementation. Then there's no chance of forgetting a call to the s.init()
in a new function. But that's the best I've come up with so far. I just want to make it as easy as possible to write tests.So that was very cool for me to see her writing it down as well. It seems my idea the other day was not completely silly. :-) Haven't seen it anywhere else up until now.
This test subject fits perfectly. Just before quitting time two work mates and I discussed about tests. And one rule we made up now is to prefer table tests, when possible. This helps writing and maintaining better tests. I remember back in the Java days when there were different parameterized test frameworks, as they called it. They worked similarly, but in contrast to Go's flexibility of the builtin table tests, it doesn't really compare. Arguably, it's still heaps of code in Go, but creating parameterized tests in Java was always much more hassle in my opinion. Oh, I need this special runner now, which is the correct one? What was the annotation called again? Oh hang on, now these other tests won't work anymore with this new test runner, I have to move stuff to new test classes. That's why I only rarely used them. With Go, it's a real first-class citizen and not an afterthought and that positively shows. (Not sure if parameterized tests improved after Java 8.)
One thing that the article doesn't mention, or I already forgot after writing this wall of text. ;-) Thinking about edge cases. That's super important and often they're missed in my experience. Here TDD might be a good approach to the problem. Come up with possible cornor cases up front, write some tests and then implement the logic. At least for bug fixes this is a great way. There are limitations of course, if you don't know in advance how your going to design the API, TDD won't work in practice. We just had exactly this sitation this week at work. Even with only one fairly simple new function in the end. We threw away four (!) designs and did it quite differently for the final result. If we had strictly followed TDD here, we would have rewritten all our tests a couple of times. And that would have been super annoying and thus demotivating (well, we had to completely rework them once). Granted, that doesn't happen thiiiis often, but it still occurs every now and then.
One last final thing: I very much enjoy looking at code coverage reports and see a lot of green there. This motivates me writing more tests and thinking of ways I could test that last little thing here as well. And if that turns out to be impossible with reasonable effort, you know that you probably need to refactor things.
cbl
and friends. When I quickly counted by HTTP status code, I thought it would be nice to interactively drill down further. But I couldn't answer my question of what I actually want to see or look out for, so I stopped.
HELP
, because my quickly thrown together parser didn't expect this sort of crap. Any particular tools you use to analyze your logs with?