HN user

mattarm

280 karma
Posts0
Comments84
View on HN
No posts found.

Makes me wonder if the hardware engineers look at software engineers and shrug, “they don’t really know how their software really works.”

Makes me wonder if C programmers look at JS programmers and shrug, “they don’t understand what their programs are actually doing.”

I’m not trying to be disingenuous, but I also don’t see a fundamental difference here. AI lets programmers express intent at a higher level of abstraction than ever before. So high, apparently, that it becomes debatable whether it is programming at all, out whether it takes any skill, out requires education or engineering knowledge any longer.

Yeah, the online Gemini app is not good for long lived conversations that build up a body of decisions. The context window gets too large and things drop.

What I’ve learned is that once you reach that point you’ve got to break that problem down into smaller pieces that the AI can work productively with.

If you’re about to start with Gemini-cli I recommend you look up https://github.com/github/spec-kit. It’s a project out of Microsoft/Github that encodes a rigorous spec-then-implement multi pass workflow. It gets the AI to produce specs, double check the specs for holes and ambiguity, plan out implementation, translate that into small tasks, then check them off as it goes. I don’t use spec-kit all the time, but it taught me that what explicit multi pass prompting can do when the context is held in files on disk, often markdown that I can go in and change as needed. I think it ask basically comes down to enforcing enough structure in the form of codified processes, self checks and/or tests for your code.

Pro tip, tell spec-kit to do TDD in your constitution and the tests will keep it on the rails as you progress. I suspect “vibe coding” can get a bad rap due to lack of testing. With AI coding I think test coverage gets more important.

See https://abseil.io/tips/ for some idea of the kinds of guidance these kinds of teams work to provide, at least at Google. I worked on the “C++ library team” at Google for a number of years.

These roles don’t really have standard titles in the industry, as far as I’m aware. At Google we were part of the larger language/library/toolchain infrastructure org.

Much of what we did was quasi-political … basically coaxing and convincing people to adopt best practices, after first deciding what those practices are. Half of the tips above were probably written by interested people from the engineering org at large and we provided the platform and helped them get it published.

Speaking to the original question, no, there were no teams just manually reading code and looking for mistakes. If buggy code could be detected in an automated way, then we’d do that and attempt to fix it everywhere. Otherwise we’d attempt to educate and get everyone to level up their code review skills.

Some popular streamers have dabbled in OCaml this year, sometimes calling it "the Go of functional programming", which probably set off a small wave of people tinkering with the language. OCaml has also gotten gradually better in recent years in terms of tooling, documentation, standard library, etc.

In my experience learning a bit of OCaml after Rust, and then looking at Haskell, the three aren't all that different in terms of the basics of how ADTs are declared and used, especially for the simpler cases.

Bad example. Google docs doesn’t use CRDTs but uses OT instead. CRDTs may handle your scenario just fine depending on how they decide to handle this scenario.

The CRDT may pick one or the other replacement word, but who is to say that either choice is correct? Perhaps including both words is correct.

Then there’s not even a merge conflict...

Agree, this is what CRDTs are all about.

...to really worry about.

I think it is important to make clear that CRDTs do not "solve" the merging problem, they merely make it possible to solve in a deterministic way across replicas.

Often, CRDTs do not capture higher level schema invariants, and so a "conflict free" CRDT merge can produce an invalid state for a particular application.

There is also the example above, where at the application level, one particular merge outcome may be preferred over another.

So, it isn't as simple as having nothing to worry about. When using CRDTs, often, there are some pretty subtle things that must be worried about. :-)

I don't agree that a missing "framework" is the whole of the problem. It just isn't that simple.

Sure, people need to use resiliency skills to cope with the stresses of life. Often times, this is an important part of what therapy for depressed people is trying to achieve.

