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

Insightful article. The author makes some great points about the dynamics of technical debt in organizations.

I think a sinking ship is a reasonably good metaphor though. A sunken ship is a horrible, terrible outcome.

In the metaphor, a codebase is sunken when it’s unviable to continue using it. The organization stops working on it and no longer runs it. At this point, the code is completely worthless to the business, like a ship at the bottom of the ocean. True, you could imagine the code getting worse theoretically. But in reality, it will just sit there and rot.[0] The business might attempt a rewrite or just discontinue the product.

It’s possible, but not a given, that a business sinks with one of its codebases. This can happen with a ship too, if a business relies heavily on it.

[0] https://en.wikipedia.org/wiki/Software_rot


There’s some interesting information in there. Unfortunately the person or LLM writing this got pretty confused right in the introduction already.

> “Suppose […] they type straße and you’ve stored STRASSE. To make these count as matches, you need […]”

Really bad example, because as the article says later on, this casefold crate won’t match those two strings because the ß → ss conversion isn’t done.

> “[str::to_lowercase and case folding] diverge on real characters—ß, İ, final sigma”

The main point is true (case folding is different from lowercasing), but two of the three examples are wrong. The casefold operation that they use maps ß to itself, as does str::to_lowercase. The casefold operation maps İ to U+0069 U+0307 regardless of locale, as does str::to_lowercase.

When I’m reading an article, these kind of mistakes in the introduction make me doubt the accuracy of the whole article. Which is a shame, because again, it’s an interesting write-up. The mistakes also make the article harder to follow, since the examples imply ß is folded to ss.


Too late to edit, but the situation with İ is more complicated, and I got the mapping wrong for this specific casefold implementation.

What I should have said is that in the case of İ/i/I/ı, using str::to_lowercase for string matching wouldn’t be any less correct than using their locale-independent casefold.

The third character in the list, final sigma, is a good example that illustrates why using str::to_lowercase for string matching isn’t good.


If anything, the word STRASSE is a great example why case-folding followed by string comparison is not the same as a case-independent string comparison

Or if you really want to do it, your case-folding needs to map certain lowercase characters to to other lowercase characters (lowercase ß to ss, lowercase ı to i, etc), losing some of the meaning


> If anything, the word STRASSE is a great example why case-folding followed by string comparison is not the same as a case-independent string comparison

s/case-folding/lowercasing/

Proper Unicode case-folding absolutely does map ß to ss, ς to σ, etc. Moreover, there are some scripts (IIRC Georgian) where for historical reasons case-folding yields uppercase letters, not lowercase ones. The case-folding mapping is specifically designed in concert with the comparison rules to yield the same result, that’s why it’s a separate operation from lowercasing.

(I believe the thing described in TFA is supposed to be proper case-folding in that sense, but given TFA is AI-written I wouldn’t trust its descriptions either way.)

That said, if you want to match the sort order customary in a specific language, you need to use language-specific rules for producing collation keys rather than generic case-folding. There’s no way out of this because different users of e.g. the Latin alphabet want contradictory results. And if you think you do want generic casefolding, then you probably actually want NFKC_Casefold instead unless your input is pre-normalized.


In some cases your're also lost ng all of the meaning. For example: aß/Ass, Maß/Mass, Buße/Busse, Floß/floss


  Location: Europe (UTC+2)
  Remote: yes
  Willing to relocate: no
  Technologies: Python, SQL, C, Java, Go, PHP, JavaScript, Typescript, Claude Code, Analytics, Git
  LinkedIn: https://linkedin.com/in/lukas-gelbmann
  Email: me@lukasgelbmann.com
Senior software engineer, experienced with backend engineering, databases, data analytics, application security, web applications, and fullstack development.


> There are 349 million people in the US, so the number of arsonists is 0.0001% of the general population. The number of firefighters that are arsonists (100/65,795) is 0.0015%, so I suppose it's slightly higher that the general population.

