HNHacker News
TopNewBestAskShowJobs

sagichmal

2,816 karma · joined April 16, 2014

e1b1ce94085da63902d7c51d8f1e0697
submissionscomments
sagichmal··on Show HN: We wrote a book about building business applications in Go
> Most people don't understand how to build an application. They think in terms of RPC and encoding, not in terms of Screens, Actions, and Workflows.

What are Screens, Actions, and Workflows?

sagichmal··on Show HN: We wrote a book about building business applications in Go
> go-kit is very far away from DDD.

Bizarre. Go kit is basically the reference model for DDD in Go.

sagichmal··on Show HN: We wrote a book about building business applications in Go
Lightweight DDD is a great match for Go. You don't want to go all-in -- you don't want a package usecases, for example. You just want to take the high-level concepts and apply them in a way that's idiomatic to the language. The Hexagonal Architecture is basically equivalent.
sagichmal··on Show HN: We wrote a book about building business applications in Go
> inheritance is an advanced programming language feature

It really isn't.

> that is easily misused.

If a tool is misused frequently enough, it really isn't the fault of the users.

sagichmal··on Fly’s Prometheus Metrics
> VictoriaMetrics

:(

Not actually Prometheus-compatible, sloppy code, spotty docs. I have no idea why this dumb product continues to attract users.

https://prometheus.io/blog/2021/05/04/prometheus-conformance...

> Telegraf, which is to metrics sort of what Logstash is to logs: a swiss-army knife tool that adapts arbitrary inputs to arbitrary output formats. We run Telegraf agents on our nodes to scrape local Prometheus sources, and Vicky scrapes Telegraf. Telegraf simplifies the networking for our metrics; it means Vicky (and our iptables rules) only need to know about one Prometheus endpoint per node.

Normally you just use a regular Prometheus server to do this. Why add another, different technology to the stack?

> We spent some time scaling it with Thanos, and Thanos was a lot, as far as ops hassle goes.

It really isn't -- assuming you're not trying to bend Prometheus into something it isn't. Prometheus works using a federated, pull-based architecture. It expects to be near the things it's monitoring, and expects you to build out a hierarchy of infrastructure, in layers, to handle larger scopes.

This is structurally different to what I'll call the "clustering" model of scale, where you have all your data sources pushing their data, aggregating maybe on the machine or datacenter level, but then shuttling everything to a single central place, which you scale vertically from the perspective of your users. This appears to be what you want to do, based on the prevalence of push-based tech in your stack.

Prometheus doesn't work this way. Some people really want it to work this way, and have even created entire product lines that make it look as if it works this way (Cortex, M3db) but it's fundamentally just not how it's designed to be used. If you try to make it work this way yourself, you'll certainly get frustrated.

sagichmal··on Why People Feel Like Victims
No, it isn't framed as all or nothing.

Principally because "the framing" isn't some well-defined objective thing, it's all a matter of perception, which means it's always possible to read whatever narrative you like into the facts.

Like this:

> the narrative around racism being the sole and primary cause of failure.

This perception is yours, not the facts on the ground.

sagichmal··on Why People Feel Like Victims
Macro vs micro.

Appropriate advice at the individual level is often very different than, and sometimes the complete opposite of, appropriate advice at the demographic scale. It's fine to tell your brother to quit the shit and pick himself up by his bootstraps or whatever; it's both inappropriate and ineffective to translate that notion into social policy.

Systemic racism is a macro concern. Talking about it, and what to do about it, is a conversation totally different than the conversation you have with your kids about their lived experience. Being aware of systemic racism doesn't make anyone a victim. It makes them cognizant, smarter, better actors in the system.

sagichmal··on How Basecamp Blew Up
My post rebutted a claim. It didn't inflame anything, nor did it escalate the conversation. Readjust your sensors. And unflag the post.
sagichmal··on How Basecamp Blew Up
In no way did I do what you're claiming. Please unflag my post.
sagichmal··on How Basecamp Blew Up
> You think the base got there all on their own,

Yes, more or less? I can't think of a single right-wing activist or politician who was truly rabble-rousing for the cause.

sagichmal··on How Basecamp Blew Up
> And conversely, you don’t get to assume that others understand you when you use language in ways that aren’t colloquial.

Yep! It was a failure of all parties involved that the two competing definitions of racism weren't laid out on the table, when people started getting huffy.

> Shared definitions is the bedrock of human communication, and absent that, we’re no better than chimps just grunting past each other.

(laughs) Lay it on thick, why don't you?

sagichmal··on How Basecamp Blew Up
(laughs)

"Politicians and activists" obviously didn't politicize masks. No coherent reading of the last 2 years supports that conclusion.

It was the screeching Republican base, who decided on day one that the masks were a symbol of government overreach and I guess got Covid to own the libs.

sagichmal··on How Basecamp Blew Up
You don't get to assert what other people mean when they say things (shrug)
sagichmal··on How Basecamp Blew Up
You're describing the critical perspective, which is just a framing that motivates discussion. There are versions of it for essentially every sociological phenomenon. The hypersensitivity to it among certain demographics is what's remarkable, much moreso than the thing itself.
sagichmal··on How Basecamp Blew Up
> I agree for the most part there. Less so the founders,

How anyone can look at this debacle and think of the employees as anything but victims, and the founders as anything but reactionary blowhards, is absolutely incoherent to me.

The founders are obviously the ones in the wrong here, and obviously come out with shattered reputations.

sagichmal··on “Shared libraries are not a good thing in general”
> many people seem to like unified look and feel

All else equal, sure. But they'll sacrifice that in a minute if it means elimination of other toil.

> many people complain about per-app auto-update

Facts not in evidence.

> many people love to complain software is getting worse

Okay.

> I work on distros...

Well, there you go.

sagichmal··on “Shared libraries are not a good thing in general”
The number of people who consider the system/distribution the atomic unit rather than the application, is probably about equal to the number of people who "edit dependencies and put their system back together" -- they are in total statistically zero. The overriding concern is the user need for a working application. Everything else is a distant secondary concern.

I'm not trying to convince you of anything, here, I'm just describing the facts on the ground. If you're not into them, that's fine!

sagichmal··on “Shared libraries are not a good thing in general”
Rebuilding tens of thousands of packages on a dependency upgrade is not a big deal.
sagichmal··on “Shared libraries are not a good thing in general”
Fewer and fewer people are interested in the benefits provided by "coherent whole" distributions. And more and more people are interested in the benefits provided by "it's own island" applications.

The future is statically linked and isolated applications. Distros need to adapt.

sagichmal··on “About one-third of Basecamp employees accepted buyouts today”
> Probably, the founders believed that the toxicity of the internal culture had reached a point

There are precisely one set of actors behaving toxically in this whole fiasco, and it's the founders.

> I'd be really surprised if this surprised the executive team. This seems to be a super intentional and very professionally executed cultural shift / purge.

Hahaha, what? In which universe are you inhabiting? No piece of evidence supports this theory. All the evidence clearly points at this being a hasty and unplanned reaction to a hasty and unplanned emotional outburst at an employee by a founder.

sagichmal··on Swimlanes.io – generated editable sequence diagrams
Cool!

Sequence diagrams are by far the most effective way to communicate system behavior.

These, and boxes-and-lines diagrams to communicate component relationships, are all that's necessary to document a system of arbitrary complexity.

sagichmal··on The unreasonable effectiveness of print debugging
I've not figured out a way to effectively debug a distributed system except via printf. Debuggers are basically a nonstarter, because stopping one component to inspect it almost always triggers knock-on effects in other components that change the overall state of the system.
sagichmal··on My Go executable files are still getting larger
TinyGo will soon support encoding/json.
sagichmal··on My Go executable files are still getting larger
This isn't an interesting or convincing argument because it revolves around a non-satisfiable metric. No matter the size of an artifact, this line of reasoning can always be used to claim it's too big and needs to be smaller.
sagichmal··on Golang: Know Your 'Nil'
> if res, err := fn(...); err != nil { > return nil, err > }

It's bad practice, though unfortunately extremely common, to return unannotated errors like this. I can't think of the last time I've used this stanza. The proper form is, at a minimum,

    if err != nil {
        return nil, fmt.Errorf("executing request: %w", err)
    }
Or, if there's additional, caller-actionable information about the error you want to provide,

    if err != nil {
        return nil, OtherError{Inner: err, Extra: xyz, ...}
    }
and so on. The point is you have in that stanza the space to program with the error, same as any other value in the function. The... semantic equivalence? which the idiom reinforces is actually extremely good! Error handling isn't any less important than happy path code, and, IMO, language features like `?` suggest that it is.

> It's incomprehensible to me that...

It is not immediately clear that the first example is incrementing every even number. To get there, we have to parse the method names, recall and parse the special syntax rules for those methods, and, if we're being diligent, reflect on the ownership requirements and allocation effects w.r.t. their parameters, to make sure we're not doing anything with unintended side effects.

We're doing basically the same work in the second example, minus the ownership stuff. We're using more characters to do it, but that's not a priori worse. Parsing `res = append(res, v+1)` does not take more time than `map(|a| a + 1)`. Using curly brackets and newlines to demarcate transformation steps instead of monads is not more prone to bugs. It's the same stuff, expressed differently, and, IMO, more coherently: code written in the imperative style is generally easier to understand than functional. (I hope that isn't controversial.)

> There's no argument for the go loop being "better" than the Rust equivalent that doesn't also argue that the C version with the additional hassle of bounds-checking and manual incrementing is better still.

Reducto ad absurdum.

sagichmal··on Golang: Know Your 'Nil'
> Even better, if there’s an error, there is no non-error return value. You can’t accidentally use the zero-valued return half of a tuple (as you can in golang) because it simply isn’t there.

That is better! But it's not as better as I think you think it is. The conventions are adequate, here.

> Is the important part of error handling having some copy-pasted stanza repeated everywhere? Or is it enforcing that errors are always handled and semantically-undefined return values are never accidentally passed along in the event of an error?

Neither, really: it's about having the error code path visually equivalent to the non-error code path.

> No, it simply is not. `?` early-aborts the function and returns the result straight away if it’s an error, and unwraps the interior value if not. There is no plausible way for someone to mispredict this behavior, and if there was, it would be no different from golang, since the two constructs are semantically virtually identical. One is simply shorter than the other.

I don't want early abort. Don't know how else to say it. If I have 5 operations, each of which can fail, I want them to be 5 visually distinct stanzas in my source, and I want to be able to manipulate the errors from each independently.

> Ease of understandability is almost hands-down the most important metric given the ratio of frequency to code being read versus written. And to be completely blunt, it is flatly ridiculous that wrapping every line in nearly-identical error handling code somehow doesn’t impair comprehension. The argument is the same for abstractions like `map`, `select`, `reduce` et al. Intent and behavior of code can be understood at a glance when you remove the minutia of looping, bounds-checking, and indexing

I'm sorry, but I just don't agree. You call looping, bounds-checking, index, etc. minutia, but I don't see it that way.

sagichmal··on Golang: Know Your 'Nil'
I think the core of it is the belief that error handling is no less important than "happy path" code. In some domains, this isn't true. In mine, distributed systems, it is. So I don't want to relegate errors to some ghetto, I want them to be front and center, equal to everything else.

Another small part is probably how you think about the error values themselves. I almost never want to pass an error to my caller exactly as I receive it, I almost always want to do something to it first, most often decorating it with relevant context and metadata where I receive it. Sometimes, obscuring it, if I don't want to leak implementation details.

But ultimately it's about explicitness, obviousness. `?` is easy to miss, and permits method chaining, the outcome of which is incredibly easy to mispredict. And in imperative code, which is the supermajority of all code, `?` gives no meaningful increase in speed-of-reading -- which is a bogus metric, anyway. So for me, strongly net negative.

sagichmal··on Golang: Know Your 'Nil'
Yep, it's very useful for channel-based state machines, you can turn transitions on and off between states.
sagichmal··on Golang: Know Your 'Nil'
There is one way to iterate over things, for any kind of elementwise processing: a `for` loop.

There is one way to format your code ;)

sagichmal··on Golang: Know Your 'Nil'
`?` makes code substantially less coherent, not more.
← PreviousPage 4 of 34Next →