12 ms·
How (not) to write Factorial in Java
- loungin 16y agoWow... weird timing of this post. I spent all day yesterday debugging a daemon written by a consultant in Java 4 years ago. To the few above who asked: Yes, there is code out there (in production!) that followed the same path. Needless to say, I spent most of yesterday cursing.
- inetsee 16y agoI feel like a nag. This is the second time that I've criticized a blog post for poor readability. Light gray text against a white (or off-white) background is a fundamental usability flaw. It makes the text very hard to read, and detracts from the content.
- ghurlman 16y agoUse Readability[1], and stop nagging. [1] http://lab.arc90.com/experiments/readability/ http://lab.arc90.com/experiments/readability/
- burgerbrain 16y agoAlternatively, use Readability, and continue to nag. If at any point Readability becomes necessary, it's a pretty good indication that the author should be made aware that their site is crap.
- inetsee 16y agoThank you for reminding me. But Readability is not perfect. Less than an hour after posting this comment I came across a site that could be improved by Readability, except for the fact that Readability did not render the page correctly (it did not show some information in lists). I still believe that pointing out ways that authors can improve the usability of their web pages is useful feedback.
- jws 16y agoThat gray is #737373 which is in the darker half, though not by much and the background is full white. People's vision varies, but it might be worth a check at a black and white gradient with your display to see if it is wonky. I keep one from the bad old days of CRTs at http://jim.studt.net/bw.gif http://jim.studt.net/bw.gif if you want to take a peek. If you see wide, uniform areas then your display needs work. (As does my gradient, now that browsers have a white background by default. You can't tell if there is a flat spot on your righthand edge.) It helps to make a little circle say 1/10th the width of the image with your hand, and look through that. See if each section looks like a gradient in isolation. Your brain lies to you a lot.
- axod 16y agoIt gets absurd very quickly. Anyone who programs like that is a bad programmer. That's the fact. It's nothing to do with the language being used.
- gdulli 16y agoBut you can't deny that each language has a culture that promotes a certain set of practices and styles. If this article had been written about Python instead of Java, no one would have understood what the author was trying to say because it doesn't fit the Python culture.
- ciupicri 16y agoYou're right. The author does mention: The biggest complaint I have with many Java developers is that they develop a whole bunch of really bad habits.
- axod 16y agoI have never cared about, or taken notice of any 'culture'. I agree that some programmers do, but I think you only pay attention to 'culture' if you don't really know what you're doing. These are the programmers that copy and paste code from google and ask questions on stackoverflow all day. Just read the damn language spec/APIs. A programming language is just a tool. You can use it as you wish to. There is absolutely nothing inherant in Java that suggests you should create a mess of Singletons Factories etc. And if you're a good programmer - you won't. Our job as 'hackers' is to not do things the 'accepted way'. To think outside the box. To go against 'accepted wisdom'. That's kinda the point. So just because some idiot in a cube somewhere creates 18 Factory classes an hour in his IDE, and somehow that's become "accepted wisdom" about how Java should be used, it doesn't have any bearing whatsoever on how you use it. I'd like to think we're all better programmers than that here.
- cynicalkane 16y agoFor my short (<3 years) professional career, I've lived almost entirely in Java. I write in better languages for my hobby projects, but working on those you solve different kinds of problems. This heavyweight Java stuff is everywhere. DriverManager. Security SPIs. Hibernate. Spring. EJBs. JNDI. You cannot do enterprise work in Java without running into this culture. And just like poisonous people will poison you, so do poisonous design patterns. I was hacking on a Clojure project, and writing a data access layer, and without thinking started writing a factory-based indirection layer for abstraction purposes before realizing I didn't need one...
- deleted 16y ago[deleted]
- rst 16y agoThe classic on this kind of overengineering is Spolsky's architecture astronauts essay[1]. Which also describes another way to go wrong --- getting so lost building general structures that you actually lose track of the problem that you were originally trying to solve: "... then they'll build applications ... that they think are more general than Napster, but which seem to have neglected the wee little feature that lets you type the name of a song and then listen to it --- the feature we wanted in the first place." Worth a read. [1] Whole thing here: http://www.joelonsoftware.com/articles/fog0000000018.html http://www.joelonsoftware.com/articles/fog0000000018.html
- joezydeco 16y agoEvery OO horror story I've ever been involved with has that same phrase in there somewhere: ...it does not allow us to select the algorithm we wish to use at runtime I'm an embedded programmer so this kind of thinking is alien to me. But really, everyone plans for runtime configurability but is it really needed that often?
- axod 16y agoOnly if you don't know what you're doing and need to write several algorithms that you can try out at runtime :/ It's an absurd use case IMHO
- kenjackson 16y agoThis simplification is just as wrong as the blog post. It's very common to invoke different algithms based on specific instances of the data. To give a baby example, its typical that one uses a different sorting algorithm as a function of size and data distribution and key type. Theres a popular fft package, FFTW, that is based on this as well.
- axod 16y agoI wasn't saying that you can't use different algorithms based on inputs/data/circumstances. The issue I have is articles like this always try to make things stupidly configurable and general - like "I want to be able to hot swap this algorithm at runtime".
- btilly 16y agoWhat is sad is how true it is. I've encountered non-Java programmers who were fond of taking simple stuff and wrapping it in layers of abstractions which provided real costs to no discernible benefit. But the density ( * ) of such is much, much higher in Java. * Density could accurately refer to a number of possible things here.
- alrex021 16y ago> ... self-important masturbatory Java bullshit Priceless :)
- augiehill 16y agoI'm going to use "masturbatory" in casual conversations now.
- deleted 16y ago[deleted]
- blahedo 16y agoSee, I just read it as satire and whimsy, and I thought it was great---I was laughing by about a third of the way in. Perl and C have their obfuscation contests; clearly the analogue for Java would be the overarchitecting contest, which this post would be a good competitor for. ;)
- arethuza 16y ago"this post would be a good competitor for" No XML, SOAP, EJBs, Connectors, Spring.... it barely qualifies as a (obfuscated) Java architecture.
- Tycho 16y agoAgreed. I kept imagining someone asking this guy to write a factorial function in a job interview, and then he puts this up on the whiteboard, as they watch dumfounded. That'd teach them alright.
- SandB0x 16y agoIt's C#, not Java, but you may enjoy...Enterprise FizzBuzz: http://code.google.com/p/fizzbuzz/ http://code.google.com/p/fizzbuzz/ http://code.google.com/p/fizzbuzz/source/browse/#svn%2Ftrunk%2Ftrunk http://code.google.com/p/fizzbuzz/source/browse/#svn%2Ftrunk...
- Roboprog 16y agoHe forgot to "synchronize" his singleton and cache variables :-) Java: because it pays the bills, not because it's good. (TM) Seriously, I kinda knew what to expect when I waded into the article, BUT, his "punchline" at the end about actually learning the domain of the problem, and jumping in a completely different direction about a O(1) way to generate an approximation in some cases, rather than further crap-plating the "solution", was GOLD.
- lisper 16y ago> The smart Java developer would know when to stop. But a really smart developer would know not to use Java in the first place ;-)
- minimax 16y agoThat certain developers consider needless complexity to be worthwhile is not a new criticism, and it's certainly not as Java-centric as we'd all like to believe. It's an old trope. Consider this "evolution of a programmer" joke which has been around since at least 1990, before Java even existed. http://groups.google.com/group/rec.humor.funny/browse_thread/thread/9a260fa129930384/aba12607e86a2392 http://groups.google.com/group/rec.humor.funny/browse_thread...
- mithaler 16y agoOur company's PHP framework has a system like this in our database logic. We only use one implementation of it. Ever.
- augiehill 16y agoExcellent post. Knowing how and when to restrain yourself is the sign of a truly experienced developer. I certainly did the "planning for the future" thing a couple times before wising up.
- dabeeeenster 16y agoTo me the real danger is that a programmer who has come up with the absurdly verbose answer thinks that they're a great programmer, due primarily to the absurd verbosity of their work.
- brown9-2 16y agoCouldn't this "pluggable architecture" be written in any language? This is more of a rant against "developers" with "really bad habits" than it is against the language.
- simonw 16y agoIt's a rant about Java culture. Culture is an important aspect of any language.
- steveklabnik 16y agoThe Sapir-Whorf Hyptothesis applies to software languages as well as human languages...
- RiderOfGiraffes 16y agoThe current common stance of linguists is that the SWH doesn't hold for human languages. I personally disagree, but I haven't done the formal experiments to confirm my informal belief.
- xiaoma 16y agoThat was true 20 years ago, today not so much. The strongest of the original Sapir-Whorf claims don't hold up, but the weaker ones do. See Lera Boroditsky's work in particular. She's been publishing on this topic for at least 10 years. Most of the good stuff requires a library (or paying), but heres an edge article from a year and a half ago: http://www.edge.org/3rd_culture/boroditsky09/boroditsky09_index.html http://www.edge.org/3rd_culture/boroditsky09/boroditsky09_in... Boroditsky, L. (2003). Linguistic relativity. In L. Nadel (Ed.), Encyclopedia of cognitive science (pp. 917–922). London, England: Macmillan. Boroditsky, L. (2001). Does language shape thought? English and Mandarin speakers' conceptions of time. Cognitive Psychology, 43(1), 1–22.
- steveklabnik 16y ago
- kaylarose 16y agoThis reminds me of the joke about OOP and monkeys[1] Really though, I think this is more related to culture that Java (and many Java books) tends to nurture. Anybody that's read a fair share of "Enterprise" Java code has seen FooBarFactoryFactoryFactoryImpl classes. Hopefully as dynamic languages on the JVM become more popular, this will change. But I find many "Enterprise" developers aren't really interested enough to look outside the box. "jRuby? I think I've heard of that, what's wrong with Java?" "It's not a real programming language unless it's statically typed." [1]http://www.codersatwork.com/ http://www.codersatwork.com/
- jcromartie 16y agoJust for fun, a fairly fast and low-memory factorial in Clojure: (defn factorial [n] (reduce * (range 1 (inc n)))) It's almost criminal how simple it is, yet it's pretty correct. It works for int, float, BigInteger, etc., treats negatives as 0, and throws on non-numeric types. (Edit: needed an inc in there)
- jacquesm 16y agoIf there ever was a powerful argument for expressiveness in languages I think you've just made it in a very hard to refute way.
- mahmud 16y agoThe funny thing is that you could also write REDUCE and RANGE, with one line each. In Scheme you could even write DEFN, again, one line. [Edit: Not RANGE you don't. Let's see how long it takes to get it under 5 lines]
- jacquesm 16y agoSounds like a code golf assignment in progress. Actually there might be an interesting contest, cross-language code golf.
- silentbicycle 16y ago
- jcromartie 16y agoWhat do you do when one customer wants to deviate from the way the product works, and you can't say no? Do you say: if (customerID = 328281) { ... } else { ... } Or do you go ahead and build the architecture that lets you specify which class or method to run per customer? The situation does come up often enough to have to make a decision. I'm working on a project which has tended to say "if (customerID = ..." in the past, but I decided to move to the more configurable/pluggable approach. I'm actually not sure if I made the right decision.
- brlewis 16y agoYou did exactly the right thing: made the pluggable architecture after you got proof it would be useful.
- ldh 16y agoI recall working on one project where those customer-specific exceptions became the rule, and the core business logic was pretty well obfuscated by the time I got there. If your project makes one exception, a whole bunch more are likely to follow.
- snorkel 16y agoHere's my take: 0 customers asked for it: Don't abstract it. 1 customer asked for it: Corner-case it. 2 customers asked for it: Strategy pattern. 3 customers asked for variations: Config option.
- KirinDave 16y agoThis is not a bad plan, but there is a danger here. If you find that "1 customer" (being a series of disparate customers) all ask for various minor tweaks to the way something works, then before you have half-a-dozen disparate forks in your logic you probably do want to pull that out and use a strategy pattern where applicable. It doesn't take many clever sidesteps in a clean algorithm to make a nightmarish scenario later on.
- jacquesm 16y agoI'd roll 1 and 2 together, typically if one customer asks for it today another one will ask for it next week. Save yourself the time and bother to dig back in again and solve it at least for the foreseeable future with less overhead than what it would take to tackle the same task again, typically getting in to do the job takes at least as long as doing the job in situations like that (just to make sure you didn't break anything by accident, test the works and so on). If the overhead is constant and a 'small' fix like that takes 5 instead of 4 hours including all the extras then that's a trade-off worth making. Unless of course you're really under pressure.
- batterseapower 16y agoObligatory link to the (classic) Haskell equivalent: http://www.willamette.edu/~fruehr/haskell/evolution.html http://www.willamette.edu/~fruehr/haskell/evolution.html
- iman 16y agoI was also going to post this. A must read for all programmers. You can overcomplicate things in any language. "The Evolution of a Haskell programmer" is brilliant. Funny and insightful at the same time. Make sure to read the bottom part: "But seriously, folks, ..."
- nervechannel 16y agoAs a counterpoint, I like this quote from Twitter's Nick Kallen: This smacks of the oft-ridiculed Java AbstractFactoryFactoryInterface. But let me put it bluntly: AbstractFactoryFactoryInterface's are how you write real, modular software–not little fart applications. http://magicscalingsprinkles.wordpress.com/2010/02/08/why-i-love-everything-you-hate-about-java/ http://magicscalingsprinkles.wordpress.com/2010/02/08/why-i-... [N.B. I'm not saying there isn't a lot of truth in the factorial article, it's just you have to know which challenges just need a one-liner function and which require an AbstractFactoryFactoryInterface]
- aphyr 16y agoI've read that article twice in the last few months. When I was writing a lot of Java I thought "Oh, you know, that actually makes some sense." Now that I've returned to writing Ruby full time, I look at it and think: "Hey, wait a minute..." All we've done here is forced the programmer to adhere to some ridiculous interface which requires just as much understanding of the internals of the code as overriding the method in the first place. You also end up with hard-to-understand naming schemes, which leads to two points of confusion: 1. Which one of the provided query factories does what I actually want? 2. If I need to write one myself, what would I call it? PerQueryTimingOutQueryFactory? You've added more parts to that name than would have been included in an option to the query function! Oh, and it still doesn't include the information necessary to run, because it folded the timeout specification down into a HashMap. One more thing for the end-programmer to understand. There are good places to use dependency injection. There are also places where Factories are exactly the pattern you need. But in most dynamic languages, you can achieve these effects implicitly through inheritance and closures, and it cuts down the complexity of the code immensely with only a minor cost to reusability. This guy works for Twitter. They control Querulous. He could have just added a :timeout argument which takes an number or a function returning a number to the query method, but now you have to understand all this additional architecture to get anything done.
- rbanffy 16y ago> When I was writing a lot of Java I thought "Oh, you know, that actually makes some sense." Now that I've returned to writing Ruby full time, I look at it and think: "Hey, wait a minute..." And thus you demonstrate using Java for prolonged periods may cause brain damage.
- akkartik 16y agoThe most insidious thing about over-engineering: if something is complex you have to understand it all before you can tell if it's unnecessarily complex.
- Jabbles 16y agoAt the risk of making a horrible pun, I'll point out that the Gamma function is defined for all complex numbers, not just real... http://en.wikipedia.org/wiki/Gamma_function http://en.wikipedia.org/wiki/Gamma_function
- wnoise 16y agoIf you're at risk of making a horrible pun, you should rewrite. A deliberate horrible pun is much preferable.
- unoti 16y ago"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." --Brian Kernighan
- weichi 16y agoIt's true that the "bad java programmers" version doesn't work for negative numbers, but that's actually much better than his version of gamma, which doesn't work for ANY numbers, since it has a bug: Math.pow(z/Math.E, z) should be: Math.pow(tmp2/Math.E, z) So from this I conclude that there are two types of java programmers: those that over-architect their solutions, and those that don't even both to test the code they put in blog posts ;-)
- jacquesm 16y agoIn fairness I think he literally wrote the code the way he claims he wrote it 'as a rant', so it's not surprising he didn't actually test it. If this was written off the cuff without testing it's actually pretty impressive.
- weichi 16y agoHis Gamma function is even worse than I said above, because not only does it have a bug, it doesn't work at all for negative numbers, which was his big bolded complaint about the original implementation. I'm embarrassed that I didn't see this at first, because it should be really obvious - the approximation would be taking the square root of a negative number! I know he would have caught these bugs had he needed to implement these for a real system. But there is nevertheless an important point here. He is 100% right that over-architecting is a bad idea, and that correctness is more important than architecture. But complaining about a factorial function not handling negative numbers, and then "fixing" the problem by implementing the Gamma function, is doing the same thing all over again. It's really easy to fix the factorial implementation to do something reasonable for negative numbers; it's much harder to implement a Gamma function that works for all input. Why bother unless you really have to?
- steveklabnik 16y agoHe also explicitly says "I compiled it, but I didn't really test it, and I'm not sure I copy/pasted it correctly because that's not the effing point" too...
- jacquesm 16y agoThe first time I saw the GNU 'hello world' package it gave me exactly the same feeling. The amount of superstructure piled on top of a simple thing in concept is making programming much less accessible than it needs to be. By the time you understand the scaffolding you've lost sight of the problem. The clojure example elsewhere in this thread it a really nice breath of fresh air, unfortunately it still needs all of java to run, and the number of times I've run in to obscure classpath issues and runtime problems are large enough to remind me that clojure is not entirely free from this sort of heritage either. That does not reflect on the language, but clojure has enough java roots that some of the issues are quite familiar.
- jcromartie 16y agoThe classpath is one of my favorite things about the JVM. In my experience, it's a great way to unambiguously specify what to load. Just look at the horrible mess that is ASP.NET assembly loading: you've got the bin/ directory, Temporary ASP.NET Files, and the Global Assembly Cache all competing when you load libraries.
- jacquesm 16y agoIt's great when it works as expected. Woe to you if your cron job happens to get started with a different CLASSPATH set compared to your regular log in (just one example).
- jbooth 16y agoYeah, but even when it's hard to work with, it's still waaaay easier than ld/gcc, IMO at least. I mean, try to resolve different versions of libraries in Java, it's not easy, but in C, it's hard. Gems and eggs and CPANs or whatever tend to have a lot of the same problems.. turns out it's a hard problem to solve. In Javaland, we at least have Maven :)
- jacquesm 16y agold -static is your friend. I've used that many times for stuff that I need to deploy across different releases of the same OS that as a rule have their devtools removed for security reasons. My development system is typically geared towards desktop use (ubuntu atm), the servers run either redhat, debian or some other flavor and the static trick gives you a slightly bigger executable but the upside is that it is simply drop in and go.
- dkarl 16y agoThe biggest complaint I have with many Java developers is that they develop a whole bunch of really bad habits. Specifications are unclear, or they think someday the code may need to be extended into a different direction. So they write a whole bunch of overblown architectural nonsense, sight unseen, thinking that the additional crap someday will help out and make things easier. This is not fair; Java has moved beyond this. In modern best-practices Java it is no longer necessary or even possible to write big piles of gratuitous OO spaghetti. Today, experienced Java programmers build their applications on top of huge, industry-standard, highly polished piles of architectural bullshit, wrestling with which leaves them with no time to write any code of their own.
- swannodette 16y agoYeah experienced developers building scalable "bullshit" like GMail et al, ITunes Store, Android, etc.
- rbanffy 16y agoFor every example of well used Java, I can easily come up with a dozen counter-examples of insanely complex, unreliable and unmaintainable messes I have encountered in my professional life. It's not worth it.
- mseebach 16y agoTo be relevant to the thread, those systems must be insanely complex, unreliable and unmaintainable, because the Java developers who made them has these habits that Java developers apparently have. To the extent Java correlates with bad software, IMHO the causation is more likely to be that the environments (in the vein of clueless corporate management, waterfall, http://www.halfarsedagilemanifesto.org/ http://www.halfarsedagilemanifesto.org/) are more likely to pick Java for their development.
- rbanffy 16y ago> because the Java developers who made them has these habits that Java developers apparently have. That's the point. Java, it seems, make it tempting to "overarchitect" applications into excessively generic and modular beasts early in their lives when a much simpler implementation would be perfectly adequate and much simpler to extend and maintain.
- giberson 16y agoInterestingly, the factorial function is typically used as a trivial example case for introductions to learning a language. Used for the purpose of learning function calls and recursion and as such we tend to think of it in the simplest context. From that context, the factory function makes this article a great example of over designing. And certainly in some senses the point of the article is quite accurate. However, there exists another less common context for the factorial function--serious usage of the function. Not as an introductory example to the language, but as the basis of actual software that has purpose. In this context questions like memory usage, processing power, and even mathematical precision come in to play. Is BigInt large enough for the required use? Maybe you need to use a class based number type capable of having a limitless value. Perhaps you are targeting a distributed processing system, or a single super computer. Will your computing have memory limitations, processing limitations? Suddenly, when considering real applications for the factorial function, all those satirical over-design considerations are now principal necessities that you'd curse the programmer for not having implemented. Ultimately, the key is scope. It's necessary to know the intended scope of the functionality you are coding. You need to consider who (will use code), how (the code will be used) and where (the code will be used [platform]). In Java, the big GET is the DRY philosophy. An immense library of code is available for your reuse. And it's certainly true when perusing the code base of those libraries you'll see a lot of what might seem like over-designing. However, when you consider the intended scope, it's rarely actually over-designed. Because frankly the scope of most code in the library boils down Everyone (who), Any purpose (what), Any platform (where). In such a scope, simple three liner utility functions seldom are sufficient or appropriate.
- powera 16y agoUm, this problem really is that simple. If you're doing something where you really need many factorials, you use a lookup table (and probably don't call a factorial function at all), or you use a closed-form function to give an estimate. And it's going to be painfully obvious which one you want.
- endtime 16y ago>It’s obscuring the purpose of the code–replacing a two or three line utility (max!) with dozens or even hundreds of lines of self-important masturbatory Java bullshit. I'm not trying to troll, but are there any Java programmers who don't write code like this? I've never seen "real" Java code, which is to say production code, but every time I had to work with Java in school it was pretty much described by the above quote; and what's more, the libraries I had to interact with often made me feel like I was forced to do the same thing.
- coliveira 16y agoThat is the big problem of Java: the libraries. They require programmers to use these patterns, even when it makes no sense.
- giberson 16y agoLibraries don't require you to use them. You are free write your own solution [that makes sense].
- steveklabnik 16y agoAnd also making it really easy to say "bye bye" and move to a language that has sane libraries.
- meadowsp 16y agoCould you point me towards a comparison of an insane java library and the sane equivalent in a different language?
- steveklabnik 16y agoHello world in Swing: (from here: http://www.java2s.com/Code/Java/Swing-JFC/HelloWorldSwing.htm http://www.java2s.com/Code/Java/Swing-JFC/HelloWorldSwing.ht... ) import javax.swing.JFrame; import javax.swing.JLabel; public class HelloWorldSwing { public static void main(String[] args) { JFrame frame = new JFrame("HelloWorldSwing"); final JLabel label = new JLabel("Hello World"); frame.getContentPane().add(label); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } } Hello world in Shoes: Shoes.app do para "Hello, world" end Hello world for Hibernate: (from here: http://www.javaworld.com/javaworld/jw-10-2004/jw-1018-hibernate.html http://www.javaworld.com/javaworld/jw-10-2004/jw-1018-hibern...) package hello; public class Message { private Long id; private String text; private Message nextMessage; private Message() {} public Message(String text) { this.text = text; } public Long getId() { return id; } private void setId(Long id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public Message getNextMessage() { return nextMessage; } public void setNextMessage(Message nextMessage) { this.nextMessage = nextMessage; } } Session session = getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); Message message = new Message("Hello World"); session.save(message); tx.commit(); session.close(); The equivalent in ActiveRecord: class Message < ActiveRecord::Base end message = Message.new(:text => "Hello, world") message.save You have to set up your schema in both, so I've left that out. These are just the first two that came to my head. I ditched Java so long ago that I'm sure a few hundred more have come up.
- DanielBMarkham 16y agoAbstraction is like salt -- a little bit will go a long way. The time to use it is when your business users can't agree -- one says do it that way, another says do it this way. Or they say it's one way, but they're not sure if it's going to change or not. That's a perfect time to cover both bases. A tiny bit of abstraction applied well can save immense heartaches down the road. A bunch of abstraction applied poorly can make your life miserable. Part of "growing up" as an OOP developer is learning what to do when. Also, this is a good example of why founders and startups use so little abstraction -- nobody knows what the problem is or what's going to change. It's all complete guessing. So might as well get something out the door today instead of playing mind games about what might happen or not based on your imagination of what a user might be. (This is also the reason functional programming maps so much better to startups: you don't have a spec. You just want one thing to go in and another thing to come out. If that isn't what people want, you have to iterate. Completely different paradigm than working in a business environment where somebody gives you ten bucks to go make well-defined change in system X)
- viraptor 16y agoI really agree with some parts. If you expect to grow, you can at least make an effort to keep stuff extensible in the future. Right now, I work with old code every single day. With code written one day assuming that: tax will never change (did twice since then), tax code will never change (changed once), service provider will never change (another one was added, so we have to choose one at runtime based on many dynamic conditions), this modification is needed for only one reseller (file has 10+ lines of if reseller_id == ...). Making things flexible may not sound pretty at the start. But ending up changing 3 apparently completely separate systems to accomodate the fact that you changed the version of some software and the output format needs to be different (hey - why would we do immediate representation, output's not going to change). It looks silly in the example, because it's a simple operation. Now substitute 'factorial()', for 'provision_customer_config()'. You WILL change the backend at some point. You WILL change the endpoint at some point. You WILL change the way the function works completely, but will have to retain the previous procedure for existing users. It's a when not an if question. There should be a saying similar to that about people doing backups: there are 2 types of programmers - those who write modular code and whose who will.
- lsd5you 16y agoThere is a point there to be made, but it is a strawman nevertheless. Code reuse is infact sometimes and often desirable, and even gasp if it does turn up the level of expertise required to use/work with a particular library/framework. The important thing is to realise that their are alternative approaches and dispassionately understand the compromises involved - a judicious use of judgement. Calculating factorials (pretending for a moment that it is occasionally worthwhile thing to do) is only ever 2 or 3 lines and it makes no sense to create a flexible implementation, especially if it is also has to be made efficient. On the otherhand, what about a templating engine? How much string concatanation do you have to do before you can justify using a framework? Now obviously some languages have it built in, e.g. in groovy you can reference variables in scope within strings. This is all very well, and is definitely a nice feature, but ... the abstraction remains more leaky than a dedicated templating engine. In line templates are inextricably linked to the code and this has its disadvantages. When there are clean conceptual breaks to be made in code it is often desirable to do so. I believe it is for this fundamental reason that lisp has not taken off because although it is very powerful, it discourages the creation/maintenance of library code, but in fact high quality library code is better in many situations than just using powerful language features.
- ashearer 16y agoI've come to view layers of abstraction as creating technical rent. This is not the same as technical debt. Each new abstraction layer has a manageable initial cost, but it needs to be paid again every time a programmer revisits the code, by rebuilding the abstraction in his or her head. The worst part is when the layer of abstraction is justified as an intervention against potential technical debt: a small cost now to avoid possible interest payments in the future. When, in reality, the small cost has to be paid over and over, even if it turns out that the requirements never change in the particular direction that the abstraction anticipates. Occasionally the abstraction does actually provide enough benefits to outweigh its future costs, but failure to recognize the existence of those costs leads to poor decisions.
- singular 16y agoI think the article highlights the problem with being made to make decisions before you even have enough information to base those decisions on. Just because your manager thinks you can decide how a project's going to look when done before you've done it, doesn't make it true.
- lemmsjid 16y agoI've seen multiple variations on this article over the years--it usually seems to be directed at Java, and it usually involves solving a very simple problem with the "full stack" of Java (anti-)patterns. I've coded professionally in static and dynamic languages, and enjoyed myself in both worlds for different reasons (I guess I just enjoy coding on a basic level). I recently came back to Java after a multi-year hiatus, and suddenly found myself back in a world where people tend to program in patterns such as the above. The funny part is, my experience has ultimately been positive. I was recently in the position of having to patch and modify a very large Java library (written by some well respected Google guys) because I needed it to do something different from its original intent. The OP would have hated this library--when I cracked it open I found innumerable factories, strategies, observers, visitors, etc. etc. After studying the library for a while (which was frustrating because as a developer I wanted to just dive in and write some code), I started to realize that the patterns were well-utilized and built with anticipation of expansion. In the end, I was able to inject my code into the midst of the patterns at some key strategic points and make fundamental changes to the library. Most importantly, I did so feeling like I had the implicit blessing of the developers, and that the general algorithmic flow of the library was not impacted. What I've found after my return to Java is that the language is so boringly, stultifyingly structured that an amazing thing happens--you can actually weave together an application with thirty dependencies on other libraries and have it work. Libraries aren't walking over eachother and behave in predictable fashions. Developers aren't dynamically injecting code into core libraries because they can't. Now, the library I was patching was the kind of library that deals with real world server-side complexity (managing data across multiple stores, with support for testing environments, etc.). That's where these types of patterns shine. They don't shine in examples like the OP's. If a developer in my organization always wrote code like that, I would hope they would be let go. But if they wrote code like that where it was needed and useful, I would be quite happy with them! Conversely, if a developer thought such patterns were never necessary and were never useful, I would think they needed to learn their craft a bit more. In the end, it's all about pragmatism and experience. Over the years I've been bitten for over abstracting and under abstracting. Over the years you develop a weather sense for how extensible a particular piece of code needs to be.
- mindcrime 16y ago
- roadnottaken 16y agoThis is why I like perl. A one-liner can just be a one-liner.
- nickolai 16y agoWell, much as I dislike java, This is more of a developper problem with inexperienced people overabusing the lasagna antipattern. ->"Having a problem? Thinking you might have one in the future? Just add an abstraction layer! Abstract your troubles into nothingness!"
- mmilkin 16y agoErr Ok... you have a point to make but it is not what you think it is. :) It has nothing to do with Java Programmers. It has everything to do with premature optimization and implantation of Design Patters for the sake of Implementing a Design Pattern ... for more information on what I am trying to get at please read Refactoring to Patterns [http://www.informit.com/store/product.aspx?isbn=013265119X http://www.informit.com/store/product.aspx?isbn=013265119X]
- netmau5 16y agoSure expended alot of effort to say YAGNI. Not sure I understand the condescending attitude towards Java developers in general either. I can write stupid code in any language.
- StrawberryFrog 16y agoI came here to say that: the article can be summarised as "Java guy discovers YAGNI, gives good funny factorial example".
- yason 16y agoRule: 1, 2, N.
- mcasaje 16y agoI think that we all need to remember to K.I.S.S. At least those people who have to urge to add unncessary complexity to simple programs need to remember.
- deepGem 16y agoThis article reminds me of an application we were developing for a health care billing system. Back in the days when Spring 1.0 was evolving and was the 'hip' technology, architects had used spring, and had written wrappers around spring. No one could make the head and tail of these 'wrappers' except for these few 'talented' individuals. I mean, as if Spring wasn't slow enough, the wrappers made the application even slower. Finally, management went berserk over the application performance. It's ridiculous how the developers wanted to create an aura of exclusivity by using some technology that was probably not required at all. Oh and Amen to 'Brevity is the soul of wit'.
- moron4hire 16y agoI'm going to echo that this is not Java, this is just OOP ideology specifically and the culture of programmers generally. It's this sort of programming that has made me seriously reconsider my life choices. Programmers are very opinionated people, and that's great, they're just shit at acknowledging other people's opinions. Here's the thing. Most code that is written in the world is not difficult code. It's pushing data between clients, databases, and consumers. Wrap that shit up in a web interface. Put a transaction log on top of it. Whatever. It's not hard. But some idiot with an MS in CS has to justify their existence. This should be a solved problem by now and we get every Tom, Dick, and BS fucking CS trying to come up with their own solution, complete with articles and white papers on how wrong you are for not doing it their way. I'm sick of the judgmental nature of it all. There is a common phrase in my current office--a certain bit of buggy code is "Doing it Wrong" (and yes, the capitalization happens). In the cases I've seen there, there was certainly a wrongness to the code, but there is no "right" solution, and the proposed fixes weren't any more "right" than the original, they were just politically favored patterns. I need to get out of programming because I hate programmers. The stereotypical programmer is a culture fascist. He sees one way and only one way.