Ask HN: What is the most enlightening concept that changed how you program?
Assuming that you are still learning and you learn from new experiences or concepts, what was the most mind blowing concept you learnt that totally changed how you approached programming problems?
Edit: Provide pointers to where others can learn about those concepts
32 comments
[ 2.8 ms ] story [ 66.7 ms ] threadTyped arguments as strong pre requirements to intent, and the cost/benefit of typechecks.
What do I actually do? Boring imperative python3.
I wish I'd learned LISP as my first language. It was literally a left door right door choice to do Fortran on cards, and then Pascal. Two people teaching the induction classes. I went through the Fortran->Pascal door.
If I'd turned left, I would have entered the other cohort who started with LISP.
2. linters like eslint forces best practices and readability in my code
3. security is learnable from online sources like latacora blog and owasp cheatsheets
4. reading latest docs and github issues helps a lot in debugging.
5. reading readme file and getting started guides is more reliable than watching video tutorials.
6. videos however are good at getting comparisons and seeig presentations of ideal use cases of particular tool software or database or framework
Could you please elaborate on that? I'm not sure to understand.
Start out to broad and wind up wasting resources that could be put to better use.
Start out to narrow focus without knowing where need/$$ to keep going is and wind up wasting resources. Idealy, the narrower focus permits getting to the 'wasting resources' point faster.
Hiding the details via abstraction when details are still in development/need to be viewable & readily available defeats the purpose of abstraction making things simpiler/easier.
Write the simplest abstraction first, then as the system develops combine similar use cases into useful abstractions for clarity
Anything that is “premature” is per definition incorrect. So there is no information in that sentence.
Having said that, a lack of architectural abstractions leads to badly designed code with a WTF count reaching the heavens. Have you ever seen UI code directly relying on a specific flavour of SQL implementation and database? That’s an example of how a lack of architectural abstractions leads to spaghetti code. Or how about the domain logic directly relying on a specific UI framework? Another example where an early architectural abstractions would have saved years of maintenance work. Again something I see all the time in the wild.
leaky abstractions create more trouble than is worth it. If your abstraction does not fit the problem neatly do not abstract it.
> Having said that, a lack of architectural abstractions leads to badly designed code with a WTF count reaching the heavens.
> a lack of architectural abstractions leads to spaghetti code.
> domain logic directly relying on a specific UI framework?
If we are pedantic: lack of architectural abstractions, spaghetti code, and domain logic tied to an UI can also be interpreted as simply bad, so no information in either of our posts :)
Of course, I am joking. Saying that I think leaky abstractions are bad, or you saying that no abstractions are bad is new information (it reduces uncertainty). It tells us that we think that x is bad.
We can agree that bad abstractions are bad. In this thread, abstracting to early, or having leaky abstractions or not having any abstractions are just 3 positions on the topic of what a bad abstraction is.
I bet we could much easier agree with a specific example. In my experience all "big principle" discussions improve when we focus on a specific example. Otherwise people are thinking of different scenarios.
In any case, I can think of scenarios where each of those 3 positions is right, so I do not really disagree with any of them.
An example where a lack of abstractions is always bad IMHO is when the UI is directly depending on a specific database implementation. For example, dialog callbacks directly using the Oracle dialect of SQL to do business logic. I see that all the time in the wild and it makes the code super hard to improve, test, and maintain.
Another example is the domain logic directly depending on an external framework or database. A simple abstraction that reverts the dependency would make the code so much more maintainable and flexible.
Those examples are but two of the many I see in the wild all the time. Which makes me believe that often, in practice, the lack of architectural abstractions is a big problem.
I now think much more about immutable, append-only data stores as a result.
The gist of it: you program procedurally without thinking too much about the code and only add "compressions" when the need for them arises. The compressions can take various forms like encapsulating data types within objects, behaviour within functions, extracting often-repeated operations into separate libraries and then loading and referencing them when needed, etc.
[1]: https://caseymuratori.com/blog_0015
This is a profound insight. It totally changed how I think about the nature of multithreaded and multiprocessor based programming.
Also from Kevlin - Refactoring to immutability[2], which showed me exactly why you would want immutable "variables"
[1] https://www.youtube.com/watch?v=Hi6ICEVVRiw
[2] https://www.youtube.com/watch?v=APUCMSPiNh4
Thinking of the stupidest way we can get it done and then ruthlessly refactoring until the resulting algorithm / system is as simple as possible.
Edit: point 1 comes from A Philosophy of Software Design. One of my fave programming books of all time.
Procedural is fine and simple and it works. You can refactor later if you have the time and money.
Related listening/watching: Jonathan Blow.
I have seen a lot of videos of Jonathan Blow. IIRC he created his own programming language to code in. That could be interpreted as pretty "nerdically sound" and "perfectionist" by many.
My point is, I agree with what you said in spirit, but the way you phrased it could be used to justify spaguetti code, too much technical debt and, ironically, fashion-based decisions (we need to just make it work, lets choose x).
Technically 2 concepts but they’re highly related.
Basically, allow the consumer of a component to pass in something, rather than the component needing to contain that logic.
It’s great for front end systems, but also apples to backend and general systems programming… an invaluable concept
Basically, it boils down to this: F(A . B) = F(A) + F(B)
(F,A,B, ., +) could be anything which you found suitable.
Instead of :
Now I write: Exit early makes the code easier to read and understandI try to make each method/function to have a single entry and a single exit.
Cond, case, pattern maching in function heads, decision tables, and syntactic sugar in some PLs, allow you to flatten the nested code / branchinbg / conditionals.