Hacker Newsnew | past | comments | ask | show | jobs | submit | MarkMarine's commentslogin

I love the model, hate the tool. I’ve taken complex stuff and given it to Gemini 3 and been impressed, but Anthropic has the killer app with Claude Code. The interplay of sonnet (a decent model) and the tools and workflow they’ve got with Claude code around it supercharge the outcome. I tried Gemini cli for about 5 seconds and was so frustrated, it’s so stupid at navigation in the codebase it takes 10x as long to do anything or I have to guide it there. I have to supervise it rather than doing something important while Claude works in the background

I’m sure this isn’t directed at everyone that works at GH, but it would have been more tactful to fault the people making decisions. Those frustrations are real though.

It is actually.

"I also strongly believe that you should not be proud of working for Microsoft, and particularly on GitHub for the last 5 years. I truly am sorry but you need to be called out."

https://hachyderm.io/@andrewrk@mastodon.social/1156234452984...


Reading the infra part of the post made me smile, I spent part of my week putting workloads on spot but this is the real spot market. Chaos monkey is running in prod if you are ready for it or not.

Jokes aside, the technical depth it takes to make that one server run is impressive. That makes me more interested in codeberg, not less, though I’m going to keep my own mirror of the zig repo until they get some better hardware.


To be clear, I’m not knocking it; I also like to reuse old computers. But it’s incongruous with replacing GitHub, rather that being a “weirdo hobbyist” version of GitHub.

And yet the amount of work time I've missed out on from github being down is slightly concerning in retrospect. I imagine the smaller scale of codeberg will actually lead to more uptime despite chaos monkey's best efforts.

The numbers aren’t looking great so far[1]: they’re not cracking 3 9s on their primary service, and their CI/CD isn’t even cracking 2 9s. And these numbers are much better than when I checked a few days ago!

(This should not be read to imply that I think that GitHub’s reliability is acceptable; it clearly isn’t.)

[1]: https://status.codeberg.eu/status/codeberg


Uptime above 99 I really would only care about the time to get back working. My enterprise experience with Github was multiple days of no work in a year.

> we hope to use direct solar power to operate CI/CD nodes only during sunshine hours

Status: CI down due to cloud issues.


There is no such thing as “the neighborhood kids” anymore. Having any kind of social circle for your children is going to require your facilitation and effort… a lot of it. It’ll be extra hard without the common bond of shared activity.

Not knocking what sounds like your choice to homeschool, just sharing something that has changed from my youth.


There are in fact neighborhood kids. It only takes a couple of families deciding to restrict phones and video games and support their kids in spending real time together. We’ve done this in our neighborhood and it’s great. It just has to be intentional now, where it was the default before all these screens.

I revile this pattern. Look at the examples and imagine these are real and everything in the system is abstracted like this, and your coworkers ran out of concise names for their interfaces. Now you have to hop to 7 other files, through abstractions (and then read the DI code to understand which code actually implements this and what it specifically does) and keep all that context in your head… all in service of the I in some stupid acronym, just to build a mental model of what a piece of code does.

Go used to specifically warn against the overuse of this pattern in its teaching documentation, but let me offer an alternative so I’m not just complaining: Just write functions where the logic is clear to the reader. You’ll thank yourself in 6 months when you’re chasing down a bug


This is a common gripe among former Java programmers who still believe that the point of interfaces is the type hierarchy (and as a result misunderstand Interface Segregation). They hang on to interfaces like they're these precious things that must be given precious names.

Interfaces are not precious. Why would anyone care what their name is? Their actual purpose is to wrap a set of behaviors under a single umbrella. Who cares what the color of the umbrella is? It's locally defined (near the function where the behaviors are used). Before passing an object, just make sure that it has the required methods and you're done. You don't have to be creative about what you name an interface. It does a thing? Call it "ThingDoer".

Also, why would you care to know which code implements a particular interface? It's equivalent to asking give me a list of all types that have this exact set of behavior? I'm possibly being myopic, but I've never considered this of particular importance, at least not as important as being conservative about the behavior you require from dependencies. Having types enumerate all the interfaces they implement is the old school approach (e.g. Java). Go's approach is closer to true Interface Segration. It's done downstream. Just patch the dependency with missing methods. No need to patch the type signature up with needless "implements this, that, other" declarations, which can only create the side-effect that to patch a type from some distant library, you'd have to inherit just so that you can locally declare that you also implement an additional interface. I don't know about you, but to the idea of never having to deal with inheritance in my code ever again I say "good riddance".

Again, interface segregation is about the behavior, not the name. The exact same combination of methods could be defined under a hundred different umbrellas, it would still not matter. If a dependency has the methods, it's good to go.


Your two paragraphs give example to the exact problem. “It doesn’t matter what the name is, interfaces aren’t precious”, and “you don’t need to see the implementation to know what it does, just read the method name and type signature” right?

