Block / Report User

If this user/feed is violating this Pod's ( community guidelines as set out in the Abuse Policy, please report them immediately!

You are also free to Unfollow or Mute this user or feed. Muting will also remove that user/feed's content from your view and you will no longer see content from that user/feed anywhere.

@lyse does not follow you (they may not see your replies!)

Recent Twts

Recent twts from lyse

(#hn4w24q) Congratulations! That’s by far the longest twt I’ve seen. :-) Working fine in tt. I was a bit worried, that lengths of multiple screens would be hard to read or scroll. But magically it just scrolled line by line.

I reckon two returns 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.


(#c2v3fnq) Kind of, I know that August is great for the perseides. So I thought I’ll give it a quick shot. Given, that I just do that for at most a minute each night, I didn’t expect to actually be that lucky and see anything. Looking at the nice moon and the Ursa Major is generally all I can ask for.

Comet is also not too shabby. ;-)


(#moqdvoq) Ta! KMail goes two steps further. The blue pane appears already while typing up the e-mail. When hitting Send, the Attach File… button in the message dialog is the default, minimizing chances of sending the mail without any attachments when just pressing Enter out of a habit. Yup, also experienced that a couple of times. :-)

And now I nearly missed adding the screenshot to this twt! Good thing I proofread it three times.


(#moqdvoq) I have a high prejudice against GTK, but thanks for the tip! At least they also go the OK/Apply/Cancel route and don’t just offer a Close button in the settings dialog. That sounds promising. Their feature list is also very nice. I’ll take a closer look next time KMail maroons me. One question, does it warn about missing attachments? That feature I first saw in KMail saved me thousands of times.


(#moqdvoq) KMail is actually fairly good, it does basically all I need. Problems started when they introduced this Akonadi shit. This just calls for trouble every now and then. On my old machine the database even got corrupted irrepairably. Starting over with a maiden one I ended up with another broken state beyond repair a few weeks later. Still today Akonadi, must be kill-9-ed from time to time.

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. Absolutely, HTML mails are an invention straight from hell! I even only send plain text mails at work as the only guy.


Bloody hell, my system update affected the libc, libc6, locales and golang-1.19 packages and after a reboot KMail is fucked. Uses 100% CPU and doesn’t show any mail texts anymore. Starting it in a terminal then shows heaps of org.kde.pim.webengineviewer: WebEngine render process crashed being printed to stdout. Closed as invalid. suggests to QTWEBENGINE_CHROMIUM_FLAGS="--enable-logging --v=3" kmail, unfortunately, nothing useful shows up:

[32957:1:0813/] Activated seccomp-bpf sandbox for process type: renderer.
[32491:32555:0813/] 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?


(#7t25nmq) I reckon pretty much the same like you did. I haven’t looked at this OpenAI API, in case it is simple enough, I would probably not have used their client library, though. Again, no idea if that would be feasible. I like WTFPL and even got a proper answer when trying to ask about it on your demo. ;-)


(#kwzlfya) Cool. Do you plan on writing an article on your time shell script? I was quite happy to see basically simple (in practice could be more complicated) things like this cobbled together in a short time. The script itself would also suffice, but maythere there is more to tell. :-)


(#bqxlviq) Right, it’s not inheritance, but embedding. The two standard errors are cool. But always doing basically the same for all our own errors with probably also implementing 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.


(#3vguvha) Now, looking at’s es, I feel quite a bit stupid. In my particular case I could have just put the %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! :-)


(#bqxlviq) In one project a bunch of work mates strongly advocated a new to everyone (them included) idea. Any incoming request must produce exactly one log line. Not more and not less. Exactly one. That way the log does not get spammed with lots of useless information most of the time and one immediately sees what went wrong, if at all. In the beginning I thought this is completely rediculous, because I had never seen this anywhere and thus just couldn’t imagine that this will work at all.

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.


(#bqxlviq) Error handling especially in Go is very tricky I think. Even though the idea is simple, it’s fairly hard to actually implement and use in a meaningful way in my opinion. All this error wrapping or the lack of it and checking whether some specific error occurred is a mess. 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.


(#ifbiyuq) Let me think. Three things come to mind. I wasn’t aware of all the history of ASCII and the exact reasons why some symbols are placed where they are. Pretty genious. Also the French Russian pen friend parcel is a cool story I never ran across.

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. :-)


(#zcz4kua) It’s been a long time ago, that I looked at the yarnd code. Maybe you need to follow those people to mention them automatically? No idea. I just remember that it was changed. In the beginning there were quite a lot of mentions filled in when replying and then people decided against that behavior for some reason I cannot recall anymore.


(#nik3c4a) Yes, formatting with a special date is incredibly silly. I couldn’t believe it myself either the first time I ran across it. It still drives me nuts every single fucking time I have to deal with it. Not sure why the Go folks still don’t consider it a failed experiment. Luckily, I can often just use the 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 Xs though).


(#bqxlviq) I forgot one thing. Testing for errors is also an important part that is often overlooked in my experience. Another rule we talked about two hours ago is to test error messages preferably exactly. Then there’s a dim chance of spotting a final garbage error message. When seen in total, one might tell if it is understandable and all important context information are present. Lots of error messages I’ve come across are completely useless, I’ve no idea what’s going on or what I have done incorrectly. A frightening lot of times messages don’t even make any sense at all. Not a single bit. Just random words put together. The really bad ones you don’t understand even if you look at the code and exactly know what the situation is but still cannot decipher the message with all that knowledge on top. It happens more often that I would think.

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.


(#bqxlviq) Yup, looks good, I also agree with her.

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.


(#bqxlviq) It’s been a while, but your code I’ve seen so far didn’t look too bad to me. I remember we had discussions about missing tests, but other than that, I can’t recall any “oh dear, WTF” momements. Obviously, there’s always something, that can be improved, nobody writes perfect code. Only close to perfect. :-) Being sick and having time pressure doesn’t help writing good code either. So, don’t take the harsh feedback too seriously. Let a week pass and have a look again, your perspective might have shifted and you possibly understand what they wanted to tell you, assuming they wanted to give you honest feedback. Buck up! :-)


(#fj6gwxq) Like, I can’t give you any hints, Sorry. For me, a hobby project just has to be fun in some way. But I know this too well myself, over time interest is lost and thus the project never finished. But I reckon that’s fine, too. Because there was a time where I had fun and/or learned something. However, I fully agree that it doesn’t feel good to not have completed the project.


(#7ldrcdq) You’re spot on. Making everything configurable opens a whole sea container of worms. You convinced me to make it as simple as possible. Haha, no, I do not have paying users, in fact it’s just me. Maybe up to three other mates in the future. It’s just a hobby project, so there won’t be anybody paying anything. And that’s perfectly fine for me as nobody can force me to do something. :-)

I’ll go with two predefined exercise types, that’s all that I need at the moment. Yeah, keeping extensability in mind is very important. Thank you very much for all your valuable input!

Our approaches differ in measurements, I don’t care about calories, although, that is most likely by far the best meaningful number. It’s just not something I’m interested in and I also don’t have any way to measure it. In that regard I’m like a child and want to play with counting exercises. ;-)