Live data from Hacker News

Go + Services = One Goliath Project

engineering.khanacademy.org

211–220 of 449 posts

Re: Go + Services = One Goliath Project

#211

We turned our monolith into a bunch of micro services almost 6 years ago to the day. For a long time I was very happy with the new pattern but over the years the weight of keeping everything updated along with the inevitable corners that fall behind and have...questionable..security due to how long they sit neglected has really left me wondering if I am happy with it after all. I would love hear some thoughts from ot…

Our approach to services at Khan Academy is likely a bit different from most. We're sticking with a monorepo (the code for all services lives in one repository). We have a single go.mod file at the top of the repo, so all services use the _same versions_ of dependencies.

We're still building out our deployment system to better support multiple services, but we're planning to redeploy all of the services when library code changes (which is something we're trying to minimize).

All of this ensures that we don't have trouble with services lagging behind on critical updates.

Re: Go + Services = One Goliath Project

#212

Isn't there a quote somewhere along the lines of "full rewrites are suicidal?" Seems pretty risky to me.

The saying only applies when your product is software itself, not in most cases where software is just the means to deliver your product — here a website providing education in video form etc. Besides, the reality is that most business software out there gets rewritten every 3-15 years (really depends on use-case and conditions, but on average 4-5-6 years is a good bet). After some time it's just not worth it to keep…

the number of failed migrations, modernizations, and "tech transformations" in non-software industries, as well as the number of consulting outfits and their profits doesn't seem to back this up.

[0] IT disasters now part of modern life - https://www.afr.com/technology/it-disasters-now-part-of-mode...

[1] Number of IT failures at banks and other firms is unacceptable, say MPs - https://www.theguardian.com/business/2019/oct/28/number-of-i...

[2] The Biggest IT Failures of 2018 - https://spectrum.ieee.org/riskfactor/computing/it/it-failure...

we can argue whether these are "rewrites", but big changes can be rewarding but are inherently risky. balancing this is hard, and rewrites uncover and introduce the unknown unknowns.

Re: Go + Services = One Goliath Project

#213

Earlier quoted context omitted.

If you need to express something complex enough that you can't do it in a single statement in Python, it deserves to have a name (or more likely, it already has one in the standard library).

Large anonymous functions are very much a thing in JavaScript.

This trend will gradually fade into the history books. Just because it’s a thing doesn’t mean it’s a good one.

Re: Go + Services = One Goliath Project

#214
post #143

Earlier quoted context omitted.

But python for loops can and typical do have multiple lines, yet that “block” inside the for loop doesn’t have a name. The fact that the body of a for loop can have multiple lines but an anonymous function cannot is a purely arbitrary syntax limitation, and the principle you stated ought to apply (or not apply) equally to both use cases.

This doesn't follow: for loops are there specifically for cases of the complexity that can't be handled by other constructs (like comprehensions). Anonymous functions are not, for the complex cases you give the construct a name. It's a very intentional language limitation, much as semantic whitespace is an intentional limitation. And there is actually a language difference. A for loop is a statement. A lambda is an e…

I tentatively disagree with both of you.

I've sometimes wondered whether code would be universally clearer if all you could do in a loop is have a one-liner or call another function/method (mainly when looking at my own code within loops and thinking WTF!!!).

Would probably cause issues when teaching programming though. It would be interesting to have a compiler switch that enforced this...

Re: Go + Services = One Goliath Project

#215

Earlier quoted context omitted.

While functions are first class in Go, the limitations of the type system make them less ergonomic to use, I think. Without user defined generics, many of the common uses of first-class functions become a lot less convenient to use.

Do you have an example where that's the case?

One easy example is map functions.

In typescript, if I have a bunch of "User" objects where each user has an "name" and "age" field, and I want to print a comma separated list of all those names formatted as "name -- age", it's simple. I write:

    let userNamesList = let userNames = users.map(u => `${u.name} -- ${u.age}`).join(", ")
    console.log(userNamesList).
This is possible in no small part because map is generic.

In go, to get the same level of expressiveness, I'd have to write the following stuff around it:

    func mapUsersToStrings(f func(u User) string, users []User) []string {
        result := make([]string, len(users))
        for i := 0; i 
And after writing that boilerplate, I can finally write:

    userNamesList := strings.Join(mapUsersToStrings(func(u User) string { return fmt.Sprintf("%s -- %d", u.name, u.age) }), ", ")
That boilerplate, of having to write a specialized map/filter/etc function with a for loop for every combination of types you transform between (mapUsersToStrings, mapUsersToAddresses, mapUsersToAges) is really annoying.

It's harder to point to many other cases because, simply enough, people don't write such cases. The fact of the matter is just that go libraries make very sparing use of first-class functions because the lack of generics prevents it from working well, and so we end up with an entire language ecosystem where code is harder to read and with fewer simple abstractions reused across it.

You can still write any code without good generics or first-class functions, you'll just have more programmers writing more code with less clean abstractions.

Re: Go + Services = One Goliath Project

#216

Earlier quoted context omitted.

Fundamental? IMHO, they are just syntactic sugar on a foreach loop. Which in many ways is bad because it provides yet another way to express the same concept, without a significant difference in the method of execution. What am I missing?

They don’t have to be glorified for loops, even if they usually are. Map and Filter should be capable of running in parallel or asynchronously, and some languages provide this.

And many languages, have parallel for constructs. The openmp #pragma parallel extensions in C/C++ for example. Of course its possible to create constructs which provide the messages passing for clustered environments too.

And maybe that is part of the problem with a generic 'map' your not really sure the underlying implementation, is it parallel, clustered, serial, etc? So you end up with map(), parallel_map(), mpi_map(), etc, and how to you control the parallelism. Do you just let it default or do you have levers to control the batch & interleave. Pretty soon, its not such a simple construct anymore.

Re: Go + Services = One Goliath Project

#217

Ok this is going to sound ignorant, as my only experiences in backend services have been Go and Python. I don't like either. Is there something I'm missing? For simple CRUD apps, both are sufficient. But (in my limited experience), the moment I've wanted to create more complex business logic with stricter constraints, neither has been quite up to the task. Go doesn't make things easy. It asks you to repeat yourself.…

People here don't like C# for some reason, I write really complex business logic with it every day and it is not only easy to write, it is maintainable as well. My own JS code with lot less complexity is way harder to understand after a while.

Re: Go + Services = One Goliath Project

#218

Earlier quoted context omitted.

Everyone’s project/code base is different but in my experience there’s been a critical mass of libraries for a few years. I presume the “it’s hard to move to 3” is dev teams wanting a new toy as much as “the rewrite is too complex”. Library use, size of code base etc are all big factors but at the end of the day, I think team motivation is really the deciding factor.

I worked on a fairly large codebase that needed to be rewritten from scratch when migrating from 2 to 3, primarily because all the tests were written using a test framework that was no longer maintained. So given that you might need to start over anyway, I think it's reasonable to consider other options. That said, yeah it's difficult to understand how KA's web server costs aren't already basically zero, and how thei…

According to their 2018 accounts, 'information technology' costs were $5m. Salaries were listed separately at $29m so I'm guessing the $5m was mostly servers.

Re: Go + Services = One Goliath Project

#219

Earlier quoted context omitted.

The lack of multi-line lamdas is one of my biggest gripes with python.

If you feel the need to use a multi line lambda you should be using a regular function. This is a code smell for sure.

Multi-line lambda is not code smell.

There are a lot of cases like GUI programming where you need a lot of handlers which are suitable for lambda because they don't have a good name, and should never be called manually, and often they have multi-lines of codes.

Re: Go + Services = One Goliath Project

#220
post #128

As much as I personally don’t enjoy writing Go I really can’t fault them. I still find it interesting that for a relatively obvious feature set of fast compiles, fast startup and fast runtime there really isn’t anything mainstream out there to compete with Go. I really hope something like Kotlin, Swift, ReasonML or even AOT JVM/.NET brings something to the table soon. Or perhaps I’ll just have to wait for WASM to rea…

in production is fast startup really such a boon outside of serverless? especially if you're already doing blue/green deployments, doesn't seem like it'll have much impact.

(depends what "fast" vs "slow" means - are we talking about milliseconds vs a second or two, or startup times so horrendous they cripple your devs' ability to iterate and tests?)

Post reply on HN