Before Stack Overflow, programmers at the time had to learn things by knowing someone who had the info, reading documentation, or going through code (if it was available). Stack Overflow, Google, and now ChatGPT provide more direct solutions to our problem, allowing us to get unstuck and move forward more quickly than before.
But, you end up not knowing if the solution is actually the best way to solve the problem, and usually don't
have any real insight into why the presented solution works. Practically speaking, Stack Overflow and AI
chatbots are typically out of date and can give answers that were correct, but now aren't.
Here's how I deal with this problem without abandoning these valuable tools.
Let's say you want to install NodeJS inside a Docker image you are building.
Kagi's top result for "install nodejs inside docker image" is this Stack Overflow question from 2016. The top
answer has you installing a node version manager to then install Node, while the answer marked as correct
instructs you to build from source.
Kagi has a built-in AI chatbot powered by Claude that gives a "quick answer" to any search (only if you want). It's answer is extremely verbose and over-explains, but it does contain some pretty specific instructions. They are to use curl
to download a script from deb.nodesource.com
, execute that script, and then use apt-get
to install nodejs.
Both Stack Overflow answers are completely wrong, at least as of 2024. They may work, but would likely be
pretty painful to try and debug, and a nightmare to maintain.
Claude's answer is much simpler and definitely works, even though most of the text that explains what it is doing is misleading or wrong. But, it will work.
Following Claude's advice, however, doesn't really teach you much. If you need to make a change later, or
debug a problem in the future, you basically have to start over again. You also can't really be sure that
what Claude told you to do is the best way to do it.
Here is how to become sure.
When I can, I try to work backwards from a working solution until I find documentation from the software
vendor that explains what to do.
Depending on how much you understand what you are doing, this could be easy or could be involved. For
example, in the example above, you need to eventually figure out:
Dockerfile
FROM
and RUN
doapt-get
work and why is the shell script from nodesource.com
needed?nodesource.com
?Let's say you understand the Docker stuff: Dockerfile
is building an image, FROM
declares your operating system and version, RUN
executes code, and apt-get
installs software.
If you didn't have Claude's answer, starting from nodejs.org
and trying to find out how to do this would be pretty difficult. But, with some sort of working answer, you can navigate nodejs.org
more
intentionally.
Clicking “Download” leads to a nice page where you can configure your OS and installation method.
Unfortunately, the “Docker” choice isn't what we want. You have to know how Docker works to know that the
answer isn't correct, but you can also see that it's not giving you directives that go in Dockerfile
. But, there's more on that page to explore.
There's a link to “Check out other community supported package managers”. From there, you can click "Debian and Ubuntu based Linux distributions" (since you know that FROM ubuntu
means Ubuntu), and end up on a GitHub page that has instructions.
And these instructions are pretty close to what Claude told you. They have some minor differences, and
install a later version of Node. But it does validate that Claude was mostly correct. More importantly, however, you now have a definitive source for the right way to do this.
Even though Claude wasn't 100% correct, it led you to the right answer, and it may have been extremely difficult to find that answer without some sort of help as to where to begin.
Here's an exercise you can do yourself. I'm assuming you do not know how to parse command line arguments in Bash, so if you want a script that accepts -v
and -s «service»
, this is how you'd do it:
SERVICE=default-service
VERBOSE=0
while getopts ":vs:" opt "${@}"; do
case ${opt} in
s)
SERVICE="${OPTARG}"
;;
v)
VERBOSE=1
;;
?)
echo "Invalid option: ${OPTARG}"
exit 1
;;
esac
done
shift $((OPTIND -1))
Try to figure out why this works and see if you can piece together documentation from Bash and getopts
to convince yourself this is the right way to do this.
Here is what I do, in a general sense:
Sometimes, if I have time, I'll do a sixth step, which is to just…read more of the documentation. I'll explore it and see what other capabilities are sitting there, waiting for me to use. It can be quite inspirational!
Here's some esoteric Ruby for you: name-based dependency injection based on method parameter names!
Let's say you have some objects in some sort of context:
context = {
payment_service: PaymentService.new,
tax_calculator: TaxCalculator.new,
shipping_determination: ShippingDetermination.new,
}
Now, you want to make a class that needs a PaymentService
and a TaxCalculator
:
class Checkout
def initialize(payment_service:, tax_calculator:)
# ...
end
end
Ruby allows you to access the names of the parameters:
> Checkout.instance_method(:initialize).parameters
=> [[:keyreq, :payment_service], [:keyreq, :tax_calculator]]
You can use those names to grab instances from your context
, creating a hash of arguments like so:
args = Checkout.
instance_method(:instance_method).
paramters.map { |(_param_type,param_name)|
[ param_name, context.fetch(param_name) ]
}.to_h
With args
as a Hash
, you can now create a Checkout
instance by converting it to keyword args using **
and passing it to new
(which calls initialize
):
checkout = Checkout.new(**args)
You don't always—or often—need dependency injection, but if you do, you could make a basic container for it in, well, not very many lines of Ruby.
Unless otherwise noted, my emails were written entirely by me without any assistance from a generative AI.