What happens with the "I'll build everything from scratch" apps is they are oftentimes not easy to understand, different patterns end up being used, 3rd party packages get slapped on ad-hoc and over time it just becomes a frankenstein. Much better to start with a hard set of rails that follow a set of conventions you just have to learn once.
The whole "I can move faster" without a framework is just an illusion that appears at the beginning of building an app. It will quickly disappear as more devs and complex code features are requested.
For the standard answers of "GPT-4 or above", "claude sonnet or haiku", or models of similar power and well known languages like Python, Javascript, Java, or C and assuming no particularly niche or unheard of APIs or project contexts the failure rate of 4-5 line of code scripts in my experience is less than 1%.
I'm pretty sure everybody measures "failure rate" differently and grossly exaggerate the success rate. There's a lot of suggestions below about "tweaking", but if I have to "tweak" generated code in any way then that is a failure for me. So the failure rate of generated code is about 99%.
Other than that, what correlates more strongly with the ability to use LLMs effectively is, I believe, language skills: the ability to describe problems very clearly. LLMs reply quality changes very significantly with the quality of the prompt. Experienced programmers that can also communicate effectively provide the model with many design hints, details where to focus, ..., basically escaping many local minima immediately.
I do not remember a single instance when code provided to me by an LLM worked at all. Even if I ask something small that cand be done in 4-5 lines of code is always broken.
From a fellow "seasoned" programmer to another: how the hell do you write the prompts to get back correct working code?
1) try to use "for := range" loops instead of the traditional for
2) "var result [4]string" - really seems like this wants to be a struct with a couple of fields.
type result struct {
id string
name string
brand string
price string
}
Makes code more self documenting: result.id = product
result.name = e.ChildText("h3 a")
result.brand = " "
result.price = e.ChildText("span.value")
3) you could introduce a "store" struct with fields like "separator", "name", "baseProductUrl", and a "Visit" method. This would entirely eliminate the need for lines 63-73, which are static code in a for loop and a performance/code smell.3b) The "visitStore" method does a switch on "store", but it is in a hot loop. This is a good candidate for micro-optimisation-is-the-root-of-all-evil debates later down the road. It's better to avoid those, and there's a number of simple solutions here to prevent that "constant check" in the hot loop.
4) Using defer in for loops is always a red flag. While it is technically correct, it's very likely not what you want here. Imagine that you have 10k products to visit, for 10 stores. The file for the first store will be flushed and closed only after your main function exists (your entire program in this case). What you would want is to open a file, visit all products, flush the writes and close the file handle, and only then move on to the next store. In other words, the lines 76-98 (the body of your main for loop) should be a separate function so your "defer"s happen when a loop iteration terminates, and not when the "main" function exists.
Not an expert, but my gut says maybe it runs against zero values? As in, "what's the zero value for a non-nullable reference?" Maybe the answer is something like "you can only use this type for parameters", but that seems very limiting.
What is missing is the ability to have pointer variables and have the compiler ensure that it will be never nil. I believe this was a design choice, not some technical limitation.