But this isn't to say that there isn't a constellation of causes in recent decades and years that cause the world to be particularly stressful, especially for young people. It also isn't to say that we should dismiss what is occurring in the world today as "the same old stuff" without acknowledging that it may actually have unique properties worth understanding. Off the top of my head: world population is at an all-time high, global warming is becoming increasingly understood, it is increasingly acknowledged that we can no longer simply extract unlimited resources from the earth to solve all problems, the Internet has changed the way the world works that seems to speed everything up: communication, changes within social groups, larger societal shifts, economic change, etc.

It's much more a matter of whether you want to do something small scale and fun, or whether you want to suck all the joy out of it by applying the same soul crushing constraints we already get paid to do in our day jobs. Bleh.

Amen. And further, what better prepares a programmer to assess the relative costs of implementing a thing vs using a library providing that thing than having attempted an implementation?

Learning by doing is a valid approach, and this can even be called fun.

Causal Trees 3 years ago

Definitely interested in how you achieved another 2-10x over the btree approach. I want surprised that btree was as effective as it was, but I’d be curious to know how you squeezed a bit more out of it.

Those are good things to consider in review, but I maintain that the answer might be "no" to one or more of those questions and still be acceptable.

I'm old enough to have worked in the pre-code-review era. Things were fine. People still learned from each other, software could still be great or terrible, etc. It wasn't appreciably worse or better than things are today.

An implicit question in several of the above is "will this set a good example for future contributions?"

Which in my experience can be an almost circular requirement. What do you consider a good example? As perfect as perfect can be? Rapid development? Extreme pragmatism?

The more experienced I get, the less I complain about in code review, especially when reviewing for a more junior dev, and especially for frequent comitters. People can only get so much out of any single code review, and any single commit can only do so much damage.

Put another way, code review is also about a level of trust. Will the committer be around next week? Are they on the same team as me? If yes, give them some leeway to commit incremental work and make improvements later. Not all incremental work need occur pre-commit. Mention areas for improvement, sure, but don't go overboard as a gatekeeper.

Things are obviously going to be different when reviewing code from what amounts to a stranger on a mission critical piece of code, etc.

Given equivalent data stored in both JSON and BSON format I would expect them both to compress down to blobs of roughly equivalent sizes. This is because both encode roughly the same amount of information, so the compression algorithm will tend to compress down to the same final result. I haven't run this as an experiment though..that would be fun.

I am more excited by Emacs 30, mostly I like the ahead of time compilation of Lisp code.

Emacs has had an ahead of time compilation feature, "Native Compilation," since Emacs 28. Is this what you mean? Or is the Emacs 30 feature something different?

There is always an authority structure in these kinds of companies. I'm personally familiar with Google, but this description of Facebook makes it sound similar...

The upside is that people, in theory, don't need to wait to be promoted to (attempt to) have an outsized influence on what actually happens on their team, in their org, etc. The downside is that the "real" power/influence structure can be a more nebulous/social game, rather than something concrete that is diagrammed out in a visible org structure. It was often said at Google that you get promoted to level X after already doing work at that level, which implies that the people with influence are running around influencing/leading before they've been anointed with an official title that "gives" them authority.

Reading Carmack's letter, it sounds like he consciously chose to prioritize his personal programming/engineering work over his social/influence/leadership at Facebook. In all my observations, past a certain level, you kinda have to choose one or the other. Both are valid choices.

Which is why unless is such a hard concept for people to grasp, not just in code, but also in regular English.

This is the first I've heard about this confusion over the word "unless" in English.

In spoken English I do notice that most often the "unless" comes after a statement. Example: "I'll be there on time, unless the bus is late." That is more clear (to me) than "I'll be there on time, if the bus is not late." Maybe not by coincidence, I tend to like "unless" when it follows the action in in Ruby code, too.

nix unlike all other distros can install multiple version of the same package

The above is sometimes true and sometimes not. For the most part, Nix can install multiple versions of a program but only one can be in use at any given time.

Nix is for the most part shell based workflow (as in bash, zsh, etc.). The `nix-shell` command lets you switch out the packages (and versions of packages) that are used in any given shell, but it works off of a configuration file written in the Nix language that you write. The programs that are available are controlled by environment variables such as PATH and MANPATH.