Not sure how you hold those two things in your head at the same time, but they are anathema to each other. Different implementations of the same function name and type signature can have drastically different effects in go because side effects are everywhere in go, so you must read the implementation to understand what it does.

If this was Haskell and I could read the type signature and trust that I know what the system did with that (ignoring Rich Hickey’s point about the type signature not describing what “reverse” does) then fine, but in every function call there are unconstrained numbers of side effects, go functions which persist after the function goes out of scope and can modify any pointed to memory at any arbitrary time later… go is the Wild West in this regard. The interface method name + weak go type system function definition is not enough to tell a developer what the implementation of that interface actually does. Finally: Java’s “implements” plus excellent IDE support for Java DI allows a developer to jump to the implementation in one keyboard press, this does not exist in go. You’ll probably never know what method is actually called unless it’s runtime with the actual config on the server.

I’m not going to explain the whole reasoned argument about why it’s important for a programmer to understand program execution flow in their head clearly, Dijkstra did a much better job than I ever could with GOTO considered harmful, but check out a modern descendant of this article specifically talking about go functions, and try to internalize the point about being able to understand program execution flow:

https://vorpus.org/blog/notes-on-structured-concurrency-or-g...


I see a few of my words and others that I neither said nor thought. With respect, perhaps you're rushing in a particular unrelated tangent and drawing conclusions.

The points I was trying to draw your attention to was that duck-typing as it's done in Go (structural typing to be more exact), is at the crux of its approach to interfaces. Do you understand duck typing or structural typing?

To summarize what I've already tried to say before, Go interfaces are not Java interfaces. Java cares about the interface as a type, while Go cares only about the listed methods (the behavior). These are two completely different paradigms, they don't mix so well, as former Java programmers doing Go are discovering. In Java, interfaces themselves are important because they're treated as types and programmers tend to be economical about them. They're used everywhere to say that a class implements them and that they're a dependency of some consumer. In Go the interface is just a convenient but unimportant label that points to a list of methods that a consumer expects a particular dependency to have. Only the list of methods is meaningful. The label isn't. That's it. Done.

Again, completely different paradigms. If you embrace Go interfaces, the way you read, write and think about Go code also changes. But complaining about them with a Java mindset is complaining that a wrench is a bad screwdriver.

At the end of the day, it's up to you to decide whether you can open your mind and actually learn to use a tool as it was meant, or just assume that its creator and all the people that claim to do so successfully are in denial for not admitting to share the pains you have.


Look, I understand duck typing. Go doesn’t have it, the fact you keep calling go’s dynamic dispatch duck typing is a bit of a red flag, but I can see why you would think that. It’s not my point though, you’re missing what I’m saying.

You’re saying, essentially, that you just use the objects method and you don’t need to read its implementation to understand what it does, if something has a “Update” method and it takes a new copy of the object and it’s a pointer method, as a caller we can assume that we give the new data to that update method and it’ll just take that data and patch it into the object at that pointer address. You don’t have to read the method and go on with your day, the interface proves it works and you don’t need “implements”

The problem with this is there are bad programmers who do crazy things with “Update”. Some people will kick off go routines that do things later and mutate things you don’t expect. So when you fetch 500 things then update them in a loop and suddenly nuke your database with 50,000 writes simultaneously that are all contending for the same key, you will go back to Update and see… oh fuck this update method uses some clever Postgres queue and keeps a lot of metrics that are also in Postgres, that’s why my system locked when it shouldn’t have. I should have read this Update method.

So that is crux of my point. Having the method name and function parameters only is not enough to understand your program, and using single interface definitions all over the place hurts readability and understanding.


> Look, I understand duck typing. Go doesn’t have it, the fact you keep calling go’s dynamic dispatch duck typing is a bit of a red flag

No, more like static typed duck typing, or more accurately its close cousin structural typing.

But if you need to hear it from the horse's mouth https://research.swtch.com/interfaces

> You’re saying, essentially, that you just use the objects method and you don’t need to read its implementation to understand what it does

Your recent points have nothing to do with mine. What you're thinking that I'm saying is not what I'm saying. I'm still very much aligned with the original topic of the article, Interface Segregation as it's done in Go. An article to which you reacted adversely, while demonstrating that you're clearly still looking for Java where it doesn't exist. I'll leave things at that, since I'd just be repeating myself at this point.


I’m not a Java dev, my preferred languages are Clojure, scala, rust, and python. I think you assumed ignorance, tried to explain something your colleagues probably don’t get to someone who understands it, and then haven’t put the effort into reading the link I sent earlier, and I’ve failed miserably at explaining my point.

I think you’d have to have seen the problem, and maybe it only pops up in a large go monorepo that uses DI the IDE can’t see through, while simultaneously having to work with interfaces like “Get” where some of the implementation was written by devs who think Get is a mutation.

You’re right though. We’re talking past each other and both think the other one is a moron. Leave it to the reader to figure out which one is I suppose.