You comparing arsonists/pop with firefighter-arsonists/arsonists. That’s the wrong comparison. You should be comparing arsonists/pop with firefighter-arsonists/firefighters. Or firefighters/pop with firefighter-arsonists/arsonists.

(On top of that, mixing numbers from different sources can be problematic. For example, how are repeat convictions treated in the different sources? Who counts as a firefighter?)


Author here.

Our aim isn’t to try and line up with the calendar that was in use at the time, 2026 years ago.

Instead, the aim (for 28times) is to implement the rules of the proleptic Gregorian calendar[0] correctly. The bug was that those rules weren’t followed for some rare values.

But to address your comment properly, I think I should justify why on Earth someone would want to use the proleptic Gregorian calendar for year 0 and before. In short, because it’s a useful fiction.

The biggest reason is interoperability: a lot of software follows proleptic Gregorian rules, aligning around ISO 8601. Probably a clear majority of date/time software. We want to line up with all that existing software that assigns a specific meaning to a string like "0000-02-01". That’s the first of February in the proleptic Gregorian calendar, even though it was a different date in the ancient Romans’ calendar.

The other reason is to keep it simple: since most people use the Gregorian calendar in present times, it’s simplest (for us as implementors, but also for users) to extend its rules into the distant past and distant future. The alternative for be to have multiple sets of rules, e.g. Julian and Gregorian calendar. (You might say it would be even simpler to just not allow timestamps before 1582. But there are use cases, e.g. in astronomy or history, where people want to work with timestamps before 1582, and even before 1 AD.)

[0] https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar


I’m working on a time series management & analysis tool. The goal is to provide simple ways to work with time series data, including an API and visualisation.

https://28times.com


> “If you run this on a big repository, it will take quite a lot of time because `git log -n1` takes a long time. I think this is the fastest way to get the most recent commit time on a single file? (That's the assertion that I hope someone can correct me on!) In any case, `bttf tag exec` is using parallelism under the hood to make this even faster.”

Instead of running `git log -n1` on every file, I think you can walk through the commits backwards, skipping any files that have been seen. Something like this (these two commands could be followed by bttf commands):

  git log --pretty=format:"DATE:%aI" --name-only |
  awk '/^DATE:/ {date=substr($0, 6); next} $0!="" && !seen[$0]++ {print date, $0}'
This seems to run much faster. The only problem is it'll include files that have been renamed or removed. I got an AI to fix that too, but it starts getting awkward (still fast though!):

  git ls-files |
  awk '
    # Read all existing files from git ls-files into an array
    NR==FNR { lsfiles[$0]; next }

    # Process the git log stream
    /^DATE:/ { date=substr($0, 6); next }
    $0!="" && ($0 in lsfiles) && !seen[$0]++ { print date, $0 }
  ' - <(git log --pretty=format:"DATE:%aI" --name-only)


Oh interesting! That is indeed quite a bit faster.

I'll have to noodle on this one. `bttf tag exec` works with arbitrary commands that can print any kind of date. But your approach require a different access pattern. I can either specialize the use case in bttf (blech) or I can figure out how to generalize your approach.

I think the key issue here is probably that it isn't line oriented. bttf composes well, but only when you have a one-to-one relationship between date and data. (Or a many-to-one is also supported, but it's many dates to one datum, not one date to many datums.) So maybe that relational model is worth figuring out how to streamline. Then I think this use case would work better.

Also, thank you! This is exactly the kind of reply I was hoping for! :D


With 3, especially if the animals outnumber humans, you’d first want to do some research into animal psychology to see whether red or blue has an edge for animals.


There’s a moral benefit to choosing blue if you think there’s a chance that the end result will be split 50-50 and you’ll be the deciding vote between a blue majority and a red majority.


There's an argument to be made that anyone choosing blue wants to die and you should respect their choice.


I think it would be hard to prove you, individually, were the deciding vote to blue.

Everyone who voted blue in such a case could think they were the one vote. And they could be right.


If you’re using a model, it’s your responsibility to make sure the probability actually is that small. Realistically, you do that by not giving the model access to any of your bloody prod API keys.


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

Search: