HN user

jpollock

2,698 karma
Posts1
Comments755
View on HN

I prefer the second. :)

It's about the cognitive load and having to follow branches.

The second version minimizes the cyclomatic complexity, taking it to 1. The reader doesn't have to keep the if statement in mind when reading through the code, and doesn't have to worry about all the ways the code can get there if they want to modify it (e.g. to add logging, metrics, other logic).

Whether or not consume should be a separate function depends on how often it's called. Here, I'm guessing it's once. :)

This matching up with sliced data, either sliced by recipient, or sliced by sender, so it makes sense to have primary state with cool backups. Particularly if the state is race-tolerant.

As long as event orderings are unimportant, or self resolvable this works really well.

e.g. if Events A,B arrive, but A+B => C and B+A => C, then as long as you durably record A, B, the end state is the same.

I'm not sure why "reroute" is a message instead of a response, I would expect it to be a failure response pruning the control flow. With the GTR being "default retry".

There's a lot of learned experience in that doc. Reading between the lines, both the logging and configuration systems have caused global outages (or near misses). Nifty to read.

This style of architecture fits with a "no global changes" and "never lose it all" approach to fault tolerance, accepting that there will be visits from "Mr. Cock-up" [1].

Very nice writeup.

[1] https://www.youtube.com/watch?v=D5r8xwu0l8w

Yesterday. I was reviewing for an exam and came across a bug in the profs text. I took a screen shot pasted it in the prompt and asked. It initially agreed with the Prof, then checked it's work, revised and agreed with me, all while showing the work it did.

I was able to see why it got confused at the start, attempt to confirm, fail, and then calculate from the data and come to the opposite conclusion.

If your data is naturally sharded (users) with writes happening within a single shard, parallelism becomes easy. The request is routed to the shard hosting the user's data and reads/writes locally.

This makes scalability _much_ easier to reason about. It's cut-paste, cut-paste. Every N users needs another shard.

It does buy you a _different_ set of problems, like cross-shard querying (analytics) and how to do load leveling as users age out.

But it avoids the whole shared index scaling problems from inserts/updates with large user counts.

It becomes a hierarchical instead of a relational database.

Glancing through the study, I'm curious about both sample bias, and the lack of formal measurement. I'm not an expert in this type of thing, not even an amateur. I'm poking holes to see what's left.

"Participants were identified via media reports featuring Australian firms trialling the 100:80:100 model, in addition to companies listed on recruitment sites that specialise in 4DWW jobs. In other instances, eligible organisations were recommended by the participants themselves."

I'd expect organisations with positive results will be the ones recommended by other participants - "talk to these people, it worked for them too!"

I'm also interested in whether or not organisations converted all staff to 100:80:100, or if it was optional. Is the performance driven by peer pressure?

Finally, the participants' measures of productivity will have significant lag time in them, so it depends on trial's length, e.g. "revenue", "profit", "csat", "projects delivered on time", "net promoter score".

Table 1 has "Duration", but the units are unlabelled, if it's weeks, it's less than a year, months is probably better for seeing performance changes.

It's an interesting qualitative study, I'd certainly like a four day work week with no change in comp.

It's not a single payment failure, it would be multiple days, possibly even a week to 10days.

This is why businesses should put in the effort and sign up for credit terms. Then it's an invoice, and you reduce this risk substantially.

Credit cards are _not_ reliable at this scale. Banks are offline all the time, cards are marked stolen, protocols change, all sorts of things that will cause flags indicating "the money can't move down that path".

Businesses that pay for AWS/Cloud/etc via credit cards are trying to buy reliability but put it behind a single point of failure.

Credit cards are not how you should be paying for business services with uptime requirements!

There would have been efforts to contact them, but it would have been via their contact method, aka the email they set it up with.

Common ways this happens? They are using a credit card to run their business with no backup payment method. Then the company's contact person is on vacation.

Sign up for terms. It will get you payment terms!

Do any refactorings in separate reviews, and say things like "REFACTOR_ONLY:", with a rule that none of the code changes behavior.

That makes reviews a lot easier. The review starts from "nothing should be changing" and then reviewers can pattern match on that.

Otherwise, the reviewer is re-evaluating every line of code to make sure nothing has changed. That's really hard to do properly.

The version control systems I've worked with have allowed queues of changes, each one reviewed independently. As I'm developing, if I need a refactor, I go up a commit, refactor, send out for review, rebase my in progress work and continue.

I send out a continual stream of "CLEANUP:" "REFACTOR_ONLY:", and similar changes with the final change being a lot smaller than a big monster of a change.

Your reviewers will appreciate the effort.

Plays the metric game (if you're working in that type of org) without being evil too.

Well, I think there are two things at play here.

1) As org size grows, it's the team's average quality that matters (so yes, large numbers).

2) Even with a single team, the velocity will increase to match the acceptable level of quality.

Management will push the accelerator until they get too many bugs, then it will be "we need fewer outages".

So, in an team+environment, you end up with a constant (in time) detection rate, which basically means a constant in time injection rate.

If the teams' velocity increases without increasing quality, the bug injection rate (and detection rate) will increase.

AKA if the AI is slightly worse, but 10x faster, stop carrying the pager. :)

Yes, that is what is required. Every dependency needs an internal owner and reviewer. Every change needs to be reviewed and brought into the internal repository.

If no one is willing to stand up and say "yes this is safe and of acceptable quality", why use it?

It's a software engineering version of the professional engineering stamp.

Faults are injected into the code at a constant rate per developer. Then there's the intentional injections.

Auto-installing random software is the problem. It was a problem when our parents did it, why would it be a good idea for developers to do it?

Code you ship vs tooling you use to build the code.

So, the product vs everything that is needed on the way, but isn’t the core.

CI/CD tooling, template population…. Things you write a use once/use few script for.

I typically end up with a library of tools to deal with repetitive finicky tasks.

You are communicating with future readers of the code. The presence of ConcurrentHashMap will lead future engineers into believing the code is threadsafe. This isn't true, and believing it is dangerous.

That's deterministic dispatch, as soon as it forks or communicates, it is non deterministic again?

Don't you need something like a network clock to get deterministic replay?

It can't use immediate return on replay, or else the order will change.

This makes me twitchy. The dependencies should be better modelled, and idempotency used instead of logging and caching.

Yes, it sets the reviewer's expectations around how much effort was spent reviewing the code before it was sent.

I regularly have tool-generated commits. I send them out with a reference to the tool, what the process is, how much it's been reviewed and what the expectation is of the reviewer.

Otherwise, they all assume "human authored" and "human sponsored". Reviewers will then send comments (instead of proposing the fix themselves). When you're wrangling several hundred changes, that becomes unworkable.

The last time I tried AI, I tested it with a stopwatch.

The group used feature flags...

    if (a) {
       // new code
    } else {
       // old code
    }

    void testOff() {
       disableFlag(a);
       // test it still works
    }
    
    void testOn() {
        enableFlag(a);
        // test it still works
    }
However, as with any cleanup, it doesn't happen. We have thousands of these things lying around taking up space. I thought "I can give this to the AI, it won't get bored or complain."

I can do one flag in ~3minutes. Code edit, pr prepped and sent.

The AI can do one in 10mins, but I couldn't look away. It kept trying to use find/grep to search through a huge repo to find symbols (instead of the MCP service).

Then it ignored instructions and didn't clean up one or the other test, left unused fields or parameters and generally made a mess.

Finally, I needed to review and fix the results, taking another 3-5 minutes, with no guarantee that it compiled.

At that point, a task that takes me 3 minutes has taken me 15.

Sure, it made code changes, and felt "cool", but it cost the company 5x the cost of not using the AI (before considering the token cost).

Even worse, the CI/CD system couldn't keep up the my individual velocity of cleaning these up, using an automated tool? Yeah, not going to be pleasant.

However, I need to try again, everyone's saying there was a step change in December.

There are definite discontinuities in there. What works for a team of 5 is different to 50 is different to 500.

Even just taking fault incidence rates, assuming constant injection per dev hour...