Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Signs that you're a bad programmer (sites.google.com)
273 points by clawrencewenham on Aug 7, 2009 | hide | past | favorite | 121 comments


I have to say, I really didn't like the document much. Not because of substance. Some of what he says is true.

On style, though, I think the document is trash. Some of what I say is probably even a bit ad hominem.

Most of the good programmers I know don't spend time worrying about bad programmers. They just write good code and cleanup bad code when they see it.

If someone feels compelled to write up an essay about bad programmers, he probably spends a lot of time dealing with bad programmers.

That experience should lead to humility, not arrogance. If you deal with a lot of bad programmers, you might not be as good as you think you are. After all, you work at the same place on the same project as a bunch of bad programmers. They where hired under the same standards as you.

To me, the document just seemed like arrogant posturing. An attempt at crafting a "negative identity" (define a group by vilifying the outsider). The best way to "be", and to be recognized as, a good programmer is to write good code. All the other stuff is just horse shit.


>> "They where hired under the same standards as you."

The problem is though the hiring process for programmers is often completely broken. Measuring good programmers is also broken in many companies, so bad programmers tend to just stay there instead of improving, or being fired.

I think being a good programmer isn't too hard if you have the talent, taste, time etc. Being recognized as a good programmer, and rewarded as such is harder.


Excellent point. Another to add to the list is that you may easily have been hired under a higher standard as the team lead or "working/programming manager".

I have been fortunate to never work with a bad programmer, but I have worked with inexperienced programmers that were learning as they went. I was not hired under the same standard or for the same reason they were.


I agree with your sentiment, and although I generally agree with the parent, I also disagree with the statement that "[t]hey where hired under the same standards as you". Few companies look for programming talent and I've seen this being hand waved away by statements like: "good programmers don't necessarily make good employees".

But on the whole, the article also leaves a sour taste in my mouth due to the superiority complex that cuts through it.

Good programmers won't effect much change at companies that have broken hiring practices. Rather move somewhere where your skills will be appreciated.


Being recognized as a good programmer when you focus on the "bad programmers" around you is both unfortunate and counter-productive.

Being a good team member who improves the process of your team by working to everyone's strengths is ... excellent.

Oddly enough, I think that at least some managers are more likely to recognize the latter than the former and often rightfully so.


> If someone feels compelled to write up an essay about bad programmers, he probably spends a lot of time dealing with bad programmers.

I should cancel my appointment with the psychoanalyst :-)

Writing is also a catharsis. You write to discover what you think and improve yourself.

But perhaps Isaac Asimov spent a lot of time dealing with robots...


I appreciate your meaning; certainly, there are enough weak essays about bad programmers, but this one has more substance than some I've read.

The idea behind any essay about bad programming has merit. I read the points in essay like this through two filters: is it a valid point and am I guilty of it. Most of the points in this essay are valid. The one about pointers isn't so relevant unless you live in C but the others, sure. The bit about knowing your platform well - that made me think about some things I've been working on.

The essay made me think and maybe checksum myself just a bit. For that, I like it.


> The one about pointers isn't so relevant unless you live in C but the others, sure.

To be fair to the article's author, he does mention that understanding references is analogous to understanding pointers. They aren't the same thing (his own words) but they're close enough to matter. I confess I originally thought exactly as you did: "What? This only applies to languages like C!" until I read a little more closely. It was a tricky sentence, and I would have appreciated it more if he were to have made the two a little more obvious. It's always easier to judge in retrospect, though.

The problem I have is that I agree with you and the original individual who stated that the article seemed arrogant. On the one hand, it made some really good points including MANY that I have been guilty of at some point or another.

The biggest beef I have with the article at large is that some of the issues are language-specific. For instance, not using methods/fields "correctly" is a pretty big problem--unless you're using a language that doesn't have properties (hello, PHP). I absolutely love properties, but whenever I've had to maintain or write PHP (yeah, I know), I tend to create public fields and use them as a pseudo-property rather than writing getter/setter methods. One, since it's a scripting language, getter/setters are superfluous for most simple applications and the fact that it's a dynamic language with an extremely stupid typing system sort of mitigates the benefit of writing extra code. I'm also not sure whether there's a performance penalty with accessor and mutator methods (maybe someone can clue me in here) in PHP.

So, am I a bad programmer because I don't use standard paradigms for small scripts written in an arguably awful language? Maybe so. Maybe more so since I actually write in that language from time to time! But, the point of this minor tangent is that some of the article's points don't effectively apply in all languages either due to deficiencies or oversights in the language specification.

I do appreciate your point about reading the article through two filters. I'd like to add a couple of others: does it matter (in the context of the language you're using) and is the point of contention a mistake that could be made due to scheduling pressure or deadlines? To some extent, I'm sure we could blame a specific degree of bad code on ridiculous deadlines (and I think the author pointed that out, too!).


"The best way to "be", and to be recognized as, a good programmer is to write good code."

That is why he included "remedies" for each condition. If you implement all of these remedies, you are very likely to write good code, and thus be a good programmer.

The title leads to the structure of the article, which is really about pitfalls to avoid if you want to be a good programmer. And for some, the negative tone might really be necessary. Remember, incompetent people are often unaware of their own incompetence. But if someone has the humility to read an article titled "Signs that you're a bad programmer" and honestly look for things he can identify in himself, he is on the right track.

In my opinion, the remedies transform this from an attempt at vilifying outsiders, into a potentially valuable tool for becoming a better programmer.


Most of the good programmers dont think about bad programmers, but if your hiring one, it's something you want to think about.


Google cache for those who hit the "pageview limit exceeded" nonsense:

http://www.google.com/url?sa=t&source=web&ct=clnk...


Never thought I'll see that on a google service. Thanks for the cache.


It's fairly ironic--Google is restricting the page views (to limit bandwidth usage), but at that same time they're hosting a copy in cache of that same page, with no limits.


No kidding. That's so moronically un-Google, it's got to be a bug rather than a genuine quota issue.

Because otherwise, Google 2009 == GeoCities 1999, and that would be unthinkable.


I find "Google 2009 == GeoCities 1999" very thinkable, especially if tweaked a little to "Google Sites 2009 == GeoCities 1999".

Empires rise and fall fast on the net. Google is now a mish-mash of offerings which get uneven attention from their internal talent. 'Sites' itself is a successor to the soon-to-be-shuttered Google Page Creator (which unlike Sites allowed custom CSS and JS). A few key people leave, a couple bad quarters -- 'Sites' could get the axe too.


wow, that's completely ridiculous.

searching through their help center, they won't even tell you what the limit is, but it seems to be pretty low. just. wow.


Reminiscent of Geocities, isn't it.


This has been making the rounds on twitter and other places, I'm sure it's had a fair amount of load.


I think he missed one.

A bad programmer won't understand or take into consideration the limits of the target platform.

A good example is posting an article to a host with limited bandwidth.


That's a bit harsh, that's a distribution problem, not a development problem. It's been long time since I've used free hosting, is there provider that doesn't limit bandwidth? (This is just out of curiosity.)


We don't :) (Weebly)


Not yet.


No. Down the line, maybe a cap on the very top end (tens of millions of pageviews per month) -- if that becomes a problem (it hasn't yet).

But we have absolutely no problem serving high traffic sites (millions of pageviews per month) for free, it hardly costs us a thing.


Oh man, I wish I had this at my last job half the team had over 50% of these symptoms, one guy had 90%. They believed, and had somehow convinced management, that they were great programmers! Some awesome practical examples from those guys below:

Overheard statement "You know when I was in college I learned C. I just can't get the hang of these objects, so I try to avoid them". The guy who said this is now 34, and has programmed python for 4 years.

A guy who would copy and paste 100 line blocks of code, and then occasionally thing "oh yeah, i need functions", and then finish out the current function by passing 12 parameters of state to current_function_2(). If you combined the func, func_2 and factored out the 100 line blocks it would be reverted with a commit: "stop making this so complicated".

There was one guy who insisted that using templates was only for web frameworks, to use them to write system/config files (done frequently due to 3rd party daemon limitations) was an abuse of the templating system, and we should just use inline prints. The program was to be called with prog > /etc/conffile.

One guy who decided that threads were so tricky, that he was the arbiter of thier use. My idea of a job queue and worker threads was "too abstract and hard to debug", so we stuck with the "tried and true" one thread per job method, all spawned at once.

I could go on, but you're all prolly bored now :)

tl;dr: i worked with the guys the article was written about


ouch... I love the 'stop making this so complicated bit'.

While some people really don't get it I'm pretty sure that most people could learn how to program with some competence.

The only metric I've found to measure programmer competence reliably is how big a project you can manage to complete. Some people get stuck at around 100 lines, others in the thousands or tens of thousands, some can keep their rudder straight across 100's of thousands of lines.

The latter takes extreme self discipline and organization.


I disagree; what takes extreme self discipline and organization is doing in 3,000 lines of code what a less organized developer would have done in 15,000. Code is a liability; developers who can get to the point save you in complexity and maintainability.


LOC is a horrible metric for this, given the degree to which morons can get comfortable with copy-paste and IDE-generated boilerplate.

Gzip-bytes of source FTW.


"you can manage to complete"

Implicit in the notion of completing a project is the certainty that the project manager will change their mind, usually after you have written 95% of it. If you copied & pasted those hundred thousand lines, you will have to change something in at least 100 different places. At that point, you'll give up in despair, proclaim the change impossible, and have the PM cancel the project in a fit of frustration. Thus, not complete.

LOC actually sorta makes sense in this context.


Good point, I hadn't thought of the ease with which text can be copied and how much garbage an IDE will spit out. Thanks!

Clever trick to measure the real information content of code using gzip too.


A good method. The skills required to create or navigate a codebase of 100, 5000, or 100,000 lines are different not only in degree but in kind. Behaviors optimal in the first case can be brutally maladaptive in the last, and vice versa. A preference for global variables or multi-threaded solutions says a lot about the size of project one is comfortable with.

But beyond the practical, what you're really measuring is the ability to break down a large problem, solve individual pieces, reason about how those interact, and iterate. That is the critical intellectual muscle that makes programmers reliably great.

I remember a few projects I abandoned when their size outgrew my ability to comprehend them. It took multiple attempts with new methods to break through certain complexity barriers. I could not write a program longer than about 500 lines until I had learned the practical use of subroutines and data structures. I could not write a program longer than a few thousand lines without a sense of taste when it came to objects and modules. And I could not write a program of significant size until I reliably turned out code that could be comprehended at a glance after months or weeks away, as my own throughput guaranteed it might be that long between visits to disparate parts of the codebase.


Hah! I remember that... I was still a kid, I really wanted to write a music composition program. One attempt after the other, this giant, monolithic piece of spaghetti. I just could not be done. Around the 700 or 800 line mark I lost overview and it would grind to a halt forever more subtle bugs to fix.

This went on for weeks, maybe even months.

Then a friend told me the magic words: "structured programming". I went to the library and read a book (I forgot the title, I think it was by Wirth).

Within 3 days I had it up and running.


>>I'm pretty sure that most people could learn how to program with some competence.

That is what logic tells you, but I've seen smarter people than me, which couldn't get it even after years of trying. (I helped a few with labs while studying.)

You shouldn't have too much grit.

You characterization about handling program size fits well with my own development. Interesting point.


I'm 34. What the hell college was he going to that taught C exclusively in the mid 90s? Perhaps he was taught C++ and just didn't understand half his courses? :-)


Probably a good one, if they taught C rather than C++. (flame-retardant-underwear-mode t)


Well, I only have experience with one college, but Stanford offers an introductory-level class in pure C and x86 assembler.


Key word being exclusive.


Funny that he has this under "Signs that you shouldn't be a programmer": "you think the presence of code in a program will affect its runtime behavior, even if it is never invoked".

Anyone who has written code in C can probably cite an anecdote where exactly this was the case, be it from a compiler bug or as fallout from a memory corruption bug.

Maybe we should add "does not understand the von Neumann architecture" to the list of signs that you're a mediocre programmer... On second thought, let's not -- the piece is bad enough to begin with. The "alternative careers" sections are just odious, and the whole thing breathes an air of inconstructiveness.


This happens in JVM languages as well. Most optimizing compilers will do things differently depending on what happens elsewhere in a function, even if it's "dead code" (and especially if it's dead code that the compiler is too stupid to realize is dead).

Granted this usually only affects runtime speed, but in some circumstances things can get worse (multithreaded programs are particularly susceptible to such optimizations, especially if they're not written correctly - yes, the real problem may be that you've written your code wrong, but there are very real situations where the presence of dead code can change the optimization path taken enough so that it either works or doesn't, which is a very real effect).

And that's even before we take into account compiler bugs, which just make things worse.


Here's a flaw which I've seen in several otherwise good programmers - forgetting that sometimes the core purpose of code is to be read and maintained by other human beings. Some of those other human beings may not have had the time to catch up on the latest/greatest language feature or 'trick' and may miss subtleties of your implementation.

I get worried when I see someone take a mainstream language (C#, Java, Python) and try and twist its idioms into whatever their favorite language is (lisp, the ML family, Perl, etc). Or if someone wants to be on the bleeding edge and use the latest language syntax/library trick. This is a pain because

- Someone new to the codebase may not have as much familiarity with all these nuances of the language. For example, I've seen crazy things done with C++ templates. I don't think there was ever a justifiable reason for doing any of them.

- The esoteric, cutting edge features often have bugs and/or don't have great tool support. Fact of life is that the more some feature gets used, the more the bugs found and fixed. If you're on the bleeding edge, you're going to hit weird language/runtime bugs which you need not have inflicted on everyone.

- Debugging. Often, the only thing you have after a weird bug is a crash dump and caffeine. You want to give yourself all the chances you can of tracking down that issue. Esoteric language features rarely lead themselves to great crash dump debugging. I'm not suggesting writing C code but the closer the mapping from code you write to x86/64 code, the easier it is for you


Sometimes use of advanced facilities is a way of elevating your status over the uninitiated. Now that you've shown weakness, I'm really going to pour it on!


I'm skeptical of these lists because people can work through things. For example, the stuff listed under "Inability to determine the order of program execution" is something that many people will get jammed on eary on as they try to take their brains (which is honed on the syntax of school level maths) into the programing world (where equals is an instruction rather than an assumptions). Another one is "Lisp is opaque to you". It's very sweet for MIT types to make these declarations from mount olympus, but lisp is something that can take time to acquire. If someone isn't a natural programmer but is happy to work at it to overcome hurdles then there's nothing wrong with that.

One of the examples of bad technique is:

    Homebrew "Business Rule Engines"
Can anyone give examples of the sorts of things the author means by this? What sort of systems have people seen, and why is it necessarily a bad thing?


"It's very sweet for MIT types to make these declarations from mount olympus, but lisp is something that can take time to acquire."

Don't worry. In the Valley, people from MIT don't have a good reputation as great programmers. For some reason, their education is a lot of 'theory' and less practice.

Apart from Standford\Caltech, Some of the best schools that produce great programmers are your average state school.

I have a theory behind this, which may be correct. Learning to be a great programmer takes years, and school is just the start. People that do well enough go to something like MIT, think they are already very smart, and don't try hard when they come out.

But if you are hungry, and smart, and just happen to go to your average state school, you probably will do better, as you probably are humbler to begin with.

It seems when the rubber meets the street, in startups, building products, that's where the great programmers are made, and lisp is not a requirement to know to be a great programmer, or actually build great products. Having an idea of what functional languages are is a must, knowing them is not.


nope not the case, I know a bunch of people at these various schools, and the crux of the problem is that theres a huge culture at MIT (and moreso than many peer schools) of celebrating herculean last minute efforts that get the grade. This is great for experimental hacking on a weekend, and "good enough" for research, but it does not encourage an incremental design sensibility, owing to its last minute nature.

This is not to say that any of these people are bad at what they do, they just have bad habits that they need to walk off, but first someone needs to tell them!


the crux of the problem is that theres a huge culture at MIT (and moreso than many peer schools) of celebrating herculean last minute efforts that get the grade

That's a very astute observation. I work and have worked with many MIT people, and even TA'd an MIT course. The "all nighter" hazing ritual culture was very prevalent. To this day, my friends who went to MIT prefer to work 24 hour shifts, late nights, and on weekends - even though they've been out of school for a decade. In addition, MIT had a culture of boot-camp style negative reinforcement. "You suck, are not smart enough and are lazy, work harder" was the driving attitude. (at least it was in the late 1990s)

In contrast, when I moved to the west coast, all the Stanford people I met were more about basking in their obvious awesomeness and mastering time management. Get the project done early, schedule everything around ultimate frisbee team and rock climbing club, go to the outdoor concert on Friday night and still make it up to Tahoe for the weekend.


I think it's much simpler than that: Most good programmers are self taught. School is just increasing their exposure and nailing down some good habits.

Even fricken DeVry will help you with that if you are already motivated.


While I'm not an MIT student, I think the school puts a huge emphasis on being pragmatic ( see http://news.ycombinator.com/item?id=530659 ). Also, given the huge disparities in abilities of the freshmen there, I'd reckon that, more often than not, an MIT education would be a humbling experience.


My dad, an MIT alum (though in chemistry, not CS), likes to tell the story of how whenever new grad students arrive on campus, everybody's wearing Phi Beta Kappa rings. By the second week, they've all disappeared. When everybody's got one, flaunting yours displays arrogance a whole lot more than intelligence.


I've seen weak work from a few Stanford grads.

While I have great respect for these institutions and the aptitude required to succeed within a difficult program, it's not a guarantee of quality.


Well, his alternative careers for those who with an inability to determine the order of program execution are pretty good. I wouldn't mind being a civil engineer.


The inability to determine the order of program execution is what made me give up haskell for ocaml and scala. Does that make me a bad programmer?


Don't worry, you're in good company, for example: http://janestreet.com/

I (a Haskeller) interviewed there, and ended up in an long debate with their CTO Yaron Minsky poking at warts in each other's pet languages and patterns of thought -- in retrospect we were trolling each other pretty hard just as a natural reflex.


Why do you care what order your functions run in Haskell? Seems to me you want them to run as late as possible and no sooner.


He doesn't. What he really cares about is memory consumption, especially stack consumption. Order of execution can influence that a lot: unevaluated chunks may hold quite a lot memory, and their evaluation in normal order may overflow the stack (in most implementations).

These problems are called "lazyness leaks". This is why he still cares about order of evaluation.


This one time I had to work at a place where a postgresql install was not only the main datastore, it was also the main system message bus by abusing notifies. Further the enterprise message bus was a homebrew thing that was written to both pass messages and do RPC, oh and be the main way to monitor if a remote site was up or not. I think both of those count as well.

For those who are curious: given these were linux systems, d-bus was the right answer for the former, and something like RabbitMQ or OpenAMQP, or even JMS solutions would be the proper answer to the latter.


See to me, those look like homebrew solutions, and Tibco/RV or MQSeries is the proper answer.

It's easy in retrospect, but Postgres predates JMS etc by a loooong way - who's to say that wasn't the best solution at the time?


Good question! The postgres solution was unexcusable, it was always used side-by-side with dbus. The other was around before any affordable[1] enterprise message busses existed, however as that changed the buggy solutions was still touted as "amazing new tech that keeps us ahead ofthe competion. No we can't switch to something else".

[1] Affordable being defined as: this particular company could pay for it without going out of business.


I love the insight that lacking critical thinking "originates in both lazy thinking and egocentric thinking". The latter is very true. I have never met a great programmer who thinks they are at the top of their game. Being aware of the trade offs in any solution requires a degree of humility.


Signs that you're a bad web host: "pageview limit exceeded"

If Google can't figure out a way to monetize popular content targeted at a professional technical audience, something's very wrong.

The best idea I've seen for such situations is to let people trying to view the page buy an instant traffic upgrade on the site's behalf; I'd chip in 100x the costs to serve my single hit if I knew it would restore visibility for me and some others.

The help link is also uncharacteristically inept for Google -- it doesn't lead to an explanation of pageview limits, and searching [pageview limit exceeded] in the help area turns up only user questions, no official article on the topic. The third hit is this unanswered gem, from a popular site with AdSense that keeps going down due to the limits:

http://www.google.com/support/forum/p/sites/thread?tid=08f19...


This is a very good article, and hits lots of very good points.

However, it seems that there is a little bit of a self-diagnosis problem. For example, if you write "voodo code" (great description), unless there is some one to tell you, how do you know? And if you write voodo code, do you know what idempotent means? There is maybe a bit of the "Blub" effect here.

Perhaps between "Symptoms" and "Remedies" there needs to be "Diagnosis" or some hints at self-evaluation or tools for self-assessment.


This is absolutely amazing and comprehensive! I can't think of anything he really left out.

I've seen articles like this before, but they're usually super-parochial, and I've never seen one that offered 'remedies' (much less the hilarious 'alternative careers' in the last section).


Signs that you're a bad programmer: 1) You think you're an amazing programmer.


Just reading that made me a bad programmer. :/


Pageview limit exceeded

We are sorry, but this site has exceeded its page view limit at this time. Please try again later. For more information, see Google Sites help.


Oh! I thought that was the joke. The sign that you're a bad programmer is that you implement a page rate limit on one of your properties (google sites), only to serve up the exact same page out of another one of your properties (google cache) thus accomplishing exactly nothing


Does anyone have a mirror for this page?


I'm getting the same message, could someone post a mirror? Or if any one still has the page open, please save it and post it elsewhere.


He's missing the third part, signs your a decent programmer, to differentiate the good from the great.


That's ridiculously difficult to do at all, much less in pithy universal checklist form.


For starters howabout: 1. you read the bad list and thought "oh crap!" 2. the oh crap is no longer a problem for you, but remembering the code with that problem makes you wince.


I know it's fairly difficult, but we can think of a few. You can have a derivative of the 'good' programmer, the hotshot cowboy who productively makes many products quickly that run well, but the code is "unnecessarily clever", disorganized and difficult to change.


That was mostly high quality except for the wannabe "you might be a redneck" (shouldn't be a programmer) section at the end.

> (Functional) Manually caching the results of a deterministic function on ... Haskell

You still have to explicitly memoize at times in Haskell.

> refactor his old code with the goal of reducing its instruction count by 10:1 or more

What a loser! I go into my old code with a goal of 10000:1.

> Recursive subroutines that concatenate/sum to a carry-along output variable

This can be justified.

> Using strings/integers for values that have (or could be given) more appropriate wrapper types in a strongly-typed language

Not always worth it.

> Unit Testing, which you use at design time.

No, I don't.

> You don't use whitespace or indentation

If I'm not using whitespace, what am I supposed to indent with?


Seems to be a good source for creating interview questions.


It's down, but it sounds like a copy of http://badprogrammer.infogami.com/


Just moved it to another host. Not like Google was any better >:|


I noticed when one of your articles was posted to reddit that there was no signature on it, it's nice to know who is behind them. Do you think you will ever publish these in book form? Your tips are blindingly accurate, it could definitely be a Code Complete III, updated to include functional and declarative programming.


Indeed, I just realized you're the author of both pages. Thanks for bringing a fine article to attention again.


"Phase 5: "By letting a constraint solver figure out the mundane details, I can write programs by describing what I want, rather than how to give it to me""

This is one of the best arguments for why anyone should bother to learn Haskell (or likewise language)


1. (Haskell) Propagating the myth that Haskell would do some automagic caching of function results.

(Haskell simply does call-by-need: square (x+1) evaluates to (x+1)*(x+1), but there's still only one (x+1) that gets evaluated.)


Some praise for this article: Identifying a set of patterns for sub-quality programming practise is useful in order to set about correcting those things esp. if you're in a mentoring position. I think it would have been nice to have given these names (like design patterns perhaps) and fleshed out their definitions further.

Yes, the author is more arrogant than desirable in his delivery but don't let that blind you to the good stuff. Some of the teaching analogies, in particular, I thought were good.


High cohesion is bad in exactly which programming environment? Functional or procedural?

I've always understood high cohesion to be related to low coupling. Also, writing util classes before you need them (where low cohesion may be necessary) is a nothing more than a time sink. Do something when you need it, not before. You are not omniscient and will not be able to account for everything no matter how hard you try.


FTA: "Signs that you shouldn't be a programmer

1. Inability to determine the order of program execution

Symptoms

a = 5 b = 10 a = b

print a You look at the code above and aren't sure what number gets printed out at the end"

The answer is not always obvious. If the above code were in Java and print a was running in a different thread then it very well print 0, since a or b could be 0. JMM can really bite you if you don't understand within-thread as-if-serial semantics.


That's a pretty extreme case don't you think? You're certainly playing devil's advocate here. We all know what the author meant by this.


This is spot on:

   5. Lisp is opaque to you


I can't learn LISP. I can get reasonable work done in imperative functional/OO languages like Perl, C, Java, etc. and took the time to learn Erlang to get a look at functional programming and I can drop the SQL bomb like nothing else (so I can do declarative too) but every time I've sat down to learn LISP because people say it will make me a better programmer, I've gotten distracted and haven't finished.

I don't think this makes me stupid, or a bad programmer. I think it means I have different tastes and limited time. Learning LISP feels like learning assembly: a great exercise, but there are other things I'm more interested in doing - like building things I enjoy with my limited free time.

That being said, maybe I am stupid, or a bad programmer. I don't think not being into LISP means this is the case. I like building things people use, more than I like writing elegant code for code's sake.


You really ought to look at the SICP videos (http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussma...). Hour for hour, it's probably the best introduction to Computer Science you'll ever see, and as as side benefit, you'll learn LISP in the first two hours.

I don't think you're a bad programmer-- but if you're making a distinction between "building things people use" and "writing elegant code", prepare to have your mind blown by SICP.


I used to think the same; couldn't really grasp LISP and had even more serious problems with pure functional languages such as Haskell. But the thing is, you can make up all sorts of excuses for not knowing something, but in the end, it's really just not knowing, no matter how good your excuses are.

Then I've spent some time learning LISP, practising it, trying to implement more and more complex algorithms in it and while I'm still not a pro, I'm starting to grasp the basics. And it made me a better programmer, even though at my daytime job I work as a C#/.NET programmer, the little LISP knowledge I have heavily influenced the quality of my code and I think for the better.


I don't think Lisp being opaque has anything to do with your ability to learn a particular PL such as Common Lisp, Scheme, Arc or Clojure. Rather, opacity is usually a term levied at a syntax, when it makes it hard to understand what the underlying semantics of the program are. Lisp has the least "syntax" of any programming language I know of, so if it's opaque to you (e.g., you can't take a guess at what "(+ 2 3)" means), you probably shouldn't be programming.


I don't understand the following point you made:

"so if it's opaque to you...,you probably shouldn't be programming"

So your saying that someone should not program if they haven't learned basic lisp ( 5 )?

Or are you suggesting that there should be some time limit... like if you program for X months but don't understand it you are forced to quit.

But.. further... What is the purpose of forcing these people to quit?

And.. What is the purpose of belittling these people?


I'm not talking about learning programming. The reference in the article was to people that already were programmers.

To put it another way: if you call yourself a programmer, and sell your skills as a programmer, but can't mentally decompose "(+ 2 3)" into an AST (basically the first, and easiest, step to understanding), even after Lisp's general syntax is explained to you, then you aren't actually a programmer.


Above, you said whether they could guess it, not whether they could understand it after explained.

"you can't take a guess at what "(+ 2 3)" means"

I can see your meaning if it was explained to someone and they still didn't grok it. But I would still kinda feel like encouraging them.


Nevermind this.. Posted under the wrong thread.


I see. Its not literally opaque - I got that far in the book, but I can't follow a real program's execution.


I think LISP, Haskell and 'Learning Lisp' or 'Learning Haskell' is nothing one should take too literal.

I think the point behind such statements is the point, that Lisp and especially Haskell today are very, very advanced languages with very, very advanced and abstract concepts (best example: Monads.). If you 'Learn Haskell', or 'Learn Lisp', the speaker will usually mean: Learn these abstract and advanced concepts. Learn to love homoiconic languages such as Lisp, Factor, and learn to love the mathematic backgrounds in haskell, with its Monads, Types, Monoids and whatsoever. If you have groked those concepts, you will usually make a serious step on the ladder of good programmers.

However, as 'Learning Lisp', or 'Learning Haskell' are just a way to say to learn these very advanced concepts, it can be very possible that one knows these concepts by heart already. So, if you know functional programming, the most interesting part about lisp reduces to macros, pretty much. (I know, I will be bashed, because there will be one or two interesting features I forgot, because I did not venture into the LISP-Land too much, because the madness of interpreters and such was too big for me, but the point still stands.)


Its not opaque to me, i just haven't invested the effort to bother learning it yet.


I'd been looking for a name for what the author terms "yo-yo" code. I've often wondered if others have to deal with such head scratchers too.


Great doc to make screeners with.


After reading it twice, there are many points that are good, but there also some points that are not so clear cut, or plain bad. Maybe I am a bad programmer, but I disagree with some points:

# (OOP) Writing lots of "xxxxxManager" classes that contain all of the methods for manipulating the fields of objects that have little or no methods of their own

I guess they keyword 'lots' make this ok, but having plain objects (scruct like), passed around in the application, and having some managers is fine. eg. if you have an application that passes around contacts, you can have a ContactsManager, taking care of all the messy bussines (local peristence, remote persitence, deleting, etc., while contacts remain simple objects. ActiveRecord pattern goes the other way, where this logic is placed in the objects. Both are fine.

# (Relational) Treating a relational database as an object store and performing all joins and relation enforcement in client code

--I guess all those programmers in the "NOSql" movements are idiots. (they are not, some of these people are really smart). Don't take this statement too seriously.

# Re-inventing or laboring without basic mechanisms that are built-into the language, such as events-and-handlers or regular expressions

--I think regular expressions are evil, obscure, and performance is highly depended on the implementation. Practical example, checking if an email address is valid. While some people go all the way crazy with regular expression, All I do is check that there is an '@', or a '+', at least one '.', and minimum/maximum lengths. You don't regular expressions for that, as no matter how smart you think your expression is, there is a great chance somebody that edits it will fuck it up just by changing a character on it.

# Re-inventing classes and functions that are built-into the framework (eg: timers, collections, sorting and searching algorithms) *

Done many times. If you are doing mobile, most of platform implementation (at least in J2ME) just suck ass. You can't rely on them. Heck, in my previous company we did even font rendering, thread worker queues, etc. as the scheduler was unreliable, etc.

#Recursive subroutines that concatenate/sum to a global variable or a carry-along output variable

--For some problems carry-along variable are needed.

eg, in a binary search tree, trying to print only the nodes in a certain level. printTreeLevel(tree, 2) -- will print only the nodes at level two

print(node, level)

  if level == 0

     print node.data

  else

     printTreeLevel(node.left, level - 1)

     printTreeLevel(node.right, level - 1)

  
# Writing business-logic functions with tragically compromising side-effects, such as updating a user interface or performing file I/O

--I guess it depends on the definition of what "business-logic" is. This guy thinks it more as the transactional/model part and not a controller. For some apps, the business logic is the main controller. Plus, "bussines logic" is more of a managerial speak anyways.

#Homebrew "Business Rule Engines"

-- Maybe I am not old enough, but I had to look it up what a "Business Rule Engine" is. Seems stuff from the Dot Com era/enterprise world.

#Code that tries to prevent an exploit from working by searching for the exploit's signature

--Haha. That's the whole Antivirus industry. I agree with him, and I don't have antivirus software, but it seems that those companies made millions by breaking this rule.


  Recursive subroutines that concatenate/sum to a global 
  variable or a carry-along output variable
Wow...I didn't see this in the article. That is downright boneheaded. Is accumulator-passing style forbidden for a reason? It's a cheap way to make functions tail-recursive---much cheaper than CPS!


I'm still looking for a good way to express what was meant by that symptom description.

You know about tail recursion, but I'm trying to get at the uses of accumulators that have nothing to do with tail recursion.

That and I got fed up with listing all of the exceptions to every rule.


The author lists the following as a symptom of being "unable to reason about code":

"5. 'Bulldozer code' that gives the appearance of refactoring by breaking out chunks into subroutines, but that are impossible to reuse in another context (very high cohesion)"

I disagree with this. The purpose of breaking out code in to subroutines isn't only for code reuse. If you don't break out code in to subroutines, at some point your code is going to become unwieldy and difficult to read.

I try to stick to the rule of having each subroutine consist of no more than a page of code (so that each subroutine can be seen all at one time, without needing to scroll). Often that leads me to break up the subroutine in to many other subroutines. This improves readability greatly and makes it much easier to reason about the code. If any of the subroutines I break my code out in to happen to be reusable, that's just icing on the cake, not a necessity.


A precedural decomposition should at least partition your code along meaningful lines so that a reader can potentially find something faster or understand its functionality in simpler terms. If they have to jump all over the place to make any sense of your code, you're just obfuscating.

I've seen plenty of bad code where a task is broken down arbitrarily, creating sets of procedures like foo, begin_foo, execute_foo, actually_do_foo, foo_part_two, etc. This seems to be a particular problem with OOP, where tasks have to be handed off from object to object, down the chain of responsibility.


it is not a problem with OOP so much as it is with the abuse of OOP, which is easy to do. Bad developers put the work flow procedures in objects and treat it as if it can be used as traditional OOP. but the truth is that work flow is usually task specific and not reusable. It lends itself better to procedural programming. Good OOP programmers know to stuff this stuff in thread safe static subroutines(methods) and provide a service layer for all work flow. it should not be embedded in objects (i know technically the static methods are in an object). Unfortunately this has also caused another bad OO problem with anemic objects. If you look at MVC implementations like struts it has caused a new bad habit in which objects are used for nothing more than structures and all of the logic is implemented in the work flow. Reusable business logic should be implemented as methods on the object in which they relate to. User specific work flow should be abstracted away from the objects and the UI should be loosely coupled to the work flow through a service facade. Alternatively if you have a group of good OO programs you can implement the work flow elements in a reusable event based system where reusable paths can be developed and listeners can chain in for very specific non-reusable tasks, but this is very hard for a junior to follow so many good developers opt for the first pattern because it allows them to train new developers on the system, without having to teach a programmer event based techniques. I don't know why it is so hard for people to grasp OO, but it does seem like it is much easier to create a hideous unwieldy beast with it, than procedural, in the hand of the wrong developer. Conversely, some of the most elegant systems that I have seen where done with OO languages and properer delineation between the data systems the business model and logic, the work flow and the interface.

Anyway, long story short when I see a huge stack chain, general they are either do anemic objects and just hacking up the big controller procedure into a bunch of little functions or they are doing OO work flow, either of which is not an appetizing prospect to support or fix. Evey once and a while you will get someone that is doing factory patterns everywhere which can create a lot of deep dives down the stack to figure out that the 17 methods deep stack finally results in one method creating a object.

P.S. Private subroutines do not have to be reusable public ones should be. The author did not specify. so I hope and assume he was talking about public subroutines.


I thought this as well when I was reading it.

I think what the article is suggesting, though, is not just that the subroutines would be "reusable" as in useful if called from another part of the program.

He's suggesting that the contents of each subroutine should be decoupled from each other - so not sharing global state, depending on strange changes made in other seemingly unrelated methods, etc.

The property of "I could reuse this routine if I needed to" implies low cohesion and therefore (probably) more maintainable code.

Steve Yegge argued something related to this topic that I don't think I like much, and I don't think you'd agree with it either. He claimed that junior programmers tend to write shorter methods because they're not used to fitting large chunks of complex code in their heads: http://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.htm...

As someone who has seen 2000-line long C++ methods written by "senior developers", I still think short clearly named methods are better. :)


I have seen Fortran programs that don't have any subroutine at all //senior guru model. Even if you could reason about that large amount (40K LOC) I don't enjoy when you die and I get the responsibility to fix "the bug".

I do agree that you should not (depending on language) write sub of everything. ex int add(int a, int b) {return a+b;} //Junior model


Sometimes the (seemingly) simple act of trying to come up with a name for a subroutine helps me reason about what it is I'm trying to do (whether the chunk is re-usable or not).


Not being able to think of a good name for a variable, function, class or data structure is a show-stopper for me. If I can't come up with a short, descriptive name, then I assume I don't really understand what I want that thing to do or be. I'll sit and think until I'm satisfied I have both a meaningful name and a grasp on how this thing fits into the problem.


I don't know if you've tried this, but if you write down some pseudocode before you really get started, the logical chunks of the program will take their names straight from the pseudocode.


Or do comment-driven development: write the comments for the method first, then convert the (hopefully!) plain English into code, ideally so that no comment is needed.


Am I the only one that thinks the original author's use of the term cohesion is wrong? I thought the goals were: high cohesion and loose coupling.

http://en.wikipedia.org/wiki/Cohesion_(computer_science) http://en.wikipedia.org/wiki/Coupling_(computer_science)


I'm surprised anyone noticed this. Yes, I agree.


I have done this too, particularly in small projects. One thing I try to do in these situations is imagine what functions would be useful should I extend the program later. Anther trick is to imagine a different pardigm, i.e. coding it up as a state machine.

What I gathered from the original article however, is a focus on those guys who will decompose long_function(params) into short_func1(params), the last line of which is return short_func2(params, 12 state params); .


I'm not fond of scrolling (or ctrl+clicking) up and down to see what every little subroutine does to understand the code I have to fix. Only if it's my own code, I can be somewhat sure the tiny function does indeed SetOrderDate, but maybe it also modifies order's XML or changes some global variables... I can never be sure and I have to look, so reading bulldozed code is almost like reading huge routine but with way more scrolling.


Using ctags and a good editor (or an IDE) will make the process of seeking to (and jumping back from) subroutines a lot less painful.


If readable chunks were all you cared about, why don't you just insert a few newlines and a single-line comment? I bet you actually do take some care to reduce coupling even when not intending reuse.


I agree with you, but I think that when it is possible to break it into atomic functions that are reusable then that is superior to doing it simply for size reasons.


How to avoid (if you're a C programmer) writing utterly terrible code - always include these WARNINGS in your build step:

WARNINGS := -Wall -W -Wunused-parameter -Wmissing-declarations

WARNINGS += -Wstrict-prototypes -Wmissing-prototypes -Wsign-compare

WARNINGS += -Wconversion -Wshadow -Wcast-align -Wparentheses

WARNINGS += -Wsequence-point -Wdeclaration-after-statement -Wundef

WARNINGS += -Wpointer-arith -Wnested-externs -Wredundant-decls

WARNINGS += -Werror -Wdisabled-optimization -pedantic

CFLAGS += $(WARNINGS)

Note: -pedantic is pretty good if you really wanna learn how to write code that will work properly.

Also: Treating Warnings as Errors is a good thing. You'll learn a lot, and the most important thing will be: handle all warnings. Do not release code until it builds clean.


Good advice, but compilers often issue warnings like "x may be used uninitialized" even when it cannot happen.


Erm, wut? Not really. If there is a warning, its there for a reason. Fix that.


As everyone who has written a C program of sufficient complexity knows, these warnings are not always correct. Google for "spurious warnings uninitialized", e.g:

http://kerneltrap.org/node/6591

An unrelated example where gcc (and icc) emit needless warnings about integer types is this:

  int x = foo();
  unsigned y = (x == 0);

Don't get me wrong, I'm in favor of cranking up the warning levels, but there is a reason why not everything is included in -Wall (yes, "uninitialized" is included, I know).


As a professional C coder for 20+ years, with well over a million lines of code under my belt, I can tell you that anyone that is ignoring warnings because of a buggy compiler is using the wrong compiler and should fix that immediately.

I work on SIL-4 rated systems for life-protection applications. Absolutely ZERO TOLERANCE for warnings is a requirement in this job, and every single time it has been addressed, the warning gave us a clue how to fix something. Whether it was the code that needed fixing, or the compiler - either way, the alert is there. Ignore at your own peril.


Oh, you can put it as simple as:

If you think you are good, you are not. If you think you have to improve, chances are you will become better.

(Life is baby steps; ask a baby...)




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

Search: