Human accomplishment is a predictor of future accomplishment. AI not as much.
Human effort signals value, AI does not.
Human effort is often inviting collaboration. AI rarely does.
HN user
Human accomplishment is a predictor of future accomplishment. AI not as much.
Human effort signals value, AI does not.
Human effort is often inviting collaboration. AI rarely does.
I really doubt spec driven development is gonna last. As before, creating working software and iterating on it is faster and makes it easier to understand what you thought you wanted but don't, even if it's vibe coded. So, hello agile, welcome back.
That depends on how many details I specify. If I specify a lot, I usually get what I want. But in the extreme this is just another form of coding (high quality code is quite similar to a detailed spec). In many cases I find I have to do many "passes" to get the right balance of correctness, performance, security, and clean architectural boundaries. Having a loop to fix these often makes it worse since they can often be contradictory.
There's also some types of code that I believe is often wrong in the training data that is almost always wrong in the LLM output as well. Typically anything that should have been a state machine, like auth flows, wizards, etc.
When all is said and done I think the main savings come from the high throughput of low-value generic solutions. I don't currently see this changing, and the reason is that high quality products cannot be generated without specifying a lot of details. Of course, we may not want quality.
Well they then use more AI to try to fix the PR, which leads to many more rounds of the same. It's like I'm coding using an AI except through a real person who mangles the prompt. I've had some success as well in talking people out of it, but it feels like I'm gonna lose eventually
It is everywhere. Even on birthday invites for my kids there's nonsense from an LLM. At work I review PRs with code that doesn't even run. Doing research is harder than ever as more and more references are completely made up.
We're too lazy and too obsessed with getting ahead to use this technology responsibly in my opinion.
One of my favourite features in n++ is to enable "show all characters". Discovered a lot of weird end-of-line and bom issues like that
I always found that a simple merge style patch is enough, and a lot simpler. You just have to know that there is a difference between null and undefined. For large arrays, it's usually some sort of bulk operation that can be solved by an array of patch/delete requests, which is both safer and simpler. Maybe I've just not hit a proper use case for this yet
The problem with this standard is all the free text and bank specific fields that banks will use instead of the standard. One bank I integrated with had the equivalent of "Our fee is 5.65" in a text field which you had to parse, instead of the field for fees. Of course, the language of that string could also change. Fun times
Then you should store the time as well, because the number of decimals in a currency can change (see ISK). Also, some systems disagree on the number of decimals, so be careful. And of course prices can have more decimals. And then you have cryptocurrencies, so make sure you use bigints
I agree, and I just want to highlight what you said about generating a config file. It's extremely useful to constrain the config itself to something that can go in a json file or whatever. It makes the config simpler, easier to consume, and easier to document. But when it comes to _writing_ the config file, we should all use a programming language, and preferably a statically typed language that can check for errors and give nice auto complete and inline documentation.
I think aws cdk is a good example of this. Writing plain cloudformation is a pain. CDK solves this not by extending cloudformation with programming capabilities, but by generating the cloudformation for you. And the cloudformation is still a fairly simple, stable input for aws to consume.
People who are more into it usually prefer human made puzzles since they often have a logical path that you're supposed to find, which can be quite satisfying. Generating sudoku puzzles is actually quite easy. Just put random numbers on the board until you have a unique solution. It runs surprisingly fast. The tricky part is deciding on the difficulty. I made a program that would identify all the different sudoku techniques needed to solve each puzzle (x wings, pairs, all the way up to chains), then set the difficulty based on what techniques were required. Code is here for anyone interested: https://github.com/magnusjt/sudoku/ Sadly I don't think anyone would pay millions for this anymore
Has anyone had any success in code generation? I feel like chatgpt usually completely fails to write even a small function correctly unless it's a very trivial or well known problem. I usually have to go back and forth for a good long while explaining all the different bugs to it, and even then it often doesn't succeed (but often claims it's fixed the bugs). The types of things it gets wrong makes it a bit hard to believe it could improve enough to really boost dev productivity this year.
It's not perfect, but I have had success running postgres in Docker and running integration tests against that. Usually you can trigger the problem by running a handful of queries in parallel.
It's a running joke in our org that we should always vote for a new government. Keep making the dependency graph messy and we'll keep having a job
If you have different currencies you need to keep track of the number of decimals used, e.g. YEN has 0 decimals, bitcoin has 6, etc. It could even change over time like Icelandic ISK did in 2007. If you have different services with different knowledge about this you're in big trouble. Also prices can have an arbitrary number of decimals up until you round it to an actual monetary amount. And if you have enough decimals, the integer solution might not have enough bits anymore, so make sure you use bigints (also when JSON parsing in javascript).
Example in js: Number(9999999.999999999).toString() // => 9999999.999999998
And make sure you're not rounding using Math.round
Math.round(-1.5) // => -1
or toFixed
(2090.5 * 8.61).toFixed(2) // => 17999.20 should have been 17999.21 8.165.toFixed(2) // => 8.16 should be 8.17
The better solution is to use arbitrary precision decimals, and transport them as strings. Store them as arbitrary precision decimals in the database when possible.
My experience is the opposite of yours. With typescript I use an openapi spec to validate and generate types. For other entry points I use typebox to create validators and generate types. It requires a bit of work, but it adds a lot of capability even beyond basic deserialization.
With c# I've seen openapi interface generators that don't validate properly, only basic deserialization. I've seen dto's that are deserialized wrong due to lacking null checking attributes. I've seen the way put requests are misused due to how difficult it is to separate null and undefined in patch requests. I've seen dto's with all nullables due to the lack of union types. Maybe I've yet to see a good c# codebase, but I certainly prefer typescript over the above.
You can easily parse json into types using something like typebox. Not only does this work, it works much better than many other languages. Have fun trying to represent even a simple patch request, or discriminated union, in something like c#
True, but there might not be a big need for unit testing the glue code. By its very name it doesn't contain much logic to test. Integration tests are more valuable in this case.
Nodejs now has async local storage built in, which makes this fairly easy.
Last time I worked on call I was compensated 2 hours overtime for every time I opened the laptop, as well as a fixed rate for the week. I was also able to convert some of the fixed rate to days off the week after. Still, having to wake up multiple times each night wasn't worth any compensation to me. I suppose you're correct that compensation should be tailored to each situation, but the examples you give seem way too low to me. 350$ is nothing if there's any meaningful amount of incidents to handle. My company paid twice that, 10 years ago. I guess it would be ok if nothing really ever happens.
What are the main differences to aws lambda?
Will you be transparent about how it works, such as when a function is frozen? This is something I miss with many Aws services
I've had great success with having a monolithic code base with multiple entry points. Each entry point is sort of a micro service (or just service), but it can access the same db as the other services (if it makes sense), use the same types, and crucially, it can easily be integration tested with the other entry points. With full debug support.
Such a "monolith" need not be the only one in the company. One per high level module or team works well.
I guess my point is, it doesn't have to be either giant monolith or tiny micro services in separate repos. There's everything in between as well.
Very nice, I found myself nodding along with almost everything in this post. One thing I do a bit differently is that I usually put the API handlers in their own module (they're usually just a couple lines of code each), along with domain-to-api model transformers. This is because I often have various worker entry points as well, and it's nice to keep the domain logic separate from all the different entry points. I also like to keep all routes in a single file. I don't like to hunt down the full route path across a bunch of different files, and I like to be able to get a full overview of the API in one place. Just different tradeoffs I guess
Uri's are hierarchical, and hierarchies are notoriously difficult to get right. Even if you get them right, the definition of right often changes over time. In my experience, things have to be flat to be static. IDs seem to work pretty well
In general a function component does a lot more work than a class render function. Some of it is just about handling cases that we probably should have done with classes as well, but often didn't. The result is that everything must be carefully memoized (or not, it's sometimes hard to predict). For example, should you memoize a redux selector function like useSelector(state => state.x)? Should you wrap every function in useCallback? With classes we had arrow methods that ran once, while useCallback will be run every time the function component is run. We have to continuously check that function references are stable, if it matters, and if we care enough to bloat the function with various memo calls.
Now I'm not at all saying that class components are better. Hooks are mostly easier to work with. But there's no doubt that function components has me using too much brain power and lines of code on memoization. I like the new features the react team are working on, but I hope they'll eventually do something about the stable function reference problem as well.
Good code is produced when people can easily improve it. In my experience, people leave too much crap untouched because of unnecessary barriers, and having to create a new issue is definitely one of them.
I'd rather review 10 extra files every PR if it means the code is improving. If you keep doing this, eventually there won't be so many extra changes because they're fixed already.
I'm curious, why do you think fixing tech debt is a time sink?
How about not using configuration files in the first place? Instead expose a library in some programming language (preferably typed) to assist with writing config, then serialize the output in whatever format is easier to parse.
This is is the crux. It's possible to justify any and all designs using the single responsibility principle / separation of concerns. I've seen plenty of bad designs rationalized this way.
Answering your question (or "what is _one_ thing?") is often called an art, and seems to be learned through experience. Though I do wonder if it's possible to teach as well. So far in this industry we teach it using rules of thumb and "principles", but it doesn't seem to work very well.
I like this approach a lot. I wonder if it's a good idea to keep the assertions in prod as well. I guess this is a trade-off between safety and convenience..
As a side note, what do people think about JSON schema? I find it quite verbose and cumbersome (compared to, say, typescript type definitions)
I would also like to know, as I started on something similar myself. My plan was to allow calling an impure function from a pure function as long as the mutation was contained to state that had its entire lifetime within the pure function. To ensure that the impure function only did mutations in such a way I planned to add a special keyword that could be type checked. Never got very far with it though.