Hacker News new | past | comments | ask | show | jobs | submit login
Write code like you just learned how to program (2010) (dadgum.com)
50 points by raytopia on Oct 14, 2023 | hide | past | favorite | 54 comments



I think this misses why we structure code in the first place. It's not because it's aesthetically pleasant or anyone cares about or cool usage of the visitor pattern, but because unstructured newbie code only takes you so far in the most literal sense.

There's a point, a number of lines of code, where unstructured code becomes completely unmaintainable. You can't add to it, you can't change it, you certainly can't understand it. It's just what it is.

Structure, modeling, software architecture, testing, development practices, those sorts of things, these are basically the entrance fee for getting to work on larger problems.


While I agree unstructured code is unscalable after a certain point, I personally don’t find newbie code hard to add to, change, or understand. It’s still straightforward, that being a two-edged sword, in that it simply lacks abstractions that would improve a maintainer’s productivity.

I’ve seen worse codebases by mediors/seniors…


It becomes difficult to work with as it grows. Like it tends to almost implode at a certain point.

I think it's a repeating pattern. A lot of people with experience writing code but inexperience with software architecture (which is arguably most professional developers) tend to create quite a mess if you task them with designing an application.

Architecture experience is a lot harder to gain as you really only get a few shots to practice the craft, and there's a lot of beginner experts giving some seriously questionable advice if you go online looking for a second opinion.


Is there any material you can recommend to gain knowledge on that topic?


Not really.

What's written down tends to age poorly and become prescriptive, that's beyond the fact that a lot of supposed architectural advice is written in bad faith as marketing for cloud- or consulting services.

I think a big part of the problem is that it's all very situational. The same architecture choices may be fantastic in one project and a chronic migraine in another.


In many real-world apps, convention is far more important to the ability to add or change code than whether you write in some naive or mature style. That convention may be flawed, and even then you'd need a good reason to fight against it. It's also notable that convention almost certainly means structure and abstraction.

Sometimes I look at a codebase and I barely need to look around to feel at home. How do you grok a codebase while barely looking at it? Convention.


Newbie code is usually not so easy to read… nondescript functions, mutations happening all over the place


Unstructured code blooms into a rats nest of if/else statements with complex flags calling into other functions. There ultimately becomes no good way to avoid regressions and no way to make guarantees about what can be added in the current "architecture". Working with people that splat this code is not necessarily bad as long as you are allowed to refactor it when the time comes.


... you certainly can't understand it.

My first microcomputer ran a BASIC. The variables in that BASIC were single letters like A, F, X, etc. or a single letter plus a single digit like A4, A7, G2, etc.

Coming back to a program that I had written several months previously was pointless, as I couldn't remember what all the variables were for, or what they did. It was just easier to completely rewrite a program, rather than maintain one.

My next language happened to be COBOL with its variables that could be given fully descriptive names like EMPLOYEE-HOURS-WORKED, ITERATION-COUNT, SALES-TAX-VALUE, etc. Variable names like that mean that I can look at programs that I wrote in the 1980s and immediately be able to maintain them. That habit of giving variables really descriptive names has remained with me for decades.


This kind of straight forward/naive code actually tends to contain many bugs. I once worked with a guy who very quickly produced stuff. One thing he wrote was a program to display a table on a small screen. He mentioned that he thought that something was off in the drawing api or the hardware because it would not show a border around the table. That sounded strange, but whatever. Then I inherited his code and was tasked with extending it. Because I found these very large functions of 'doing straightforward stuff' rather hard to extend reliably, I wrote some automated tests for it. During writing the tests I found the cause of his 'border issue'. There were two off-by-one errors in this. Firstly, when there were N rows/columns he would draw borders by iterating from 1 to N. However, between N rows/columns there are N+1 boundaries, so the iteration should be from 0 to N (inclusive) instead. Next, he was drawing the border with a coordinate that was one too large, making it fall of the screen by one pixel. I think this "write code like you just learned how to program" does not result into very maintainable stuff. And maintenance is generally is an important issue because people keep wanting us to produce features and extensions....


These sound like straightforward bugs to find. I found it weird/hard to believe he would just blame it on something out of his control and nobody would question it.


If anyone would have taken the trouble of looking into it, it would probably be found pretty quickly but it is the kind of thing that is not a show stopper, so nobody really looked into it. Also, it now sounds trivial because I am giving away what the code is doing. What you actually see in code review is a sea of drawing commands and coordinate manipulation all over the place. You can then either demand that it be refactored into something more readable or you just think 'well, he will have looked at the end result and that will have looked okay' and leave it at that.


I think the disagreement to this generally falls into the trap of taking(rejecting) this advice as a purported unbreakable law. I can't speak for the author, of course, but I think like most (good) advice about how to do a thing (better), it's simply a suggestion that maybe some of the time you should try to be more like this.

YAGNI is a somewhat similar advice, and a good one -- at least for my overengineering inclined brain. But if for every single decision you invoke YAGNI, because overengineering is bad, you can also end up with bad code. Even in that case though, the standard for what is "bad code" depends on context (goals, deadlines, etc.). Even "objectively" bad code might not have a significant impact on the project, again depending on context.

Article is from 2010-12-24, posted a bunch of times. Earliest: https://news.ycombinator.com/item?id=2037576


I think the ability to be pragmatic, and make technical decisions with nuance and taking context into consideration is the sign of a quality engineer. _Everything_ is a tradeoff in engineering, and experience simply gives you more signals to know when and which tradeoffs to make.

If one can also be humble, and take other opinions into consideration, then that's someone I enjoy working with. I strive to be this person towards others.


100% agree. And the context is not only what you build but also who you are working with. A team with high turnover to it and a founder with 2-3 engineer should prop have diffrent ways of doing things, and there is a lot of business context that people are missing. A lot of code do not need to scale or be extended and may be thrown away or stopped worker on in just a few years. And we we as a industry's has gone to far in many places thinking about good code. Its highly dependent on the context


The blog is about being a "Recovering Programmer", as in, someone who is trying to cast aside programming as an identity.

And I think all the advice has to be taken through that lens. Of course someone who is in the midst of their programming journey is going to say, "No, I want to do the advanced thing now. I'm advanced."

But if "being a programmer" is a disease one wishes to rid themselves of, then advanced programming is merely advanced disease. And that point is roughly when you start to be able to make the right call when asserting YAGNI, because then you can identify with more clarity when the code deserves to be heavy, load-bearing stuff, and when it needs to be more like "code as an asset" - simple loops and branches that help configure the heavy machinery.


>YAGNI is a somewhat similar advice, and a good one -- at least for my overengineering inclined brain. But if for every single decision you invoke YAGNI, because overengineering is bad, you can also end up with bad code.

Examples?

YAGNI is a very abused term. I tend to find when people talk about exceptions to it theyre talking about things which don't actually fall under the header of preemptive features or preemptive refactoring.


Yes, this! Quite related... I forget where I heard it, but someone said the way you know you're talking to an expert is that their answers to a lot of questions start with "It depends...". Being an expert often comes down to understanding the nuance of when to follow standard practices and when it's better to violate them.

You went through YAGNI. DRY is the same thing. It's often very good advice. But there are certainly limits to DRY... calculating the area of a rectangle from its width and height in two different repositories in the same company probably wouldn't justify creating a library to be shared between them. There's a line somewhere in the middle. Being skilled at understanding what side of that line a given case should fall on is something we build with experience.

I think YAGNI and DRY are at their best as advice when they come packaged together, putting them in tension in order to prompt us to find the right balance and not to blindly follow either one. Taken together, they give us a framework for thinking about one set of tradeoffs. I believe the core of software engineering (and many other pursuits) is identifying the most important tradeoffs and finding a good balance among them. Blindly following advice can get in the way of that.


As professional developers we are usually in a business context and our purpose is not to be artists, to create, we are there to provide the reliable building blocks out of which actual creation can arise.

The focus here is “reliable”. Let the creative guys mess around, we should focus on keeping stuff clean. If we start becoming messy that’s no good, because it’s all downhill from there. How can you draw skulls, no matter how messy, if the drawing functions don’t work?

Using this article’s story, we are the ones creating the drawing functions, not the “skulls”. We make sure those guys that actually see the skulls can do whatever it is they do. We are bad at that, so when we are asked to be creative we arrive at what the author describes: few lines, something simple, something algorithmic.

That’s not because you are all about cleanliness.. you just lack creativity and vision and an artist’s drive to make it reality. And that’s OK.


I think you are both right and wrong at the same time. Even in a business context its not sure you want reliable over feature. And I think a lot of developers are focusing way to much on good code. And with that they think a lot on how it can be extended in the future. But they fail to see that from a business perspective this code is properly not living for many years. I have seen so many projects with good code beeing shutdown. Its of course another side here, where you code is in production for 10 years+ with 100 developers making changes to the files... But a great developer / architect are able to really understand the business context they are working on and understand how that influence what you consider good code and good architecture


> Write comically straightforward code, as if you just learned to program, and go out of your way avoid wearing any kind of software engineering hat

Can we stop saying this? Has anyone who said this actually TA’d for an intro programming class? It’s not as beautiful and “straightforward” as you imagine.


- A whole block that's pointless but they didn't bother trimming it

- Spawning threads for things that don't need threads

- Using timers for things that don't need timers

- Everything in one file, OR

- Everything in way too many files

- Most of all, busy loops, thread safety problems, and global mutable state.

I have seen the face of student code and it is weeping


- few levels of abstractions, with multi levels of inheritance everywhere.


> actually TA’d for an intro programming class

What does it mean?


TA is short for teacher's assistant, essentially someone who supports the teacher and students in a classroom, very common in UK schools.


I don't agree with this article. To me, clean and concise code is a skill that you should work to improve. When you have to solve difficult problems, that skill should be automatic and improve the entire process.


That clearly depends on the context. If you want to win a contract, having a functional prototype to be the deciding edge over your competitors. Here, speed of implementation trumps everything.


There's no need to sacrifice clean and correct code, the speed of implementation shouldn't be any less.

I can understand performing fewer tests in that context, because writing tests can take a lot of time. Still, a minimum number of tests that target complex code is a good idea.


> To me, clean and concise code is a skill that you should work to improve.

And he agrees with you - "[... if] what you really want to be is a software engineer".


> and not the designer of an experience.

You can still be the designer of an experience, is what I'm saying. There shouldn't be anything lost if writing code properly is what you always do.


I have one colleague who makes beautiful architecture: he thinks where things should go, how things might evolve, how to encapsulate things.

I have another colleague who “digs straight tunnels”: long functions, huge if/else’s embed things instead of reusing them.

I’m more like the first guy. Which means I have a lot to learn about simplicity from the second guy. The second guy’s code is easy to modify, because control flow rarely jumps file, or even function. It never ping-pongs messages between actors. He never prematurely optimises or generalises.


Ah… classic bell curve.

I believe it is necessary to reach the center of the bell first to grasp what simplicity means.


I think this is a good perspective to keep in mind, but you don't want to let yourself being trapped in a mode where you very conservatively reject & close yourself down to ideas & possibilities.

Systems & software reward greatly those who can keep a broad mentality, who are excited & happy to investigate possibilities & spring for bigger wins. Too often I've seen teams just grow sour & sad & turn into gatekeepers of code & what happens; it's a social loss & even if some of the ideas would have gone bad I feel like in the balance keeping an agile mind is effectively necessary.


There is in my opinion a plateau where you are focussed on cleanliness that it slows your programming down as you apply more technique but which also produces the cleanest result. Some improvements are disproportionate in time cost. However as your experience with a language, libraries and approach grows you gain productivity even when focussing on just making something it still ends up cleaner with less repetition. You often can save yourself considerable time on the lines you don't have to write.


I agree. I have spent roughly a decade reflecting on my code, iterating on it, simplifying it, trying different styles. Basically just mutating.

Now even when I am trying to go fast it comes out pretty clean.

Evolution only occurs through mutation.

Those who never mutate, never evolve.


Make it work. Make it nice. Make it fast.

Don't forget the second step, otherwise your nightmares will haunt you...


I don't want to build prototypes or startups. I have a job. And in my job, my task is to write stable, bug free code that scales. Keeping it simple is important. But code patterns and software architectures exist for a reason.


It's an interesting blog. Their whole idea is that you should focus less on beautiful code, computer science stuff, and superficial things like code formatting; you accomplish more when you focus on the problem domain, and try to accomplish what it is you set out to accomplish, even if it means ugly and repetitive code, or hacking something together sometimes.


It works for a few months or until you have other people working on the same code.


Why can’t everyone be as productive as Steve? When I assign something to him, it’s done in a week! When I want you to add a tiny feature, it takes three!


Future you will hate you for it, though.


Sure, if you are only coding for today. But as a software engineer, I'm coding for tomorrow.

Next you'll be telling Magnus Carlsen to always capture a piece every move, no matter what.


I usually follow the approach of first writing my feature in the most dead simple way. Only after I finish it I do a pass where if needed. Only if needed I refactor it based on convention and architecture patterns.

Ive found this a good way to first understand my solution before I optimize the code. I create less confusing abstractions and more code that’s easy to change. If i try to architect it first I end up always getting the abstractions wrong.


I call this 1-dimensional programming and 3-dimensional programming. (i'm working on a catchier title)

The sort of "excel but in Java" approach, or the no-code lo-code solutions out there work, kinda. They enable the business world equivalent of dropping blood - lots of boxes with if then statements.

But try to repeat the blood dripping (or business process encoded in lo-code). Try to use meta-programming techniques to dynamically tweak or even just print it out in logical sequence for the auditors to look at and you have major problems.

Computing should be topless - at no point shoukd the format of the code / what it represents be "that's it, no more programming with this data structure". And lo-code deliberately does this for strategic reasons, where as the skull blood coder did it for knowledge and experience reasons

And he (?) will have another experience - he will find the ways of being more "professional" with his code, and then he will use his creativity to get what that better structured code affords in the donald norman sense, and he will create something even more awesome than a dripping skull.

Mozart was always going to make great music. Giving him an orchestra and teaching him music theory just added rocket fuel.


Dance like nobody's watching

Love like you've never been hurt

Sing like no one's listening

Code like your PR won't be reviewed?


Code like your software will never be used


    10 PRINT$ "HELLO, WORLD"
    20 GOTO 10


This was how I learned to program, also, on my dad's HP-85. I would animate text on the screen by writing multiple print statements with the correct number of spaces. I drew pictures by drawing lines (HP basic has a DRAW command that draw a line between two coordinates) by writing a new DRAW statement for every line.

Much later I learned to encode the position information in DATA statements and loop over them. This is an important leap in skill.

Maintaining the balance between quick and dirty and maintainable is one skill that separates the great engineers from the good ones.


>It's extremely difficult to be simultaneously concerned with the end-user experience of whatever it is that you're building and the architecture of the program that delivers that experience. Maybe impossible. I think the only way to pull it off is to simply not care about the latter. Write comically straightforward code, as if you just learned to program, and

So to succeed in being simultaneously concerned with both the UX and the code, just forget about the code. Great advice. Pass.


> After all, look at how many bands find success without the benefit of a degree in music theory.

(With the help of producers who most likely do have a degree in music theory)


Related:

Write Code Like You Just Learned How to Program - https://news.ycombinator.com/item?id=2261458 - Feb 2011 (6 comments)

Write code like you just learned how to program - https://news.ycombinator.com/item?id=2037576 - Dec 2010 (51 comments)


aka drive it like you stole it


It took me four years to paint like Raphael, but a lifetime to paint like a child. - Pablo Picasso


Why skulls though?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: