I don't really see this as analogous. Yes, you do choose an abstraction level to operate at, I rarely think in terms of transistors, or even gates (which by your logic an assembly programmer should do).
But I often do think across adjacent abstraction levels, because abstractions are (varying levels of) leaky. Modern compilers are after many decades good enough and modern computers fast enough that it is rare that I need to dig into the assembly (but I happens, compiler explorer is in my bookmark bar in Firefox).
Other abstractions are far leakier, it is far more common that I look in wireshark to debug network issues, the application level view is often not enough.
One of the leakiest abstractions currently is LLMs. Maybe in a decade or three they will be good enough, but they aren't yet, that's for sure. At least for the hard realtime systems level programming I do. For code generation they often make enough mistakes that the time spent after review and fixes comes out in the wash, even for simple tools. Their use for bug finding, RAG and similar is however promising.
My lived experience over the past few months is proving you wrong. I started with your position and have since been able to see how good the tools are when properly used. I've also noticed a huge gap in ability among engineers and I think the gap is widening. My theory is that some folks have the premium tools and some don't and the ones that don't are sort of in this weird limbo where they are sort of stubbornly annoyed at the idea of having to pay for these things so they lash out. Understandable but ultimately self defeating. You can in-fact force the LLM to use any pattern you want. I encountered this recently with a hand made framework I wanted to upgrade. It did stuff I didn't like. But well guess what? I provided it new constraints and it started to do what I want. Be as opinionated as you want. That's the whole point. It's basically your intern.
> My theory is that some folks have the premium tools and some don't and the ones that don't are sort of in this weird limbo where they are sort of stubbornly annoyed at the idea of having to pay for these things so they lash out.
At my last job the employer paid for OpenAI access for all of us.
Baby sitting an LLM is not my idea of meaningful use of time. And reviewing code that someone else had an LLM spew out even less so.
I am not lashing out because I don’t have access to LLMs. I had access and I did try it plenty.
This is really low effort man. You can do better than "You're not paying enough to be as good as me" followed by "oh...well you haven't paid this month."
When I encounter people who don't use these tools it feels more like talking to someone without a computer who is trying to convince you that you don't need one back in the 90s. Or someone being like "the internet is useless" back in 1995. I mean early days it was kinda like that. The early internet for normies was almost entirely useless.
The change has been so rapid that I think a lot of people are having a hard time I guess wrapping their head about the lived experience of it. For a while my only access to the tools was through work. Then I ended up getting a $20/month ChatGPT account and that comes with codex and now I can't imagine sitting there Googling a problem anymore. It literally feels low tech these days. Big "I'm not paying for Cable, the antenna is good enough" energy. It saves me soooooo much time just maintaining my own local stuff. I mean it literally saves me hours and hours of personal labor.
The local models will 100% catch up. Most likely the inference I use now will be free in five years across the board and you'll be buying a cyberdeck or something with a 128G of RAM and an LLM friendly bus architecture.
> When I encounter people who don't use these tools
But you didn't encounter those people. People said they've used the tools, and then you said it wasn't recent enough. Not because you know when they've used it last, but because their experience didn't match yours.
It's great that it's working for you, really. But since you have been posting on HN a lot about this, while simultaneously claiming you don't care what other people do, maybe consider a different approach than calling everyone luddites. If people call you a shill, and you exit the conversation claiming you don't care, but then you go to the next thread doing the same low effort stuff, don't be surprised when people see a pattern. There are lots of people communicating more effectively about this.
Don't confuse the cost of org wide LLM services with coding. Two different things. Most people at any org probably just want ChatGPT so they can write reports and do research. And now they want it to sync with Google Drive or w/e so they can pull in docs. Obviously that stuff is classic B2B Software as Service hosting. Prices will go up just because that's how B2B prices work when enterprises negotiate yearly services but overall it's not the most expensive line item by a long shot and power users are only a small sub set of the population of all the users.
But for code it's a race to the bottom because it's all text and local works quite well. You can host models on LangSmith and similar and because people use those services to create chat bots the overall use of them for coding is a very tiny fraction of their overall usage. The race to the bottom is further exacerbated by the fact that as GPUs become more powerful you can host more per unit so the cost of text inference will drop precipitately. Right now people are reporting that for some of the self hosted services they are able to do everything for under $5 / month. That price WILL drop because that's how computers work.
> I'm sure they were blindly accepting the Assembly coming out of the compiler.
The fact that you consider deterministic output from a compiler the same as probabilistic output from a LLM makes me think you don't know how either of those things work, even at a very superficial level.
Compilers are orders of magnitude more reliable than LLMs. There's a reason the saying is "it's not a compiler error".
I have a standing challenge to my co-workers that valid compiler errors will be rewarded like a birthday party, with the baked goods, alcohol, or sweets of their choice. It's only been redeemed once, and I've found less than a dozen unreported compiler bugs myself.
Where do you think those bugs reports for gcc and others come from? Some people do look at the assembly coming out of the compilers.
Currently the openbsd mailing list for port is currently going through a clang update and one of the main point is looking at all the packages that failed to build. I even took a long look at the usb stack and the audio subsystem of OpenBSD because of an issue I was having with my DAC.
I literally do packaging for a living and you are misunderstanding my point. Most people just take a binary and run it. There's no analysis of the assembly code. You might profile it and bench it after the fact but no one is sitting there looking at the assembly line by line unless there's a very very good reason and frankly LLMs are better at that type of investigative work. I know because I've been investigating some curious 1 in 100,000 segfaults recently and guess what? It took an LLM to build a tool to let us even hit that bug because it was basically impossible to do by hand and no one in the before times would have sat down to write the tool cause we would not have time so we would have just accepted that 1 in 100,000 requests are segfaulting. At least now I can actually fix the problem.
What's the reliability of compilers this day? How likely for a bug to be in your code and not in the compiler? I think it's close to 99.99...
So when you have a bug and a core dump, you can quickly load it in debugger, see the stack frame and then theorize a model for the bug to happen. If after verifying the source and having complete confidence that it's good, then you start looking at the assembly, most likely while single stepping with the debugger. But you rarely get to that point, because 99.99... it's your code.
That reliability is what AI tooling is lacking. It's exhausting monitoring the output because errors can be as simple as a minus character or the wrong comparison operator.
I'm usually compiling other people's code. Hitting that 1 in 100,000 issue in run time and then having to come up with patch. And then have to make sure it's okay in arm and amd64. The bug I'm thinking of is decidedly a human output and the LLM is cleaning up the slop.
Once you reach a certain skill level you really didn’t ever visit SO anymore. I basically just live in Postgres, Redis, Ruby and Rails documentation. Still do.
The amount of times that copy pasted code will work verbatim is basically 0. Better to type it out manually so you can tweak it as needed and you understand it better.
I don't think I was ever able to straight copy and paste from SO, everything needs adaptation, and code can often be simplified. And you need to understand your code. SO was useful, but nothing could be used copy pasted.
Maybe this is not the case if you are doing a dozen throwaway websites, but for anything serious that is an absolute requirement. I work in hard realtime safety critical code, think things like brake controllers, medical devices, auto pilots, etc. In my case industrial control systems. You need to have full control and documentation for your development process.
I agree with the notion it's an age thing, but not because I am old, but because the tools are different. When I was learning to program as a kid I blindly 'copied and pasted' from computer magazine. I typed everything in, not understanding what I was doing, and made mistakes. Then came the tedious problem of figuring why the code didn't work. What was the syntax error? Why was it wrong? Why did the computer crash when I poked the wrong memory address?
I learned to debug and built comprehension by typing it in, and built it as a practice. Later in life and career I learned the value of transcription rather than copying and pasting because it at the very least forced me to read and write what I was copying, and built the base and familiarity I needed to learn from what I was copying.
That extends to how I use AI today. I use AI tooling to explore the concept of what I am building, use spec based designs to build solid outlines, and scope individual coding sessions, so that even when I use AI to build it, I have read, edited, and managed the design, and when I run into parts that I don't consider boilerplate I treat it the same way, transcribe what was attempted to understand why it was failing, and make sure I understand what the AI is doing that I haven't done before.
Most code we write is boiler plate nonsense. Writing out React components manually doesn't make me better at writing C. Like it literally is a waste of my time. I could be focusing on "real problems" like the way light diffuses in my simulated atmosphere in my 3D engine. But no I gotta sit there and manually wire up the onclick event for some button or whatever because it doesn't pass the HN sniff test from some pedantic random. Yea trying to fix one of my old job's webpack build for 3 weeks sure did build character. My boss hated how long it took. I hated how long it took. And thank fuck I NEVER have to do it again.
> SO was just an example. If you try to tell me you've never copied/pasted code before I know you are lying.
I've never done that; many experienced devs I know have never done that. We barely used it, in fact! The few times I asked a question, the answer was not "Here's a piece of code".
Look, this comment of yours, coupled with a previous comment from you in this thread (demonstrating you don't know the difference between probabilistic and deterministic output) makes it painfully clear you don't do development; or at least you didn't until you were handed a magic "write me a program" tool...
> Where does this idea come from that good programmers were ever cool with that?
r/programminghumor mostly. It was always tongue in cheek, but people took it too seriously.
However, the number of times I’ve gone over to help a colleague and realized they were trying to copy/paste code from SO, without even reading the context of the thread is baffling. Like, why did you expect it to work in the first place? I really try to be humble and not make assumptions about people competencies but it’s really hard to have those experiences and not think the average programmer is just an idiot. It’s no wonder AI is helping people when this was the baseline.
Some things are easier to verify than they are to solve, right?
So if you see an answer on stack overflow, read it, comprehend it, and you can pretty easily mentally verify the correctness to a sufficient degree of confidence…
> Where does this idea come from that good programmers were ever cool with that?
Copium from folk who were never developers before, but who now want the badge anyway. Too bad the same badge can be given out to a bright 12 year old who doesn't know the difference between a variable and a type.
I suppose I'd have to admit to not being a "developer" anymore, because developers in the age of AI won't know how to write code. Perhaps I can still hold on to the label "programmer" for a little while longer.
> With that Github and personal portfolio I wouldn't be making such sweeping statements.
Where's yours?
After all, my CV (online like everything else) shows almost 30 years in the field, 7 of which as a research scientist, 6 of which was spent writing software for munitions, many of which were spent as an EMV developer, a stint at a FAANG...
All you've done is state the things that very junior devs state, with just as much confidence.
I don't think those two things are comparable, really.
With SO copy/paste, you still were undertaking the mental exercise (and reward) of thinking through hard problems, researching solutions, and assembling it yourself.
With AI, you literally outsource most or all of that. The way some people "vibe code", they barely are engaged with any of that process, if at all.
I think about it like I do video games: it's a lot of fun to play them, and while it can be interesting to watch someone else play, it's just not the same.
I started coding before Stack Overflow existed, and those were the days when coding was most fun for me. Learning HyperCard Basic from the manual that came with the computer was so full of joyful moments.
Stack Overflow had it's heyday, but by the time AI came around I already wasn't using it. Stack Overflow for a long time has been inundated with the kind of people who think everything is the XY problem[1], and arrogantly assume they know what your problem is better than you do. Stack Overflow was all-but-useless for at least 5 years before AI broke into the public eye.
> Pardon my ignorance trying to follow up on what is most likely sarcasm but is this not Kafka's claim to fame?
Yes
> I am joining a new project and need to know to what extent Kafka is still a part of the future for new big data projects.
It's not gonna win or die on merit.
If I were to sit here and propose that you mutate bank accounts in-place (which I'm more or less doing by analogy right now over on https://news.ycombinator.com/item?id=48339103), and you just need safe enough locking technology to do so, I'd be immediately and rightfully shouted down that no one does that and you write down the money transfers and derive the final balances from that.
Manage any other kind of state, however, by appending state-changes and rolling them into a derived state, and then you're chasing fads and doing resume-driven development. So I'm skeptical about the future of this way of doing things.
Two processes intend to add two to a number.
They each read the current value.
Then they each write back the value which is two bigger then the original.
If you instead use private fields and public getters/setters, or use actors to form a protective bubble around the mutable state, you get...
If the read and the write are separate messages, i.e. the computation of the modified value happens sender-side, as in the parent example, then I don’t see how a serializing queue prevents the race condition, for two concurrent senders (clients). For that you need transactions, exactly like a database.
That's not how you would implement mutating messages in an actor system. Instead you could do either of these:
* Have an "increment" message that adds n to the current value and returns the old value.
* Have separate "read" and "write" messages, where the "write" message is parameterized by a timestamp returned by the "read" message. If the owner detects that the timestamp sent by the write is older than the most recent timestamp, it's rejected.
Because messages are handled serially, it's easy and safe to create messages that behave sanely event without explicit locks.
The point is that you have to implement it in the specific ways you describe in order to prevent a race condition. The actor model doesn’t eliminate race conditions by itself. This is true in all programming models. A database also doesn’t eliminate race conditions, you have to use appropriate transactions in order to prevent them. What you describe for the actor model is virtually the same thing: you have to use transactional messages in order to prevent race conditions. And that doesn’t happen by itself, the programmer has to implement the program logic in that specific way. There is no magic silver bullet.
> The actor model doesn’t eliminate race conditions by itself.
Sure, and the actor model was never marketed as "a tool to eliminate race conditions." That's not what it's for.
You have to use your tools correctly. One benefit of the actor model is that the tool eliminates large categories of race conditions (but not all of them). One benefit of garbage collection is that the tool eliminates large categories of memory errors (but not all of them). The same can be said of anything, from high-level languages, to debuggers, to linters, the IDEs, etc. Just because a tool is not a "silver bullet" does not mean that it does not deliver a strong advantage for the programmer.
This is correct, but databases only help to the extent that the whole world is happy to live in your database.
As soon as you have customers (who interact via REST), or partner payment systems (e.g. stripe) you're back to:
Two customers do a GET. This gets dispatched to the DB, wrapped in a nice transaction, the transaction ends, the customers get their result.
The two customers then do a POST to set a new value. Also wrapped in a transaction.
As I pointed out above, that's not the API that would be exposed in an actor model. See in particular the timestamp-based update condition, if you're principally concerned with end-user-caused races.
Less relevant, but message queues in Erlang and related languages are typically in-memory, no DB transaction required.
I can get behind the sentiment, but you absolutely need nondeterminism. You can separate the d from the non-d, but only Haskellish languages even attempt it. It's a coarse separation to make (IO vs non-IO), which is where effect systems come in - I guess you can categorise code into more fine-grain buckets. The 'algebraic' part is currently beyond my knowledge.
No, they are function colouring. That's the point.
Someone writes a post lamenting red and blue functions, and everyone eats it up.
Substitute colour for something meaningful and the idea becomes idiotic.
"Top level function declares that it is non-blocking, but when I try to call a small blocking function from it, I have to change the declaration to blocking???"
How do you handle logging then? If f() calls g(), how can I add logging to g() without having to change or recompile f() (and everything in the call stack above it)? ‘You can’t’ is not an acceptable answer.
Not sure why people are saying "you can't" when it seems to me the whole point of algebraic effects that you can. You can define g so that it has no ability to do "general IO", all it can do is yield log messages. Then f can call g in a way that turns the log messages into writes to stdout. For example, here's how you would do it in Bluefin:
type Log = Yield String
-- workWithLogging cannot do arbitrary IO!
-- All it can do is yield log messages, which
-- must be processed elsewhere.
workWithLogging ::
(e1 :> es) =>
Log e1 ->
Int ->
Int ->
Eff es Int
workWithLogging l x y = do
yield l ("x was " <> show x)
yield l ("y was " <> show y)
let result = x + y
yield l ("result was " <> show result)
pure result
-- ghci> example
-- x was 5
-- y was 7
-- result was 12
-- 12
example :: IO Int
example = runEff $ \io -> do
-- forEach determines how each log message
-- should be handled.
forEach
(\l-> workWithLogging l 5 7)
(\logMsg -> effIO io (putStrLn logMsg))
If `left_pad()` calls `send_env_vars()`, how can you add exfiltration to `send_env_vars()` without having to change `left_pad()` to expose the use of the network?
Yep. But we all know that one machine can and will fail (or be patched and restarted), so the log needs to be distributed.
Different workflows should probably go in different buckets or "topics" for clarity. Since it's distributed, the system must guarantee that the log items are stored in the same ordering ("offsets") among the nodes.
Will concede that, if you can get from "there is no proof of not-god" to supporting any claim about the nature of reality according to faith or scripture.
reply