Nix is a big shift from the usual way of dealing with packages, programs, etc. It isn't really useful until you really make the effort to understand what is going on, learn the Nix language, etc. If you are not interested in "programming" your system, then it probably isn't for you.

Exact opposite. I ask them to please not bring me a mashed vegetables patty and call it a burger. It is not.

I can agree that "mashed vegetables" does not describe a good veggie patty. I don't agree that a good veggie patty fails in "burger" format.

I can easily imagine that some people have simply never tasted a good veggie patty in "burger" format, because they are rare.

This is the root of most "meat alternatives" in average restaurants -- much of the restaurant world hasn't figured out that providing vegetarian options isn't about finding equivalent "meat replacements" but instead about cooking up options that stand on their own and taste great.

While Impossible and Beyond displaced the meat alternatives

In my experience the "meat alternative" patties have not displaced the good veggie patties in the restaurants that had good veggie patties to begin with.

...that doesn't mean you have to go meat in a vat at home, you can do products such as Morningstar Farms Grillers Original, or maybe Boca All-American Flame-Grilled Burger. Those taste stack more reasonably with what goes on a burger than the mashed vegetables patties, without the weirdness (fake blood look, why?) of Impossible or Beyond. Your local diner will probably be happy to stock them as they're simple frozen goods.

A beef burger patty has the wonderful property that it is simply made of meat -- a good beef patty has no ingredient lists because it isn't a packaged food.

A good veggie patty is also made on site of simple whole foods, in the same way a good burger is and in the same way any other good meal is.

Any frozen puck taken from a bag and slapped on a grill fails the test, be it comprised mostly of beef, soy, beans, "beyond beef", wheat, or whatever. Those things are about convenience, not taste.

An automobile recall is a good analogy here.

Most people driving cars with an active recall are unaffected by the problem the recall is supposed to address. They can drive on blissfully unaware that something could go wrong. They might even enthusiastically recommend that others purchase the car they drive.

For a few people, they'll experience a failure, possibly a dangerous one.

And this is the root of the problem. The fundamental concept of using a language prone to UB exposes all programs to a small risk. In isolation, the risk is small. In aggregate, the problem is real.

SSHGuard 4 years ago

Two terms: undefined behavior and memory safety. Try searching the web for those terms.

I don't think "DMD is a reference compiler and not meant as a production tool" is a great way to characterize it. There are certainly valid reasons for choosing LLVM and GCC for "production", but also valid reasons for choosing DMD.

Ooh.directory 4 years ago

Just like the awesome lists on GitHub.

My thought exactly, and also why I don't just search 'latest news' on Google every morning. Human curation is a thing. (not sure how much human curation goes into ooh.directory, but I'm pretty sure they don't use Google's ranking algorithms to surface links)

I wouldn't say Google's VCS solves all problems. I worked there for years and was constantly looking toward git (or something like it) as a way of managing code I was developing before committing it to the monorepo.

Google's primary internal VCS was originally Perforce (https://www.perforce.com/) and when rewritten to scale to the size of their monorepo largely retained the same user experience. You can read about that here: https://cacm.acm.org/magazines/2016/7/204032-why-google-stor.... Perforce's user experience isn't too different from svn. It is easy because it is a simpler model, and was available from Perforce as far back as the 1990s. You simply can't get into the same kinds of quagmires that git allows you to get into. It is also not a DVCS, which simplifies a lot of issues.

That said, Google's internal Perforce clone doesn't offer any sort of stack/queue of local commits that you can send off for review and continue building on. You've got one copy of your edits and that copy is not under any real version control. For a company that highly prizes code review there was always a tension between sending small-enough changes off for review and continuing to make progress on a larger feature. At the time I left a few years ago there was a staffed project building a Mercurial layer on top of the monorepo VCS that allowed for DVCS-like workflows, such as a local patch queue with multiple dependent changes out for review simultaneously. That little bit of exposure to Mercurial was enough for me to realize that being a DVCS doesn't necessarily require exposure to all the "bare metal" paper cuts that git exposes you to.

Good UI on top of git definitely makes using it more bearable day to day, but I don't think it "fixes" git's fundamental flaws (those talked about in the posted link). That said, to some degree git is just an assembly language for a DVCS without a truly usable high level interface on top of it (yet).

Leaving comments is a different kind of participation than curating a personal website. The assertion originally under discussion here (a few posts back) is that most people don't care to curate their own personal website, or, really, any sort of distinguished online identity. I think that is true. Most people are on Facebook/Instagram/Nextdoor/whatever are doom scrolling it, not trying to become an influencer. The assortment of people leaving comments on NYT, Amazon reviews, or chattering on a forum somewhere, or whatever else, are doing just that, but not trying to drive traffic to their personal home page.

Idiot Proof Git 4 years ago

A rebase creates new commits from old commits semi-automatically. Git then has no permanent record of the old commits, and even if you want to get back to them right away it requires some delicate git surgery.

This is why you can't generally share work using a rebase workflow.

It is not a big deal in practice in most every case, but in a version control system it is a little bit odd that rolling back such a fundamental operation isn't a first class feature.

5 Years of Pop _OS 4 years ago

Nothing structural about the way NixOS works at a technical level prevents it from being as stable and battle tested as Debian Stable, but it isn't in practice by my experience.

I would bet money that most people who are singing praise for NixOS have sunk significant time into absorbing the whole NixOS way of doing things, learning the Nix language, tinkering with their machine config, diagnosing non-trivial problems, etc.

It is just a smaller community and younger project. NixOS is nowhere neat as stable. The security story is, comparatively, simply not present (e.g. there is no equivalent of https://www.debian.org/security/ that I can find). The user base is tiny in comparison. Packaging up stuff for NixOS often requires non-trivial patches, downright hacks, or wrapper scripts for binaries that can break assumptions made by upstream and lead to little paper cut issues.

NixOS is many things, but it isn't a Debian Stable. They fill different roles. Debian is a mainstream distribution, and the problems you'll have will be similar to the problems most people have, so you'll be swimming with the tide and be able to find help. I see NixOS more as a rolling release distro that gives you a mechanism and programming language to control configuration and rollback, but a lot of those 80K NixOS packages are just kinda sitting there packaged up in a way that kinda worked at some point but isn't really solid.

I use Nix as a package manager on top of Debian, to bring in development tools, etc. This is relatively easy. When I tried using it as an OS I had to spend way too much time figuring out weird issues.

Casting from any T* to void* back to T* is always safe. That is one of the few safe things you can do with a void*, and kinda the whole point. :-)

I think casting from void* back to double* is the better option here. memcpy() is overkill here since that idiom is mainly for reinterpreting data with a different type without triggering undefined behavior: https://stackoverflow.com/questions/98650/what-is-the-strict.... We're not changing the type, so why confused people with an overly powerful idiom? That said, the memcpy() idiom is common and useful enough that C++ added a specific API for it: https://en.cppreference.com/w/cpp/numeric/bit_cast.

Casting and the memcpy() idiom compile down to the same code https://godbolt.org/z/xY6W9ja69*

Casting should be safe as far as I know

I assume you're talking about this:

    long x = <whatever>
    double y = *(double*)&x;
Nope, it is undefined behavior, with few exceptions, even if sizeof double == sizeof long. See https://stackoverflow.com/questions/98650/what-is-the-strict...

If you got rid of this rule a huge number of optimizations would be lost, since the compiler would have to assume that any memory, of any type, could change if anything at all is modified through a pointer. You'd be surprised how slow everything would be. You'd also be surprised how much code violates this and gets away with it. Time bombs waiting to happen. ;-)

memcpy(), and more generally accessing bytes through char*, are how you avoid this kind of undefined behavior. It comes up so often that C++20 added std::bit_cast for this same use: https://en.cppreference.com/w/cpp/numeric/bit_cast