helloworld("print")

Nerdsniped by aarols meme HelloWorld(“print”) I had to try to do this in Lua and without debug.info.

I thought about the __call metamethod at first but then realized that I had to use __index:

setmetatable(_G, {
    __index = function(t, k)
        return function(target_func_name, ...)
            local func = _G[target_func_name]
            if type(func) == "function" then
                return func(k, ...)
            end
        end
    end
})


HelloWorld("print")

x4

Image Description

Having fun with the tiny(about the size of a zine) xteink x4 eink e-reader. Would love to have RSS support for crosspoint.

The craft of interfaces

Currently I am reading 100 Go Mistakes and I like it. One of my personal pet peeves is the ‘interface on the producer side’. It’s a sure way to spot a programmer who is new to Go. And that makes me think again on how to mentor new Go programmers. I remember myself struggling with that when starting out. Today most of the idiomatic Go is widely documented and newbies still struggle with that. Should the language itself enforce these ‘mistakes’? Some can be enforced by linters but not all. And even with the ‘interface on the producer side’ mistake there are exceptions where it could make sense to share an interface between consumers and maybe even put it on the producer side. That’s the ‘art’ of the craft. I got asked once by a developer coming from .NET: “Why are these idiomatic rules not written down somewhere?”. I guess because it’s kind of an oral tradition. Similar to the (horribly named) ‘code smells’. It’s a taste imprinted by practice and reading lots of ‘good’ Go code. When working with AI I try to provide unit tests and interfaces before I let it generate the actual function. I saw too much one-shot code that was not testable and horribly un-idiomatic. The interface and the unit test act as the spec and help me get what I want out of the LLM. I still care about code quality so that might just be me.

154 Legacy

For various reason I have been thinking a lot about legacy and documentation. I have for example quite a lot of notes on my families genealogy and I would like to make them available to my family at one point. And what happens with all those digital photos? How do others manage this? Do you have a dedicated backup/document platform?

Chat Jimmy

I have been doing lots of coding with different models over the last weeks. Waiting is probably the biggest annoyance downside to developer productivity at the moment. But this seems to change. I just found Chat Jimmy and it’s is crazy fast.

Image Description

YAML is bad whats the alternative

YAML […] human-friendly […]

May I disagree?

Too Vertical

I can’t grok a YAML that is longer than it is wide.

Also vice-versa.

Tippy Taps or just Tap

Why does your format make me press shift-tab key so often? That’s way too many chorded taps.

Lists are not listening

Finally a list. Do we indent or don’t we? The equivalent to inserting a USB-A stick. Oh no, why does it look that way?

Looks are everything

Let’s not fool ourselves.

Is it sinful to yaml?

P1: God is in the details. P2: All details are made by humans. P3: YAML is made by humans. P4: Any Gods except the one true God are demonic. C: Somewhere in this YAML file here is a bezelbub to be found.

Why won’t it stop

We dug too deep and too greedily in the mines of go-k8s and now for the next 25 years we will have the to pay the price.

What then?

hedge knights sleep under the stars

I propose hedge:

# COMPONENT DEFINITION
Component   Deployment
Name        nginx-layout
Zone        production

# LAYOUT & SCALING
Replicas    3
Strategy    RollingUpdate

# VISUALS (METADATA)
Labels
    App     nginx
    Tier    frontend

# CONTENT (CONTAINERS)
# The schema knows 'Container' starts a list item
Container   nginx-main
    Image   nginx:1.21
    Port    80
    CPU     500m

Container   sidecar-logger
    Image   fluentd
    Role    logging

Structs as mutable interfaces in Go

This is one of my favorite and underrated patterns in Go.

Let’s assume a format based on Lua tables, let’s just call it LTRN (Lua Table Resource Notation) and I was imagining a mock value generator for that format.

Now is the perfect time to use a struct of function types!

Imagine we have a simple spec for a property in our imaginary resource:

type LtnSpec struct {
	Type    string // "string", "int", "bool", "table"
	Default any
}

Now we want to generate mock data for that primitive types:

func generate(s LtnSpec, generator Generator) any {
	switch s.Type {
	case "string":
		return generator.String(10)
	case "int":
		return generator.Number(0, 100)
	case "bool":
		return generator.Bool()
	}
	return nil
}

The generator would be a concrete struct that contains functions that we can swap as we like. We need a seam to insert our mock data during testing. Injecting a struct of functions makes this code easily testable.

Why, oh why, is this not an interface, I hear you ask? My argument here is that fill is an un-exported function. It won’t be used by 3rd party developers.

Let us take a look at how the struct looks:

type randStringFunc func(length int) string
type randNumberFunc func(min, max int) int
type randBoolFunc func() bool

type Generator struct {
	String randStringFunc
	Number randNumberFunc
	Bool   randBoolFunc
}

This is very flexible for low state structs that you want to heavily test. Ideally it would not have any fields at all. (Please don’t store your db connection in the generator!)

Back to my argument: The advantage of using a struct over an interface. When we implement the interface for a test mock we have to implement every single function even though we might only need one of them for the particular test. For large interfaces, this sucks! Add that to the reasons why large interfaces are generally discouraged and not idiomatic Go.

With a struct with function types we can provide only the functions that we actually need. To be honest, function types are reference types. But for our purpose we can think of them as pointers. They can be nil! This saves us from writing a lot of unnecessary code in our tests. (don’t forget to check you nils or you might run into panic)

func main() {
	fixedStringGenerator := Generator{
		String: func(length int) string {
			return "TESTSTRING"
		},
	}
	x := generate(LtnSpec{Type: "string"}, fixedStringGenerator)
	fmt.Println(x.(string))
}

My heuristic:

It is clean, easy to read and also fast to write.

What do you think? Would you prefer an interface or maybe just hardwire the functions without injection? Let me know!

Reading while listening

From time to time I catch myself listening to a podcast and also reading a book at the same time. It’s not a good habit because I probably won’t get into either. It’s easier when it’s a both in english. If one is my native language then I do get tripped up.

I wrote about last liminal year and the effects it had on me. I did not mention self-respect. I think engaging in behavior of disrespect towards yourself or in this case disrespecting the attention is in the context of virtue ethics a profound immoral act . This aligns with my feeling when I catch myself engaging in the aforementioned multimedial overload. The feeling itself might be thought pattern stemming from early childhood and parental amplification but I think it rings true on an intellectual level as well.

I do think self-respect leads to happiness and have seen the fruits of that every time I stay true to it. And on the flip side I can see the decrease in happiness when I have engaged in less self-respecting activities. That goes against a grain of maybe a fundamental part of my psyche. An aspect probably best described by Freud’s Autothanatos or the drive to regressively search for self-destruction. That might be an oversimplified model but it at least begins to shed a light on these dark corners and pulls them into the light to be examined and scrutinized without it becoming a criticism of my own character. And I don’t think it is universal.

Other people might see this behavior in themselves and not feel it to be disrespecting. So it might be a highly subjective valuation. But my valuation for myself is now clearer. It’s just something I have to deal with to be happy. It should be part of my psychological hygiene. Like brushing teeth. It should just be part of my life to keep media consumption separated.

I think of Glen Gould’s eccentricities when I catch myself reading and listening. He famously left the vacuum running while playing the piano.

This text is not really about reading or listening. I chose it as a digestible example because it might be a harmless self disrespecting behavior.

Is Markdown still it

I have been using Markdown for over a decade in all kinds of projects and also for note-taking. It’s far from being niche anymore in software development and computing circles. I do forget image and link syntax often but since I use wikilinks in most of my notes that’s not a big problem.

Still, I feel we come to end of the Markdown-era. Let’s try to collect some requirements or a wishlist for “Markdown2”:

What are you missing? Is orgdown or ge mtext the answer?

Scheduling Pitfalls

I have been thinking about time again. More in terms of programming practices and less as in technical scheduling. This is just a point I try to remember when working on scheduling related problems. That being said: engineering reality often forces you make tradeoffs of course.

Moments slip by

In logical time we are starting from identity: We can tell points in time (also called moments) apart from another by them being distinct. M1 has an unique identity and M2 has an unique identity. These moments are different from each other. This ontology is not just philosophically relevant but gives us great power to create machines to perform work at certain moments. I would argue that logical moments are also persistent in state. A crontab file is not going to change unless you change it. Logical time is always discrete but two moments might have a relationship to each other.

Chronological time is a lot more analog, dynamic and “fuzzy”. A moment in chronological time is an observation of a stream. A sample if you will of a continuous function. The stream is continuous but the observer is discrete.

I should remember: A lot of problems arise when dealing with chronological time from logical time and vice versa.

Category error: Time as approximated state

Time in a sequential procedure is a most always the worst indicator for a state change.

put pasta water on stove -> wait 5 minutes -> put in pasta

Obviously the pasta water might not be boiling after 5 minutes(stove might be turned too low or even off). The correct way would be to verify the state by looking at data or features. The water is bubbling and steaming? Or a thermometer shows actual degrees? We often combine time and state checking in polling to wait and check. But a blind timer is almost always the wrong answer. Timeouts are a special term for blind timers. State relations triggered by timeouts depend on chronological time and can be helpful as a last resort. But think about this: Would you add a “just-in-case” clause to a while loop just because you are afraid about it not terminating?

Don’t use time as a scapegoat for unsharp thinking or being lazy: If the e2e test runs more than 5 minutes it might be safe to assume “something” has timed out and therefor we can time out the whole test? No, I should at least make sure that the systems and environment is handled.