I have written production Java code, but no production Go code. I think you skipped over the commenter's main point while replying to them: you need to be able to have a good mental model of the code.

A few well defined interfaces have the advantage of being easy to understand and see usages around the codebase without the overhead of many different variants of an interface. This is extremely important if you are not familiar with a given codebase.

I'm not against segregated interfaces, but I feel like over abstracting can result in code that's harder to understand. There's a balance to be had and thought should go into introducing new interfaces, especially when working on a project with many other devs contributing.

I'm a Java dev, so I'm biased. I love being to easily understand and reason about the type system. I understand that an interface is about a set of behaviors, but when I've worked with Go code I've found it much more difficult to get my IDE to point out all the different ways some interface could be implemented. I see the advantages that Go style interfaces bring, but I personally find it harder to keep a mental model when working with Go.


> I think you skipped over the commenter's main point while replying to them: you need to be able to have a good mental model of the code.

I actually addressed the root cause of the main point: a misunderstanding of the purpose of interfaces in Go. To me these complaints are analogous to someone saying that they're not able to move fast enough while trying to run underwater. Why don't you try swimming? The fact that whenever a complainer elaborates a bit, it often points to indications that they might be looking for Java in Go, also leads me to connect the original difficulty to the latter misunderstanding.

> A few well defined interfaces have the advantage of being easy to understand and see usages around the codebase without the overhead of many different variants of an interface.

Interfaces in Go are not a thing. They're a notice from a consumer to say "I'll be using these methods on whatever object you pass in this slot". Not much more. They're closely tied to the consumer (or a closely related set of consumers, if you don't want to be too zealous). It's a different mental model, but if you embrace it, it changes the way you write, read, and think about code.

> I've found it much more difficult to get my IDE to point out all the different ways some interface could be implemented.

Implemented? Forget that word completely. Ask instead "does the object I'm about to send have all the required methods?" If not, add the missing ones. That's it. It's all about the methods. Forget the interface itself, it's a label on a piece of napkin, a tag, to list the set of methods required by the consumer on a particular dependency.

I think Python duck-typing philosophy is a much better access door to Go's interfaces than Java interfaces. You just care about how a dependency will be used by its consumer. Now, if as a language designer you wanted to add the discipline of static typing on top of duck-typing, the logical conclusion would be either a syntax for "anonymous" interfaces that lets you duck-type

    func Consumer(obj interface{doThis(str), doThat(int)}) { 
        obj.doThis('foo');
        obj.doThat(123);
    }
or the less ad-hoc style we've come to know from Go.


Congrats to the whole stytch team, I was a customer and evangelist for stytch at a previous company, and I really liked what they offered and dealing with the team. Interesting they were bought by twilio, as abstracting over two sms providers for SMS OTP was one of the main things I wanted from them.


I have dreams of being at a “Clojure shop” but I fear daily professional use might dull my love for the language. Having to realize that not everyone on my team wants to learn lisp (or FP) just to work with my code (something I find amazing and would love to be paid to do) was hard.

On a positive note I have taken those lessons from clojure (using values, just use maps, Rich’s simplicity, functional programming without excessive type system abstraction, etc) and applied them to the rest of my programming when I can and I think it makes my code much better.


nit picking on the example code while missing the example the code was trying to demonstrate. I see why TAOCP used pseudocode


Agreed! But i didnt miss the example.... i also thought it was interesting that all the various examples of declarative or applicative did Date.now(), which i see as a big thing to avoid.


These chains become easy to read and understand with a small language feature like the pipe operator (elixir) or threading macro (clojure) that takes the output of one line and injects it into the left or rightmost function parameter. For example: (Elixir) "go " |> String.duplicate(3) # "go go go " |> String.upcase() # "GO GO GO " |> String.replace_suffix(" ", "!") # "GO GO GO!"

(Clojure) ;; Nested function calls (map double (filter even? '(1 2 3 4)))

;; Using the thread-last macro (->> '(1 2 3 4) (filter even?) ; The list is passed as the last argument (map double)) ; The result of filter is passed as the last argument ;=> (4.0 8.0)

Things like this have been added to python via a library (Pipe) [1] and there is a proposal to add this to JavaScript [2]

1: https://pypi.org/project/pipe/ 2: https://github.com/tc39/proposal-pipeline-operator


If you get an exception, you might not know where it comes from unless you get a stack trace. Code looks nice but not practical imo


I use Clojure all the time and I haven’t noticed the gripe you’ve got, but these are built in features of (somewhat) popular programming languages. Might not be for you but functional programming isn’t for everyone.


I've watched LPL videos and practiced on regular locks, I can pick something that is about 10$ or less, but these expensive locks with good tolerances (Abus) or disc detainer cores (kryptonite locks,) no amount of practice and fiddling with the correct tools has ever opened one of these. I lack the skill or touch.

I can hold a 18v grinder with a cutoff wheel just fine though, I lost the keys to one of those kryptonite locks on my bike and I was riding my bike again 30 seconds later.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: