Good grief, what a vast amount of supposition backed up by very little evidence or insight. "People often write bad code." Yes, we know that. "There's more than one reason for this." Yes, we know that too.
The rest of the article is just random presumptions thrown together, for what reason I couldn't say. The best developers work in finance because the money's highest? Yeah, OK then... (To be fair, I think there is a qualifying "considered to be" in there somewhere) K is impenetrable? Hmmm. Haskell is an offshoot of ML and unreadable? Umm, factually wrong.
There's lots wrong with software at scale, and the pressures of financial institutions along with high budgets etc do produce an interesting set of problems, but this article offers nothing new about anything at all in the field.
As an aside, I already don't trust an author when they start off with a claim that textbook code is good code! It's almost universally accepted to be trivialised and simplified to the point of "don't do this in the real world" simply because it has to be. Some of the worst code I've seen has been in textbooks (and that's worst as in "dangerous" rather than as in "badly written and in need of refactoring/replacement/enclosing in concrete).
Edit to note: I think it's actually beyond incompetent journalism and in to plain lying to present a piece of code as evidence of Haskell unreadability when the link to that code on SO refers to it clearly as "obfuscated Haskell code".
>Good grief, what a vast amount of supposition backed up by very little evidence or insight. "People often write bad code." Yes, we know that. "There's more than one reason for this." Yes, we know that too.
YOU AND ME know that. The title of the article is "What Compsci textbooks don't tell you", so I guess it is targeted at people still in college, to show them how things are in the "real world".
Trust me, the example code that I get from my university is proof enough. And it makes me sad, because it makes my peers believe it's acceptable to write such poor code.
Yes, that makes me sad as well. I would not get a passing grade for that 20 years ago, now it's a B 'because it works'. This is too common and it's not acceptable.
College offers you a way to live for free, do very little work and a massive range of social opportunities. A degree is inevitable and honestly secondary, they are not the problem.
I know what you mean, and if I thought this article was actually targeted at students, and with any intention of enlightenment, I would agree with you. I just don't feel it deserves that credit. It's wandering, poorly researched hearsay.
I would call it a hatchet job if I could tell by reading it what the target is, but it isn't even good enough for that.
Pop culture is all about identity and feeling like you're participating. It has nothing to do with cooperation, the past or the future — it's living in the present. I think the same is true of most people who write code for money. They have no idea where [their culture came from] — and the Internet was done so well that most people think of it as a natural resource like the Pacific Ocean, rather than something that was man-made. When was the last time a technology with a scale like that was so error-free?
I appreciate this categorization on many fronts:
- It explains how non-computer science majors have frequently succeeded. In music, you will never find a classical musician without formal training, but frequently find pop musicians who have little or none.
- It shows how some of the same ideas keep being "discovered" by one group while another group sighs and exclaims "we knew about that years ago..."
- Pop culture is inherently youthful, prone to extremes, sensitive to new trends. Sound familiar?
- It explains a vast amount of decision making that goes on in industry. Rather than choosing the absolute best solution from a somewhat abstract technical perspective, a solution that is new and hip (or fits what I was doing in the hey-day of the bosses youth) is selected.
It is over simplistic to simplify real world code as "sucking" (though of course much does). It is like comparing Bach and <fill in your favorite rock/pop star here>. Both produce valid creations that accomplish something, but were made with vastly different intentions and for different purposes.
Real world code? All code sucks. And Alan Kay says something more damning than that: he says that the whole industry is a pop culture. We are living in the murky anterenaissance and precious few seem bothered by it.
I didn't say that. Imagine the great classical Greeks watching the dark ages take place. You could imagine their horror. Not bitter, just horrified. And with good reason.
Alan Kay has every right to be bitter. He's a great software architect, and came up with OOP as a perfectly reasonable policy for managing complexity. Now most people associate OOP with commercial garbage and that VisitorSingletonFactory nonsense.
If you came up with a set of really good ideas that were later bastardized and mutated into the sort of business horseshit that's destroying software, wouldn't you be pissed off?
In the last 25 years or so, we actually got something like a pop culture, similar to what happened when television came on the scene and some of its inventors thought it would be a way of getting Shakespeare to the masses. But they forgot that you have to be more sophisticated and have more perspective to understand Shakespeare. What television was able to do was to capture people as they were.
So I think the lack of a real computer science today, and the lack of real software engineering today, is partly due to this pop culture.
The hilarious thing about this is, of course, that Shakespeare is actually popular culture, we just glorify it because it's older than the word we made for it. And it's good, of course, but praising it as some kind of pop-culture antithesis betrays lack of understanding of culture itself, and is an example of how many people mistake something that extremely mainstream (but 400 years ago) with arthouse movies.
And to return to the issue of code quality, academia is not a magical land of perfect code. Code I read in academia, in scientific and bioinformatics code, was easily one of the worst I ever read, and I currently work on a huge codebase that started 10 years ago as someone's attempt to learn a new programming language. The "best" code comes either from obsession, or from requirements actually going down to the code quality itself — either because it's used for didactics, or because e.g. reliability requirements demand actual proof of correctness (which is rare, but there's some industrial code that actually has this requirement, see Maeslantkering).
Yeah - these are somewhat fuzzy categories and not diametrically opposed. I just think that there are certain pieces of software that are sort of "high culture" - meaning so influential and well thought out (Unix) or elegant (Lisp) that they merit close examination by later practitioners.
As for academia, I think again there is a difference in intention (publication vs. production code) not necessarily quality. Academics tend to emphasize mathematical/theoretical under pinning and work from the general towards the specific - and some of the best have their eye on some specific applications. Coders in industry tend to work to solve today's problems - and the best do so in a way that is reasonably general and abstracted. Again, I tend to have this as a separate grouping in my mind.
> Haskell, an offshoot of ML. According to a friend in academia who’s studied it, it’s “the Taliban version of ML,” in which it’s all but impossible to write readable code
Can we stop posting this crap, please? TheReg was kinda edgy and cool circa 1998, but now it just seems a forum for trollish and content free articles.
It apparently didn't occur to David that the reason why the code in banks suck might be because they don't actually employ "the very best".
I live in London, arguably the current world financial capital, but I'd have to be fairly desperate to work for a bank. (Not suggesting I'm the very best, of course, but rather taking banker money is like being a whore.)
Two very capable friend of mine went from Game Development to working in different Banks/Trading Houses in London. They both told horror stories of:
- Correcting the interviewer on C++ intricacies IN the interview.
- Very poor process of dev/test/release cycles
- Management of 'uptime' by having c++ devs on call 24/7 with Limo's, hotel rooms etc but no thought to proper testing, regression or postmortem.
- Managers that managed by fear and intimidation
- People who were clearly there because they were the only ones who could understand the shambles of code they'd written and were paid astronomically to not leave. In general they were mathematicians who were presumably great at maths and poor at engineering software.
While they were both very good and have moved on to more interesting ventures they earned more in a few years of pain then they would have in 20 years of game development so it was worth it for them.
> rather taking banker money is like being a whore
What if you're a barber who cuts a banker's hair, is that "like being a whore?" What if you sell software to a banker, or you're a nanny for the children of a banker? Also: do you have any respect for actual women who engage in prostitution?
The other jobs you mention have different power relations compared to the employee / employer relationship, and it's the dynamics of that relationship in investment banks, and their culture, that disgusts me.
Well "illegal prostitution" certainly brings about things that negatively affect communities, but that's not the point I was making, nor the question I was asking you.
You said you have no respect for the WOMEN who engage in prostitution. Why?
My point about drug dealers is that I can see having no respect for the person that deals drugs as they themselves produce harm (they could sell to kids).
antiterra said it better than I could, but I had to downvote you. We're used to techie snobbishness all the time, but calling people whores for working in one sector instead of another is not only stupidly arrogant, it's offensive.
Would it be whoring if you took money from Zynga instead? Groupon? Facebook? Yelp? Or any number of other disreputable companies that have engaged in allegedly immoral/illegal behavior?
It's to do with the attitude of people in banking specifically; that people are easily controlled with money, and those with the most money have the most power. And that's why I brought up prostitution in such a crude way; because it is a power relation that cuts through to things that make us human. It's hard work for the women involved in prostitution to mask that, to retain humanity in the face of their job, as intimate and naked as it is. Working for a banker, with their mindset and contempt for people, feels analogous - not quite as bad, but analogous.
I would say that programmers that have a choice will work on anything but banking software. And it's most likely that talented programmers will be driven by passion and not by money.
"The technology people employed at these companies are considered to be the very best..."
Who considers these people 'the very best'? Compsci majors? The hiring manager? Of course people in that sector are going to say "we only hire the best", but at best they're only hiring the best who bother to apply or that can be recruited. Very very very likely "the best" (by other measures) stay the hell away from finance.
In some industries, having extreme expertise with specific algorithms and other very deep-knowledge of specific business rules coupled with top-notch programming skills is going to be required for some tasks. Outside of that, by and large, superhuman math/algo skills aren't needed as much as other broader skill sets (inter-departmental relations, listening, etc).
It's the mentality of the financial sector: If you spend the most money, you are going to get the very best. If you earn the most money, you are the best. They assume that because they pay more than anybody else, they obviously must have the best talent. It's probably unfathomable to a lot of these people that there are motivations for developers other than financial ones.
Agreed, the programmers I know that work for big banks in London tell me stories about the software culture there. From what I can make out, their projects suck just as bad as most other enterprisey efforts in large firms, but are bigger, with more shouting, and more Machiavellian management.
The little bit of haskell FUD in this article made me largely disregard the rest (although I've heard my share of horror stories about the software s big financial institutions). Once you get past the different syntax I find haskell code to be extremely readable.
Readable to you after years of study of the CS principles and languages behind Haskell, but literally unreadable and undecipherable to the majority of current programmers. This is a major problem, even if you choose to ignore it and remain in an ivory tower.
That said, the actual problem described in the article has this issue at the very core - we have more software we need written than we have people who can write good Haskell. This means that a large percentage of software is going to be written poorly - and the only real solution would be to simply have less software.
Supply-Demand overrides this completely, and so bad software will remain. The true challenge is therefore making software that can be written by the semi clueless and yet still be decipherable enough to maintain. Java and C# seem to have cornered this market to great effect in the business landscape from my experience.
I think current language development trends towards functional programming is a mistake as it caters to such a tiny audience, and more emphasis should be placed on new languages that can force people to write good code.
Is this possible? Dumb example: If someone is hacking together computations of circles without knowing about PI, is there any possible way for a language to help here?
I think a language that can make it clear what the code is trying to do, even when written by someone who has no clue, would go a long way to being able to filter out and fix bad code quicker. If your code is in Haskell, it's going to take a lot of effort to work out what bad code is even trying to accomplish.
I disagree. In my experience, competently written Haskell is quite clear to most competent programmers.
I interviewed for jobs a few months back. When people asked me "solve this puzzle in any language you like", I usually used haskell. The solutions were just simpler and cleaner in Haskell than in Python/Java/etc. Apart from minor conventions they were unfamiliar with (e.g., "What's Maybe"), not a single interviewer had a problem understanding what I did, even though most had never used Haskell.
One company even had me demo some code I wrote (great interview technique, BTW), and I picked a Haskell project [1]. They literally stopped my detailed verbal explanations and told me: "no need to explain getFileHandleOrNothing, this all looks pretty clear and obvious. The only thing we needed an explanation of was your monad, the rest is clear."
You advocate that more emphasis should be placed on new languages that force people to write good code. That's what Haskell and other FP languages do.
So you find the (far more real world) code of Inufu unreadable?
Edit: actually when interviewing people I show them some Haskell code and ask what it does. Most of them do, some answer that they don't know the programming language. Of course I don't give them very difficult stuff, but still; a lot of well written Haskell code is incredible readable, even for people who never saw it. Also, I really assume if you have a CS degree that you played around with functional languages and recursion. My disappointment with a certain country was that almost none (and I interviewed 100s in the past 10 years) of the Masters of CS from that country even have a clue what recursion is, let alone functional or logic programming languages.
Would something like the above code be on your interview? (pow = 1 : [ 2*x | x <- pow])
I'd probably fail it even though I do understand recursion. I don't know Haskell, and the above is rather cryptic to me. I can infer that it raises 2 to a power, but I'm not sure how it works -- both in how it's called (does that define a function? Pow(4) --> 16?) and the why (the last part defines the recursion I assume, but what happens when you need multiple args, and what does it mean?)
If the interviewer is not giving the opportunity that the code is just plain wrong and assures it's correct (which I say upfront) then people can be 'wrong' saying it takes an argument x and get the 2^ or it prints the number of 2^argument or that it will just infinitely loop. All of these are fine with me; you read the code and at least got the gist. It's not brilliant because the list comprehension looks like most list comprehensions in other languages so then you can know pow makes a list which elements are (ordered) 2^[1..n] numbers.
Edit: But to answer your question: yes, I would like to be asked. I did a lot of interviews from the employee side just because I was curious, and, at least in the Netherlands, they never gave me a test. Just looked at my (possibly fake if I wanted) credentials and said yes/no. No tests, at all.
Partially true, it has taken me a long time to learn haskell. However if you want to learn anything there is some upfront effort involved.
I don't get to write haskell at work, but I see its principles everywhere with an additional layer of cruft over the top. Examples include doing functional style programming in python, linq in C#, passing around functions and callbacks in JavaScript and trying to reason about side effects.
I recently learned Haskell and am writing code in it on a daily basis, although I'm still a novice.
In my limited experience, Haskell is like any other PL, you can write clean, readable code or a horrible mess.
My major concern with Haskell right now is with maintainability/changability of code. One recent example that bit me in the ass was: I wrote an elegant solution to check whether a list of files exists, using sth like foldr (&&) True doesFileExist. Then I realized I really need to print out which file is actually missing, but only the first N to avoid flooding the user with error messages. At this point FP becomes a pain IMO, and it'd be much easier to add a counter variable and printfs in the imperative program and move on. Actually this is fairly common, think about adding printfs for debugging: not so easy in Haskell, as IO changes the type signatures of the function and its callers. So, in my limited experience, changing code in Haskell is expensive and its effect are not localized.
Regarding your example, I think that one part of the problem (which you mentioned in the first paragraph of your comment) is that you are still a novice. I cannot claim to be an expert in FP or Haskell, but here's how I would go about your problem.
First, I think your problem really has two tasks to perform: getting a list of files that don't exist, and selecting only a part of those inexistant files. It would make sense to decompose these two tasks into two different functions, and since Haskell has non-strict evaluation, we don't have to worry about generating too much data (list of inexistant files) for nothing. Starting with the function to select inexistant files:
Some Haskellers may prefer to write their functions completely point-free, but I like to have my variables in the code if it helps me read the coder better. And then we can write another small function to select only the `n` first inexistant files:
takeInexistantFiles :: Int -> [FilePath] -> IO [FilePath]
takeInexistantFiles n files = takeM n (inexistantFiles files)
where takeM n = liftM (take n)
(Surely, we'd prefer to just write `takeM` and call it directly on the result of `inexistantFiles`, but I prefered to go with the specialized function.) Someone who knows Haskell better than I do could certainly come up with a cleaner solution, but I think the code is readable, solves the problem you mentioned and isn't any harder to understand than the equivalent imperative code.
and since Haskell has non-strict evaluation, we don't have to worry about generating too much data (list of inexistant files) for nothing.
Be careful here. Because you're in the IO monad, the entire list of files will always be computed first (ie. doesFileExist will be called for every file given).
Non-strict doesn't really buy you much here. The "expensive" operation here will always be executed. At most, you're avoiding converting some list-consing-thunks to a list.
From my experiences with Haskell, it takes a long while to get used to Haskell, but once you do it really pays off, especially in the area of maintainability. It's actually one of the reasons I love Haskell so much. I've been where you are though, and I feel your pain - if you keep at it, it'll get good, promise.
Some things I find help with maintainance : * the type system allows the compiler do a lot of work for you, * types have to be concrete rather than abstract, * if a little effort is applied the unit tests can be amazing, * everything's clearly defined, * codebases tend to be a bit smaller, and once you're used to it, more readable.
In the particular situation you describe, maybe using the "take" function could work?
Yes, the IO stuff can be tricky, I agree, but with practise it's not too bad, and separating IO from pure code gives all sorts of goodness back. There's always Debug.Trace if you need to do a quick bit of debugging by print statements.
I feel the article was being unfair on Haskell there, after all the code example was being deliberately unreadable, and that's possible in any language.
I hope you don't take offense at what I'm about to say, but the code snippet you provided is not maintainable in the sense of not being readable. It sacrifices maintainability for cleverness. As someone above pointed out, sometimes it's better to write 5 lines instead of 2 lines.
We don't write code primarily for the compiler, if we would then we wouldn't be having this discussion because the compiler doesn't mind spaghetti. We write code for the next guy who will try to read, understand and modify the code. As an experienced programmer I can tell you, but you probably know anyway, that in all languages you can write very concise but completely incomprehensible snippets which even you won't understand in 2 weeks.
Honestly, I don't think danidiaz was trying to be clever so much as not knowing about the existence of filterM. A good chunk of the code was just an implementation of it:
filterM' f xs = map fst . filter snd . zip xs <$> mapM f xs
So, given filterM, the code would have looked like
nexist n xs = take n <$> filterM (fmap not . doesFileExist) xs
Which doesn't look clever at all and it's fairly easy to understand.
When a manager walks in with a new requirement, you'd rather be able to do it in 15 minutes than 2 hours, because managerial injections are annoying and you'd rather get back to more interesting work. Sure. I get that.
However, once enough hands have passed over code, with hackish fixes thrown in to satisfy dipshit flavor-of-the-month requirements, then if it's easy to inject complexity without consideration of the loss of conceptual integrity, people will do so. What you get over time is spaghetti. It doesn't happen overnight. Almost no one sits down and says, "I'm going to write a bunch of shitty spaghetti code."
Spaghetti code is rarely written by one person. It's an "all of us is dumber than any of us" phenomenon. Even Google has some spaghetti code, and I've never met an incompetent engineer at Google. (Project and people management would be a different discussion.)
The nice thing about FP is that changing behavior (except for performance) actually requires altering an interface. In a statically typed language, this requires that you make changes elsewhere in the code to accomodate the new information flow. Yes, it's time-consuming, but it also forces you to think about how your change is going to affect the whole system. That's a good thing.
Writing code shouldn't be easy, because reading average-case code is impossible. If it takes 50% longer to write code, but the result is that people can still comprehend it at scale, I call that a major win.
> to think about how your change is going to affect the whole system. That's a good thing.
I don't think you've made a coherent argument why that's a good thing. Putting in a printf for debugging is not spaghettification and does/should not affect the whole system.
You can printline for debugging using the trace function in Haskell. Or use unsafePerformIO, which is usually outlawed for production code but just fine in a transient state for debugging.
On "writing code shouldn't be easy", you're right that this statement, out of context, seems ridiculous. What I mean is that, when there are trade-offs between making it easy to write vs. read code, generally the reader's interests should be favored, because legible code is so rare. Obviously it's better for it to be easy to write code and to read it, but ease-of-writing is a secondary priority for large, production systems.
I pretty much agree with everything you say here. Thanks for the trace and unsafePerformIO tips.
> ease-of-writing is a secondary priority
In my experience, once you have enough experience and witnessed the suck of maintaining crappy code, writing good code is second nature and doesn't take conscious effort.
There's a lot of truth in what you're saying. However, if maintaining shit code turned people into good coders, then there'd be a lot less bad code (because the precursor is so damn common). I think it also requires curiosity, desire to do things right, and access to the right information (which is now trivial if one knows where to look).
What I would actually say is: the differential in difficulty between writing good code and writing bad code should be minimal or, if possible, negative.
Actually I disagree on your first point. My first job was maintainenance programming, and for some reason I stuck around and did it for 3 years. That has taught me the suck of trying to maintain and work with shitty code.
Now, X years later I still tell stories about that first job, and I always remember how I felt maintaining spaghetti code when I write code.
BUT, I find that most of my fellow programmers either have not worked as m.programmers; or have done so but didn't notice it, because I guess they don't have a built-in desire for arete or just didn't want to get upset about their work and chose to ignore the crappy code.
> it also forces you to think about how your change is going to affect the whole system. That's a good thing.
How do you reconcile that with software's pervasive idea of abstractions, which lets us avoid exactly what you say is a good thing?
Abstraction is a good thing, but what I'm talking about here is object-oriented programming. An "object" is something of which one has incomplete knowledge. OOP is, I would argue, about managing incomplete knowledge, on the (correct) assumption that if systems get large, it will be inevitable that people don't understand all the details of what they're working with.
Good abstractions deliver a lot of value. Files and sockets, for example, should be treated as objects, because the client should (usually) be agnostic of how the things are actually implemented. So OOP isn't all bad.
What's messy is a paradigm that gives an unbounded right to inject complexity. Programmers don't have enough autonomy in most corporations to do things right, so the result in most cases of Brownian-motion requirements is an increasingly gnarly pile of hacks. What Haskell does well (being both functional and statically-typed) is punish that style of development while it occurs, making it so that the kludge isn't always the path of least resistance.
Yep, it's a) only syntax (if you cannot get past syntax maybe a you need to get another job) b) a bad example in the article c) an example of how to make code unreadable which goes for every programming language. In general Haskell programmers strive to refactor to a point where you have balance between readable, performant and idiomatic Haskell.
There is no need to torture yourself with insane syntax and I should express that probably differently, but I find the obsession over syntax usually a lack of skills or experience. For instance, there are hordes of programmers screaming they 'cannot do' Objective C because of it's syntax. That's silly.
It's not just bad coders, management is also very responsible. If management doesn't make sure code is at least getting documented and shown to co workers, then a lot of bad code gets written only one person understands and can develop into the shape of his own fetish, and become a problem when he leaves. The second point is that I have seen very senior programmers, as in years, e.g. the guys with multiple decades of experience, that are quite used to dealing with this. When they take code over they can read through it, add the necessary comments, and document the structure, and convey it to others.
Well, not necessarily. There is plenty of good code out there. The dirty little secret of software development is that bad code is an effort sink. Let me run through a few truisms about bad code and see where they lead us, development wise.
Bad code is buggier, so it will require fixing more often.
Bad code is more difficult to understand and sometimes has non-intuitive side effects or method of operation and so working on it will take longer.
Because of the convoluted way that bad code often works, adding features or doing maintenance on it often makes it even more convoluted and difficult to work on.
Bad code typically has lower performance, so it will require more attention to improve performance. Due to the above 3 factors this becomes a vicious cycle of sinking effort into the code only to make it that much harder to work on in the future.
For these simple reasons bad code becomes a huge time sink. Programming tasks involving good code end up taking up a much smaller portion of the developer-effort budget because it's so much easier to work on that code, while the bad code takes so much more effort and often the code base just ends up even worse than before, perpetuating the phenomenon through to the next cycle of development.
The only way out of this cycle is to identify the code that is the main source of bugs and the main sink of effort then budget out more than enough time to tackle it and improve it. But most development shops aren't proactive enough, introspective enough, or set aside enough dev-resources to be capable of doing that. Even though such efforts tend to have an enormous impact on future development.
I think this article sucks, but of course they are right; by far most real world code is horrible. That goes for academic as well by the way; I cringe when I see the code people get As & Bs for in universities. "It has to work" they say and the prof seems to agree. So you can see, yes also in Python, the most incredible constructions which 'work' but are hardly real code and do not work outside of the required examples.
Code in real world companies is mostly horrible, especially when the company gets bigger and older. Spolsky has a bunch of articles about that. To counteract or prevent that you need heaps of money put into it and most companies really don't see the need or actually don't have the funds.
In my own experience, the development process is usually to blame, more than the developers themselves, their capabilities (or lack thereof) or their paycheck.
The project I work for depends highly on usually inexperienced developers and we're using a development process that is task-oriented but at the same time based on continuous feedback and regular code reviews. Should it be any other way, things would quickly degenerate.
That's what happened before I arrived, and we're still (years later) recovering from the damage that that has caused to the code base.
Outside the IT industry, most bosses don't want to hear about code. Coding is actually seen as a pretty trivial step in many cases. It's OK to hire an intern to add new feature X. Writing good code is not properly rewarded - as long as it works, it's stable, no-one complains, it's OK.
Not to mention stuff such as niche technologies, that usually create a barrier to entry that would-be employees have to overcome, thus concentrating the know-how, power and pay in the hands of a few bored people that won't bother learning the next thing.
This begs the question, which textbooks do include or at least address real-world code?
The closest I can recall are those with heavy emphasis on refactoring, because gradually moving from bad to good is usually the best one can hope for in the real world. I'm thinking in particular of Bob Martin's Agile Software Development, because I liked how he made the point in the book that he didn't just arrive at this beautiful code, but achieved it through TDD and refactoring.
I think "bad code" is actually what the most talented developers excel at (see also Duct Tape Programming http://www.joelonsoftware.com/items/2009/09/23.html). A talented programmer knows when it's worthwhile breaking the rules and, by necessity of getting things done, does so on a frequent basis.
Well, this brings up another problem. And that is that software development is not applied computer science. There are plenty of books which will teach you skills on dealing with real-world code (Refactoring and Working Effectively With Legacy Code being two of the biggies) and there are books that will teach you about other important aspects of development processes (such as Code Complete, Rapid Development, Design Patterns, The Pragmatic Programmer, etc. although those books are showing their age a bit these days) but none of those would be considered computer science textbooks.
True, though I don't think this article is really talking about pure CompSci. That would be about as relevant to Register's audience as books on physics.
InclinedPlane mentioned "Working Effectively with Legacy Code," and I'd just like to add that's one of the greatest software engineering books out there.
Feathers (the author) methodologically chose to copy / inspire some of his examples from code he's worked with as a mentor / developer (some of it from his time @ Thought Works w/ Beck, et al.)
The book is similar to Fowler's Refactoring in that it provides some core thought processes / ideology and then a long list of heuristics and techniques for revising/updating legacy code. (I find his definition of "legacy code" as any software without automated testing to be challenging and insightful, especially since it indicts most code written ever. ;)
If you get the chance, you could also consider reading "Clean Code", it doesn't have /as much/ "real world" source but is still excellent.
Most of the time, when stuff I write ends up as 'bad code', it started out as good code, and then got mangled over time due to a series of requirements changes (not necessarily due to bad processes - you often just understand your requirements better as you go along).
This is a fairly natural series of events that can be helped by periodic refactoring. Unfortunately, because each change is small, none of them on their own justify the time required for the refactor. That's when you've got to hope you've got a management team that trusts your judgement, and is willing to carve out the time necessary for this stuff. Most people, alas, don't have that.
Well, first thing, in the Computer Science part of programming, the requirements are very simple and straightforward. For example, implementation of hashing algorithm or HashMap.
You just can't compare the requirements of "science" part with requirements of "real world business system". The "science" requirements are almost laughably trivial. And the documentation of business system will run into thousands of pages.
Now, you say if you just refactored the code, if you saw the "grand design" and rewrote the code to accommodate every little requirement elegantly and with proper abstractions and so on... I will say you would just end up with system so abstract and general, no-one would understand exactly how it is meeting those requirements. Because you would had generalized every special case (where it should've stayed a special case, and that's that).
So in a way, the simple hacked-together awful program might actually make more sense than the elegant and grand abstract program. Because you can follow the hacked-together program, and you can't follow the arhitected program. It's this "abstractions all the way down", where you can hunt abstractions down for "how exactly does it do this one thing" all day, and then find out it's a little config setting in obscure .properties file that actually covers this one business case. (And if it was there right in code, you would be done in 5 minutes. But alas - it's a config option, so to change behaviour, now you must write all infrastructure to support another possible config option.)
I say - bad code is just fact of life in real-world business. You should strive to clean it up, make it elegant, abstract and generalize... but really business just needs to to chug along.
Don't get me wrong, I don't strive for 'perfection'. I passed through the architecture astronaut phase quite some time ago now :-).
Equally, I don't think that the opposite end of 'hacked together' is some kind of AbstractAbstractFactoryFactory extravaganza - that's just a different kind of bad code. To me, good code is code that is simple for other people to understand, and takes basic precautions with respect to being not-too-brittle to change. Every so often, I find that once the code has received enough alterations, it needs a bit of TLC.
> You just can't compare the requirements of "science" part with requirements of "real world business system". The "science" requirements are almost laughably trivial. And the documentation of business system will run into thousands of pages.
I'd say academics are very good on theory, but tend to lack the real world experience of working in teams bound by company processes. They make code for machines and students to read, not for other engineers, I suppose.
On this entrepreneurially-focused website I'm going to offer that you can't afford to be an idealist about both business and engineering- probably neither. Good-enough at the right time in the right market trumps perfection without all the outside business forces lining up every time. If you're an artist at heart, no-surprise, it's far more charming to the world if you're financially successful.
The problem highlighted by this article and the ensuing debate here is that most people in our industry (management and developers alike) talk about good code and bad code in purely subjective terms. Until we learn to talk objectively about the systems we build (where code is just one part of that system) in terms of function (what a system needs to do),
performance (how "good" the system has to do the functions) and economics (the resource constraints in building the system) - you know, like proper engineers do, we'll never move forward. The ugly truth is that would appear that most banking systems are "good enough" - i.e. they are competitive in the environment operate in - despite the horrors that undoubtably exist in their implementation. I see a lot of talk about the consequences of "bad code" but few have the evidence to back it up. It is our responsibility as engineers to measure the performance of our systems in the _right_ way so it becomes painfully obvious where we should focus our efforts to improve things.
An assumption: code is designed [to get things done].
Another assumption: the [thing to get done] will likely eventually be transformed via evolution or destroyed, as all natural things like rocks and species and hydrogen atoms and gluons and the entire known universe starting[?] with the big bang transforms via evolution or gets destroyed.
A conclusion: code that can not be easily changed and evolved will be conveniently destroyed via a complete re-write. This is why "facades" and opaque APIs are so popular - it is theoretically possible to rewrite different components of the code without rewriting the whole entire dang thing.
This is code that is hard to understand(hence the stackoverflow question), making it not easily changed. Not a good sign for the survivability of the code.
JoelonSoftware.com makes a sparse point with this example, in that a "good" coder must understand what this does. He leaves the reasoning up to the reader, likely because he is clever enough not to make any claims that can be disagreed with. Luckily I am not this clever and I will make a claim that follows from my assumptions and conclusion above:
Claim: a "good" coder needs to understand the above type of obfuscated code so that they can evolve it or destroy it safely when they see it.
Note that my claim does not say whether a "good" coder would write code like that. A "good" coder gets the job done, whether it's a write-once-use-once-read-never perl one-liner or a big part of a big program. I only claim that a "good" coder must be able to read it, so that they can change it or destroy it safely.
is absolutely trivial to understand if the reader has taken the time to actually learn the language in which the code is written. Saying this is "hard to understand" is like saying that "Ich liebe dich" is hard to understand. I'm sure it might be if the reader has never encountered German, but that's not real complexity, and it's not unreasonable for someone writing in German to assume that her reader has some competency with the language.
I disagree. I have 16 years' experience programming in C++ (and substantial experience in other languages before that), and I find that an important factor in code clarity is not writing stuff like this.
Yes, you can understand it, but it takes more brainpower to do so than it should, especially once you get beyond trivial cases. It is much better just to write it the long way.
> I have 16 years' experience programming in C++ <
Well, there you go; this is absolutely not idiomatic C++; in C++ (or even in application-level C code) one would (correctly) use language features or a library call to perform this copy.
I should have been more specific; this code is completely idiomatic for standard-library-level C (though standard libraries will generally use more sophisticated copy implementations). If one is fluent in that particular dialect of the C language, then this construct is natural and correct.
Trollish but true. Things will only change when we start to treat code as knowledge and not just a tool. And to have knowledge and not just data that can incidentally be compiled or executed as a program that does something, you also need: meta-data (comments), documentation (always sucks, probably because writing good docs is as expensive as writing the code itself...), history (vcs solves this only if the commits have meaningful comments, bug-tracker data helps a lot but it would be great to be able to easily get from a piece of code to either the written requirement or the bug-request that the code satisfies/solves) and meaningful organization (the UNIX philosophy of small one-task tools, coupled with exposing these tools through web/services APIs is still one of the best ideas in the field - just don't overengineer the interfaces and protocols, keep them thin, keep them dumb).
This is why I don't worry about Kurzweil's singularity. The putative Godlike AI will be littered with catch (e) {;} and non reentrant signal handlers and shit. It's the nature if complex systems.
Yet another reason to work at Google. They're anti- both obscure or clever code (see their coding standards), and so far in my own experience, you get the time you need to get the code right. There are periodic 'testing on the toilet' pieces to remind you to refactor ruthlessly as you go, and, on how to bring up and gather support for fixing technical debt, with your team. I haven't seen this at any other place I've worked, quite the opposite. It's a luxury.
Real world code doesnt suck in my opinion. The issue is that a lot of the time it solves problems that these books don't need to. Its easy to build an alogirthm and print it when you know every edge case.
If you would take the first version of most production code put it in a book and write the problem it solves, I'm sure you wouldn't think it sucks. My exp developer 15years, finance industry 7.
"You are what you eat", when applied to software is something along the lines of "software's eating the world, and the world is turning to crap".
We've all seen it, at least those in the audience that have worked at some corporate of any size.. maybe "start-ups" face similar issues, it's difficult to get a consensus there.
This guy shits all over his credibility by turning it into a language war. He clearly is out of his depth on the Haskell issue, and I know credible people who think highly of q and kdb (which are rare outside of finance, but ubiquitous in finance).
That said, he's got a point, but the only solution he gives is "Include some comments!" I've seen so many shitty comments that I really think this is no advice at all.
Four levels of software maturity. (There are others. This is a simplified model.)
Level 1: Your work doesn't exist until it's in version control. It might be amazing to 2012-era programmers that this could be controversial, because even the laggards have reached L1 maturity, but at one time, it was. (See: the Joel test.)
Level 2: Your work doesn't exist until it has tests at multiple levels (e.g. unit and integration). Otherwise, it has no enforced semantics.
Level 3: Your work doesn't exist until it has well-documented semantics in addition to the tests, which cannot cover all cases. Otherwise, how does one even decide what a "bug" is?
Level 4: Your work doesn't exist until you've provided the resources (e.g. a code walk or an interactive module) to teach people how to use it.
If you're at Level 1, you won't lose source code. If you're at Level 2, your breakage rate will be reduced, and you can run CI. At Level 3, your system integrity will remain decent because you don't end up with those software-as-spec modules that, over time, corrupt the whole system.
Guess what? It takes Level 4 to get good code. Unless there is a culture of teaching (incremental code reviews are not enough) within the company, you will not have good code for very long. Since engineers are intolerant of context switches and in-person teaching doesn't scale, the teaching should be automatic. Interactive modules or, at the least, code walks should come with the technical asset being demonstrated. If people don't know what they are looking at, then how can they be expected to review or maintain code. With the worst code, it's not even clear why it's bad. It's just incomprehensible.
Level 5: your work doesn't exist until it has been formally proven to be correct.
It's obvious that the amount of effort involved in this is so huge that it should only be considered in a select few problem domains. The same is true for the other levels. They're just a scale of increasing formalization/rigor, but you've said nothing to justify why they should be applied universally.
I think it's important to keep in mind that these levels (or something analogous) exist, but different domains have different sweet spots and a deliberate choice needs to be made for each project.
I would go so far as to say going past 2 is generally a waste of time until the code can do something useful. However, when bugs are measured in lives lost and billions of dollars things change.
I think if you talk to a lot of developers they would like to be at a "level 4" as you call it but the pressures and deadlines on them don't allow for that as often as they'd like. Of course it's in the best long-term interest, but management are not doing this type of long term thinking.
I think it's easy to judge from academia where you do an assignment, then move on to the next. But it only takes a couple of years in a real-world environment for code to get incredibly f'd up even if the developers were trying to be diligent. People come and go, platforms go out of style, programming fads come and go and, of course, one or two mediocre people on the team add their code to the mix.
The problem is the low social status of software engineers. We're well paid because of our rarity, but we've done an absolutely terrible job of getting respect for ourselves, so most of our work is treated as a commodity.
Consequently, business people don't trust us to do anything that resembles leadership. It's not just that they won't rely on us. They won't even let us take the time (which is why it's better to just do and ask for forgiveness, not permission) to do anything that involves future orientation or leadership.
The reality is that programming is a leadership role. When you write code and design systems, you will affect how other people work, unless your work is of such low quality that no one can use it.
The result of this is that we have a Greenspun's Tenth Law situation where the failure to address a capability results in it being met in an ad-hoc, ineffective way. Programmers aren't supposed to be multipliers, but such responsibilities emerge naturally and, when they do, the people picked to handle them (usually for political reasons, since business people are hopeless at evaluating software ability) are usually incapable of doing it.
How can you possibly have tests without well-documented semantics? You may have code that you call "tests" and it may print some reassuring messages, but you can't actually test anything without a specification of what the correct behavior is.
Reasoning about your semantics and having the learning of the code be reified are certainly important. So then the question becomes how to incentivize helping that learnng
Come on! He makes one reference to Haskell, links to the SO post on it, admits he has never used it, and all of a sudden he "shits all over his credibility by turning it into a language war"? It's an example of how ugly code can get for goodness sake.
The Haskell code snippet is from a parody of Wikipedia, and is purposefully obfuscated code. Imagine someone holding up a piece of code written in C from an IOCCC entry, as an example of how C is a language to be avoided. Additionally, bringing it up is a total non sequitur, because Haskell doesn't have much to do with the problems the article discusses, and neither does APL.
I think it does ruin the author's credibility. They didn't do the most basic research before including that code snippet, and are just holding it up as a distracting side show. The rest of the screed might have some value, but I'm pretty skeptical of that after reading the last paragraphs.
And one language I’ve been warned about, though I’ve never had the opportunity to use it, is Haskell, an offshoot of ML. According to a friend in academia who’s studied it, it’s “the Taliban version of ML,” in which it’s all but impossible to write readable code.
He follows this with a line of intentionally hard-to-read code.
Everyone who is familiar with Haskell knows that it's possible to write code like this, but it's not common. You have to actually work at it to make truly awful code in Haskell or ML.
The problem of bad software is too big for one post, and there are multiple causation, of course. Mostly it is incompetence, over-management, pay per line of code in a 9 to 5 shifts, while the resulting product is not anyone's problem. It has something to do with forced collectivization and wage labor, while everyone concerned only with oneself.
The good analogy is with writing a poetry and professional writing in general. There are many examples of technical and scientific books produced by two or free authors (they could list ten, but actual work was done usually by no more than a couple). But we haven't seen any decent book produced by a mediocre writers on 9 to 5 shifts. The idea that this will work for programming is very naive one.
Another analogy is engineering, which is also done by few capable individuals with help of others. There are nothing but failures when mediocre groups trying to engineer anything. On the contrary, we had lots of things invented by capable individuals, things that later were polished by later generations.
So, if one looking for an example of good software look at individuals, or small groups lead by one capable visionary, and avoid anything created in sweat-shops. Most of the really good software we have (Lisp, C, Unix, Plan9, Emacs, vi, nginx, redis, postgres, Informix, etc) was created by an individual effort of men of unusual capabilities, and then polished by community.
Good software engineering is as rare as good poetry, and it cannot be produced by any amount of a manual labor.
There are people who can sell you products and solutions, even ready processes which, they say, will guarantee that you can create good software employing mediocre coders in 9-to-5 shifts. It is all Java or Scrum scams is all about.
It is not tools that create software or invent things, it is minds, the same way no typewriter or fountain pen could make one a poet.
What a terrible article. That line of APL is sheer beauty (http://www.youtube.com/watch?v=a9xAKttWgP4) - being ignorant of a language's syntax and not willing to invest the time to learn it is no reason to claim it is 'impenetrable'. I'm sure sheet music, replete with quavers and semi-breves and treble clefs is impenetrable the first time you see it, but once learned is far superior to playNote(double hertz, double duration).
Worse, it goes against his point just a paragraph earlier. The whole advantage of Q/K/J/Haskell style languages is that once skilled in them, the code is much (as in 10-20 times) denser than the equivalent OO-style code, and the entire flow can be grok'ed with ease. There is much less danger of over-engineering in those languages.
The rest of the article is just random presumptions thrown together, for what reason I couldn't say. The best developers work in finance because the money's highest? Yeah, OK then... (To be fair, I think there is a qualifying "considered to be" in there somewhere) K is impenetrable? Hmmm. Haskell is an offshoot of ML and unreadable? Umm, factually wrong.
There's lots wrong with software at scale, and the pressures of financial institutions along with high budgets etc do produce an interesting set of problems, but this article offers nothing new about anything at all in the field.
As an aside, I already don't trust an author when they start off with a claim that textbook code is good code! It's almost universally accepted to be trivialised and simplified to the point of "don't do this in the real world" simply because it has to be. Some of the worst code I've seen has been in textbooks (and that's worst as in "dangerous" rather than as in "badly written and in need of refactoring/replacement/enclosing in concrete).
Edit to note: I think it's actually beyond incompetent journalism and in to plain lying to present a piece of code as evidence of Haskell unreadability when the link to that code on SO refers to it clearly as "obfuscated Haskell code".