9 ms·
Anti-Patterns Every Programmer Should Be Aware Of
- kristopolous 11y agoI read this many years ago. Let me find the source. Edit: I can't find it. Anyone else remember reading this? The mysql job queue reference was from a popular article that went out about it at the time Edit 2: the job queue article is from 2011. Edit 3: still can't find it. But I know every part of this article before seeing it ... I tested myself and remembered all the details... Where is this thing from? Still can't find it. My confidence in the permanence of the web is pretty destroyed right now. I can't even find references to it existing.
- jrgnsd 11y agoI think you're referencing this article about MySQL job queues: https://blog.engineyard.com/2011/5-subtle-ways-youre-using-mysql-as-a-queue-and-why-itll-bite-you/ https://blog.engineyard.com/2011/5-subtle-ways-youre-using-m...
- kristopolous 11y agoYes. This article came out after that. I realized a few paragraphs in that I had read all of it. I tested it by guessing the content and was 100% correct. But I can't find it. This isn't the first time I wanted a searchable version of archive.org that effectively timecapsuled the interactive internet. Things fall off the net far more than common folklore suggests Anyone got $10 mil to drop on that project?
- cxseven 11y agoI'm glad to see someone else echoing my anxiety. I had the impression that Uniform Resource Locators were meant to be treated as bookmarks into a web of knowledge, so it's like brain damage when they break. It's too bad it happens so frequently, because for a few blissful years my urge to hoard was quieted by the assumption that the internet was doing it for me. Those enormous URLs that describe nothing but a document GUID are also a sin.
- kristopolous 11y agoI made a service called http://rt2.me http://rt2.me which tries to semantic-ify the URLs ... but I seem to be the only one that likes it.
- mercer 11y agoI've resorted to capturing every single interesting link as a complete HTML page to DEVONthink, which is a mac application specifically meant for storing large amounts of data. It's already proven quite handy in two ways: 1. I can access articles that have disappeared off the net 2. I have a very powerful search function and 'similarity engine' constrained to only the information I've found useful so far. It's often the first place I look for certain kinds of information before I try google. I can strongly recommend using such a tool to make sure you don't 'lose' stuff on the internet that is important to you.
- unionpivo 11y agoAnyone know of anything similar for linux or windows? Right now i am using chrome, to save whole page as zip, but that becomes in-convenient when you have several hundreds of them.
- smegel 11y ago> "Magic Numbers and Strings" I don't know about this one...we need something have a chuckle (or cry) about over beer after work, and to make sure software archaeologists in 100 years time have an interesting job (not to mention plenty of opportunities to write blog-spam)!
- mreiland 11y agoThat one stuck out to me as well, but for a different reason. I think the idea that "explicit is better than implicit" is a good idea for more than simply "magic numbers and strings". I much prefer seeing the code in front of me than having to jump through multiple functions across several source files + tracking down the configuration values I'm looking for because someone decided to use DI. I'm not saying DI is a bad practice, but unless you really need it, prefer explicit dependencies. And on and on with just about everything you do, if all things are equal, prefer explicit over implicit.
- s_tec 11y agoIt's not bad advice, if used in moderation. The problem is that most developers take it too far, to the point where no number is safe from becoming a named constant. My default these days is to write numbers as numbers, plus maybe a comment if things are unclear. I only turn numbers and strings into named constants if they are used in more than one place, or if they are true configuration values that need to be tweaked. This makes the program easier to read (the ultimate goal) by avoiding the need to jump around in the codebase. Comments are better at explaining things than cryptic variable names anyhow.
- sken 11y agoDefinitely, although there can also be refactoring benefits to look out for. In the article example it would be much easier to change the default popup window size (800x800) across the project if they're all using the same variable. On the other hand, tools like CheckStyle can make people do some strange things when they take it too literally. I once reviewed code that defined: static final int ONE_HUNDRED = 100;
- NoMoreNicksLeft 11y agoHalf afraid to read this, I think they might be our programming conventions at work.
- allan_s 11y agofor " Writing a task scheduler for your web-server in PHP" Is the author talking about "at" and "cron" instead ?
- jrgnsd 11y agoThere's a number of solutions, depending on your stack: at and cron are good OS level solutions. Sidekiq is great for Ruby. I think the problem lies in that PHP wasn't designed to be a long running process, and for a scheduler you need something long running.
- contingencies 11y agoHaving done this (years ago), there are good reasons sometimes. At the time I was working on a relatively complex hotel reservation system with a distributed database and the need for batch execution of background processes (things like sending emails and digital fax from a queue). The master interface to the database was a series of PHP functions since the data massaging that had to occur (to facilitate correct interaction in multiple human languages across disparate timezones versus user preferences and time of day, etc.) ruled out direct DB access from anywhere else, back-end processes included. I think the end solution was something like 'every minute run PHP X from cron, which checks if there are jobs, if so successively spawn children to handle'. It was basic but it worked. Godawful pain with MySQL replication over lossy Chinese internet WAN ... never again.
- jrgnsd 11y agoI inherited a similiar system. It was painful to say the least. I didn't realise how painful until I started using proper queueing systems and Sidekiq.
- contingencies 11y agoSidekiq doesn't really look that different to what we used. Anyway, neither decent ruby unicode handling nor RoR nor sidekiq existed back then. I actually considered rewriting the whole system in ruby at one point, but the unicode support was still dodgy.
- arbsn 11y agoSurely the purpose of the LabStack example is to restrict the interface of a LinkedList to that of a Stack? Defining a new type to present a more restricted interface is not useless... it helps one reason about what has or hasn't been done to an object.
- DSMan195276 11y agoI agree - Defining a 'Stack' class is useful even if it's just a wrapper over LinkedList, because stacks have an expected way to act, and while a LinkedList fits the bill it does more then a stack actually has to do. And with that, nothing says you have to implement a 'Stack' with a LinkedList, it's just an easy way to do it. By defining the 'Stack' class, you could always go back and improve it to not use LinkedList and instead do it yourself. That said, I do agree with the author that, in the context of a programming class, writing the 'LabStack' class is absolutely useless because it teaches you nothing about actually using a linked-list to implement a stack, which I'm sure was the real intent of the assignment. The 'LabStack' class is useful in the context of being used in a larger program, it's not really useful for learning how to actually implement a stack because it just passes the implementation off to 'LabStack'. (That said, because Java doesn't support defining objects as value-types, using the 'LabStack' interface adds an extra level of indirection you may want to avoid - You have to access 'this.list' to get the LinkedList object, instead of just accessing it directly. This is more a fault of Java then anything else though.). The note about programming class isn't really relevant to programming as a whole though, which is where the disconnect happens.
- xxs 11y agoUnless the stack has to be lock free, array backed ones (ArrayDeque in java) are better on the current hardware.
- sulam 11y agoYou forgot the most important anti-pattern of all: "Not Invented Here". The urge to rewrite things that you encounter is strong in software engineers, and you should always be suspicious when you find yourself thinking "I could do this so much better." Especially when it's true!
- vosper 11y agoThe "not invented here" pendulum has swung a long way, and I think that there's now a real, hidden anti-pattern in industry: "never invent here". At some point, it's important for us as programmers to indulge that "I could do this better" instinct. If you're right you could make a real contribution to your employer or the community. If you're wrong then you'll still be a better engineer (and possibly a domain expert) for the effort. If everyone embraced "not invented here" as a philosophy then the whole industry would stagnate.
- wvenable 11y agoMost of the time I can do it better because my problem space is so much smaller. And sometimes I look at components and I'm so disgusted by the code or the API that I merely use it as an example and re-write the code for my own purposes. Just because somebody put it on Github or built a package doesn't automatically make the code good. Most of the "not invented here" I come across is from developers who never look for 3rd party solutions. It doesn't even occur to them. And it's usually obvious stuff like XML or JSON parsing! Which is why the message of "Not Invented here" is a good one to repeat over and over.
- kybernetikos 11y ago> Which is why the message of "Not Invented here" is a good one to repeat over and over. So, there is a problem where many developers would rather work on abstractions rather than concrete value-providing things. I suffer from this myself - if abstractions weren't interesting to us, we wouldn't be working in software. However, over the years I've discovered that many software projects are gaining negative value from some of their libraries, and I'm not sure which is the larger problem. http://yosefk.com/blog/redundancy-vs-dependencies-which-is-worse.html http://yosefk.com/blog/redundancy-vs-dependencies-which-is-w... describes the essential problem.
- Sami_Lehtinen 11y agoIt's nice to notice that top three actually does not have anything to do with programming. Those are absolutely general issues when ever doing anything at all.
- lugg 11y agoIf you're a dev and have never read these two wikipedia links, I highly recommend it. http://en.wikipedia.org/wiki/Code_smell#Common_code_smells http://en.wikipedia.org/wiki/Code_smell#Common_code_smells http://en.wikipedia.org/wiki/Anti-pattern#Examples http://en.wikipedia.org/wiki/Anti-pattern#Examples
- petjuh 11y agoI read A Big Ball Of Mud while in high school, left a big impression on me. Unfortunately, I've since seen that my projects all gravitate towards it at the end.
- Xophmeister 11y agoI'm pretty sure this is just the nature of the universe; increasing entropy and all that.
- quickpost 11y agoThose are great resources - thanks for sharing!
- Hermel 11y agoHow could they forget premature generalization?
- leni536 11y agoI always fall into this.
- acbart 11y ago#5 is a classic example of the Expression Problem[1]. Are you trying to add more shapes or more functions that operate on shapes? http://c2.com/cgi/wiki?ExpressionProblem http://c2.com/cgi/wiki?ExpressionProblem
- Kiro 11y ago> God Class I don't understand how to avoid this even if you break it up in smaller classes. You still need a point of entry where the logic begins and where it is decided which components to use. ThIs always means some kind of Manager or Main class for me. How do I fix it?
- adrusi 11y agoWell there's an entry point of course, but it shouldn't know much. Your entry point knows about your option parser which knows about the high-level actions your program performs which know about the sub-processes involved in accomplishing them, etc. It's important to keep this graph as acyclic as possible, and to try not to have any one component directly interact with too many other components, because then your abstraction is too fragile.
- kibibu 11y agoTake it all with a grain of salt. Here's a (vaguely) contrasting view from John Carmack: http://number-none.com/blow/john_carmack_on_inlined_code.html http://number-none.com/blow/john_carmack_on_inlined_code.htm... The main takeaway is that inlining a bunch of code to flatten the dependency tree may actually reveal problems and reduce your maintenance burden.
- fsloth 11y agoI think example 9. (the stack that wraps a linked list) is not a necessarily an antipattern. Removing degrees of freedom and adding obvious constraints make systems simpler and easier to comprehend.
- ffn 11y agoI like how the first three or so anti-patterns are in the exact opposite direction as the last three or so. The art of being a programmer is literally "don't waste time over-thinking things, but also don't ship under-thought trash". For all our fixation on simplistic and ease of use, programming is actually incredibly difficult and way more art than science. And it's exactly this requirement of masterful manipulation of balance that makes me love this field so much and long to get better at it. Getting a handle on the artsy spirit of programming is really what separates the wheat from the chaff in terms of programmer skill. There is no formal programmer guild in real life, but if there was, and there was some sort of test a journey-man programmer must undergo in order to become a master programmer, it would be the test of being given a large project and then deciding correctly exactly how much technical debt to take on to be able to ship a product within a reasonable time-frame and yet have its internals not be complete unmanageable spaghetti.
- bottled_poe 11y agoIt reminds me of the quip: "I can deliver your project quickly, cheaply and of good quality - pick two". That said, in my experience, clients tend to see software quality as the least important attribute of the three.
- noonespecial 11y agoI always tell them, "You can have what you want quickly or you can have what you want cheaply, if you insist on both, you won't be getting what you want."
- anon4 11y agoThe cheaply part puzzles me. If it takes X hours to build something, it doesn't matter if you work D hours per day for X/D days, or D/2 hours per day for 2X/D days -- it's the same amount of hours, therefore the same amount of money. The client will pay less per day, but the same amount overall. You could charge on a curve, i.e. 8hrs/day is X, but 10hrs/day is 2X, but we all know overtime doesn't work in the long run. It seems to me, that that saying works for only the small set of tasks that can be worked on in consistent overtime. Can someone clarify?
- jammycakes 11y agoI always get a bit nervous when I see Knuth's quote about premature optimisation. While the points the author makes are valid, the fact that it gets bandied about as an out-of-context sound bite results in a lot of code getting written with a complete disregard for any optimisation whatsoever. Another far more common antipattern that isn't mentioned here is premature abstraction. You see a lot of this in enterprise .NET codebases -- such as the widespread "best practice" to build ineffective and obstructive abstraction layers "just in case you might want to swap out Entity Framework for a web service."
- acqq 11y agoI've heard about the same "ineffective and obstructive abstraction layers" in Java too and worked with the C++ code base where some development managers introduced such things, because "they're the managers, the must design with abstractions, the underlings can think about the details, and ho-ho, we certainly shouldn't be bothered to make something effective, don't prematurely optimize, everybody knows that, ha!" So I consider it the effect of the"culture," "environment" and "organization" more than the particular language. It didn't help that the "patterns" were introduced exactly as the unstated promise to the managers to give them a "meta" approach. Like UML before etc. And that people started to think the more abstractions they force in the code, the better it becomes. My favorite problem description is by Rico Mariani: "The project has far too many layers of abstraction and all that nice readable code turns out to be worthless crap that never had any hope of meeting the goals much less being worth maintaining over time." http://blogs.msdn.com/b/ricom/archive/2007/02/02/performance-problems-survey.aspx http://blogs.msdn.com/b/ricom/archive/2007/02/02/performance... But in my opinion all big enough projects can be saved by redoing just some part of them.
- Frqy3 11y ago"No need to worry about optimisation, modern compilers can handle that for you." /s
- Zardoz84 11y ago> Another far more common antipattern that isn't mentioned here is premature abstraction. You see a lot of this in enterprise .NET codebases -- such as the widespread "best practice" to build ineffective and obstructive abstraction layers "just in case you might want to swap out Entity Framework for a web service." And Java codebases
- dvh 11y agoMost of the evil done in my company seems to be by Ctrl+C Ctrl+V and then changing 1 line of code.
- stinos 11y agoSame here, unfortunately. It drives me nuts. It's oh so easy and tempting to vialoate the DRY principle. But what's even worse is people actually defending their Ctrl+C Ctrl+V behaviour with false/uninformed arguments such as - why waste time with creating a function when I can copy-paste? - but I'm never going to have to change this code anymore - but it's more readable else I have to figure out what the function will do, browse to it, ... (well, good luck navigating any codebase at all) - but it occurs only twice (ok, twice is debatable, but still: before you know it the same is used again in another place an there we go again..) - but it's faster because it doesn't require an actual function call (this is by far the worst one: they claim this without having even measured it, without having checked if there even is a bottleneck, without realizing that in compiled laguages any decent optimizer would inline and generate assembly anyway)
- aidos 11y agoEnjoyed this list. Over the years I've become better and better at spotting these issues, but even still sometimes it's hard to see them creeping up on you. The worst for me these days is analysis paralysis. I'm currently working on my own so I don't have anyone around to bounce ideas off. For smaller tasks it's not a problem, but there are bigger design decisions that have ended up taking longer than probably should. When you're left to figure them out on your own it takes a lot longer to convince yourself of the "better" way of doing something.
- valisystem 11y agoTo me, the problem in choosing the "better" way of doing something is that I can't stop comparing diverging design choices. I like to think that the best way to choose between seemingly equally advantageous designs is to start with the one whose first step(s) is(are) the most straightforward. The thing is, while I prepare myself for implementation of that first step, I've a background loop in my mind that constantly checks against other implementations choices. What I am losing here, what I would gain otherwise. In the end, I never really make definitive decision before starting. I start with that background brain noise on the “most simple first step design”, and when the background noise stops and the raw pleasure of coding kicks in, I known I'm on a good track.
- aidos 11y agoI guess I do go through that process once I start work, but I'll definitely keep your advice in the back of my mind. Don't let the choice become overwhelming, get started knowing that it's ok to change your mind during the process. For any feature / bit of work that's in isolation, I don't really worry. I figure out an approach and I implement it. When it comes to changing data structures / larger changes within the product there's a fear of getting it wrong and having a mess to unpick later.
- chriswarbo 11y ago> Fear of Adding Classes I've seen this a lot, and is often made worse by attaching a load of unnecessary baggage/repurposing to classes. For example, I've worked on PHP projects which, over time, have gained coding standards like: - All classes should be in separate files, named to match the class name - All classes should be built from a PHPSpec specification - All classes should have their own test class - No class can instantiate another, unless it's a "Manager" class which does only that. Everything else is dependency injected. - Test classes can only instantiate their associated class; everything else must be mocked And so on. Now, each of these has its merits, but as each new practice was added, it increased the 'fear of adding classes', even if just subconsciously. Refactoring to break up classes became less and less common, since a simple code change would require: - Whole new test classes (OK) - New files (seems a bit like Java-envy, but OK) - Injecting new instances wherever the old class was used (seems a bit overkill...) - Mocking the behaviour of the first class in tests for the second, and vice versa (this is getting a bit silly...) - Creating 'Manager' classes to instantiate the new classes (hmm...) - Creating new test classes for these managers (erm...) - Mocking the dependencies of the managers... In the end, it was just far easier to just throw all new logic into existing classes, which grew and grew.
- mercurial 11y agoI've worked on a codebase where objects inherited from a class named "Abstract" which contained, apparently, methods used in more than one class, regardless of purpose. Other fun anti-pattern: make a Facade class hiding services. Then: - add logic directly in your facade - make the services using the facade depend themselves on the facade (circular dependencies FTW) This an excellent way of ensuring your code will NOT be reused.
- eonw 11y agooh come on, circular dependencies are fun and you know it! ;)
- erikb 11y agoI'm a little confused. I'd say that an anti-pattern is something one can avoid. Sure, I can think about every optimization I'm doing, and if I already know well enough that I'll need it and doing it right. But I can't really avoid discussing about something that is unimportant in my eyes, because the person who will discuss about it usually thinks it's important. I'd say that in the "bike shedding" regard my anti-pattern would be that I ignore some complaint as unimportant because I still don't understand it well enough. Other things are also hard to avoid by myself, like - God Classes (I could refactor here, but then the anti-pattern is fear of refactoring) - Management by Numbers (I'm not a manager, what can I do about it? Actually I'm happy if my management is already that good that they have numbers. Nothing is more horrible than management who doesn't tell you explicitly what they want and then complains about details for half a year, then starts with the next project without declaring the last one to be finished or anything. I'd say numbers are good, finding the right ones is tricky, though.) - Useless classes are avoided by simply not writing them? No, they develop when code gets refactored and nobody had looked at the responsibility of that specific class for some time. Nobody writes classes without having a goal for them in mind. Mostly calling methods of another class is fine. It happens in design patterns like Observer, Delegator, or Compositor.
- dmichulke 11y agoIsn't it blasphemy to quote Greenspun's tenth rule right after insisting in two consecutive rules that people create enough classes?
- current_call 11y agoNo, because CLOS is awesome.
- techar 11y agoIs https://en.wikipedia.org/wiki/Facade_pattern https://en.wikipedia.org/wiki/Facade_pattern a God class? I like the idea if it only delegates to other classes. Its downside is the dependencies to many classes.
- paulus_magnus 11y agoHaving worked for big corporations in Europe, I'd like to see manager types spend 10% of time technical people spend on self-optimising themselves, their working environment, post-mortems, understanding antipatterns, productivity etc.
- jongdubois 11y ago"It seems that perfection is attained, not when there is nothing more to add, but when there is nothing more to take away." Great quote - It reminds me of the story of when Michelangelo unveiled the statue of David, someone asked him how he managed to create such a masterpiece and Michelangelo answered "It was simple, I just chipped away all the rock that wasn't David".
- lukesan 11y ago"To clarify, add detail" - E. Tufte I don't think reduction only leads to perfection. If it would be, then our starting point must always be the right one. But in practice you start somewhere, reduce, move forward, add stuff, move sideways, try out and test. Sometimes you need to add stuff to make it clearer to your users.