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.
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.
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.
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.
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.)
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.
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.
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).
>>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? :-)
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.
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.
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.
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.
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:
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).
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
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.
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.
"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)
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.
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.
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'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.
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.)
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
# 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!
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 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.
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.
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.
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.
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:
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.
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.