
How (not) to write Factorial in Java - smanek
http://chaosinmotion.com/blog/?p=622
======
dkarl
_The 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.

~~~
mmilkin
I am very very confused what this post has to do with Java? It has everything
to do with premature optimization and implementation of Design Patterns
unnecessarily... And since Design Patterns are not language specific the title
of this post is wrong and misleading even the conclusion that the author tries
to draw up is of dubious merit ..... The only part of the post that makes this
specific to Java is the comment that the factorial function must be wrapped in
a class.

~~~
dkarl
You're right; convoluted architecture has as much to do with Java as polar
bears have to do with the arctic. They're two completely different things.

~~~
lukesandberg
Fun fact: its called the arctic because of the bears. The word arctic comes
from a greek word meaning northern bears.
<http://en.m.wikipedia.org/wiki?search=Arctic>

And that is also why the antarctic has its name...because there are no bears
there, just penguins.

~~~
al-king
While it's certainly named for bears, that appears to be be a folk etymology:
as the Wikipedia article you link suggests, the Arctic is named for the
northern bear constellations Ursa Major and Ursa Minor, so called since the
time of Homer. The word Antarctic has been in English since the C14th (
<http://www.etymonline.com/index.php?term=Antarctic> ); a continent opposite
to the Arctic was hypothesised long before Antarctica was discovered in the
17th century. Antarctic, then, means "opposite of north" rather than "no
bears" - though I suppose the Ursa constellations were also not in the north
:) and it's a nice mnemonic.

------
DanielBMarkham
Abstraction 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
I 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.

~~~
ollysb
Perhaps the point is that you should refactor your code into modular code when
it's required. In real applications there's a million different ways to
modularise the code, it's extremely rare that you guess which way is right in
the absence of actual requirements.

~~~
sophacles
I would like to add to this, changing some endpoint frequently involves a
single, one-time migration to the new system rather than a requirement to
support the old and the new simultaneously, thus making some of the
modularization moot or just pure overhead vs. a port.

------
blahedo
See, 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
"this post would be a good competitor for"

No XML, SOAP, EJBs, Connectors, Spring.... it barely qualifies as a
(obfuscated) Java architecture.

------
nervechannel
As 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-...](http://magicscalingsprinkles.wordpress.com/2010/02/08/why-
i-love-everything-you-hate-about-java/)

[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
I'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
> 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.

~~~
aphyr
Sometimes I wonder if Java's "classplosion" is actually a subconscious
backlash against the type system. In order to get anything done within the
narrow box of its static type checking, you're forced to apply insanely
convoluted indirection, pushing the code you want to be polymorphic up into
factories and
ByzantinelyComposedClassTaxonomiesWithIncreasinglyUnreadableNames.

I'm not sure how to actually _prove_ that, though.

~~~
rbanffy
If it's a subconscious reaction to static typing, we would see it only in
subjects who already had contact with dynamically typed languages who are
forced to use Java and its straitjacket.

After being exposed to Java for prolonged periods of time, my Python programs
became classes with a main method that was called in an ifmain condition...

------
jcromartie
What 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.

~~~
snorkel
Here'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.

~~~
KaeseEs
Something I've wondered for a while: how does the strategy pattern differ from
just passing a function pointer?

~~~
Raphael_Amiard
There are a bunch of patterns that simply disappear, or are greatly simplified
when you have first class functions in your language, namely, observer,
strategy, visitor, and a bunch of others i can't remember right now

------
brown9-2
Couldn'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.

~~~
cracki
"class-oriented" languages (such as java) attract such people.

OOP seems to be "difficult", so there are lots of "tutorials" around that
"teach" OOP by introducing and combining all those brainless constructs,
without teaching common sense. what you get is code monkeys who believe that
_this_ is decent source code.

every code base should have at least one person dedicated to _simplifying_ it
and questioning every design decision, so all this "just in case" abstraction
gets the knife.

~~~
jcromartie
I think the problem is that OOP is just taught as a way to organize code.

Pretty much everything in our ostensibly OO system could be static methods and
it would work just fine. Objects rarely have instance variables, or if they do
they are just used to set up a method call. Object lifetimes are measured in
single-digit lines of code, and messaging between them is extremely rare.

But that's what people have been taught.

~~~
aphyr
I think you may be generalizing from a particular language culture to all OOP.
This doesn't apply everywhere.

~~~
jcromartie
I'm talking about the kind of generic business app built in blub by a team of
chair moisteners who don't know anything outside of the one language the
project is written in.

It could be Java (of course), C# (just about as likely), or VB (when they get
the idea to use objects), or Python (yes, I've seen it).

------
axod
It 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
But 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.

~~~
axod
I 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.

~~~
gdulli
Culture exists and can't be ignored, but that doesn't mean you have to be a
slave to it. I find the most (perhaps only) annoying thing about Python the
thinking that leads to the zombie-like refusal to deviate from PEP 8 and other
habits/styles that are considered "Pythonic." And the need to defend yourself
from (or ignore) the inevitable criticism that you face as people bikeshed
over details that are completely orthogonal to the quality of your code.

~~~
axod
> "Culture exists and can't be ignored"

Yeah it can, why can't I ignore culture?

I download a tool, and use it as I wish to within my company.

~~~
limmeau
You can of course ignore a language's culture, but then your code will look
and feel surprising to other programmers who are familiar with the language
and its culture. If you're the only person who will need to maintain the code,
fine.

~~~
axod
The programmers I'm ever likely to work with, are good enough that they can
read code properly, regardless of if it fits into a particular 'culture' or
not.

------
lemmsjid
I'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
_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._

Bingo. It's easy to sit back and say "never guess about extensibility that
might be needed in the future." But I posit that there are degrees of
guesswork; that is to say, there's a difference between a wild assed guess
with no basis at all, and a guess based on years of experience solving similar
problems in a related domain. Experience counts for something, and part of
that is noticing familiar patterns (not "design patterns" necessarily, just
patterns in the general) that tend to crop up in certain situations. I think
making some speculative decisions based on the latter form of guesswork can be
a net positive more often than not.

Of course I don't have scientific evidence to back that up, but I believe it
very strongly based on my own experience.

------
rst
The 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>

~~~
joezydeco
Every 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
Only 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
This 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
I 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".

------
ashearer
I'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.

------
jacquesm
The 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
The 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
It'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
Yeah, 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
ld -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.

~~~
jbooth
You mean like mvn assembly? :) I agree on static linking being almost always
worth it, of course.

------
lsd5you
There 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.

------
batterseapower
Obligatory link to the (classic) Haskell equivalent:

<http://www.willamette.edu/~fruehr/haskell/evolution.html>

~~~
iman
I 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, ..."

------
kaylarose
This 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/>

~~~
jcromartie
Just 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
If 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
The 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
Sounds like a code golf assignment in progress.

Actually there might be an interesting contest, cross-language code golf.

------
dabeeeenster
To 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.

------
endtime
>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
That is the big problem of Java: the libraries. They require programmers to
use these patterns, even when it makes no sense.

~~~
giberson
Libraries don't require you to use them. You are free write your own solution
[that makes sense].

~~~
steveklabnik
And also making it really easy to say "bye bye" and move to a language that
has sane libraries.

~~~
meadowsp
Could you point me towards a comparison of an insane java library and the sane
equivalent in a different language?

~~~
steveklabnik
Hello world in Swing: (from here: [http://www.java2s.com/Code/Java/Swing-
JFC/HelloWorldSwing.ht...](http://www.java2s.com/Code/Java/Swing-
JFC/HelloWorldSwing.htm) )

    
    
        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-hibern...](http://www.javaworld.com/javaworld/jw-10-2004/jw-1018-hibernate.html))

    
    
        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.

------
alrex021
> ... self-important masturbatory Java bullshit

Priceless :)

~~~
augiehill
I'm going to use "masturbatory" in casual conversations now.

------
akkartik
The 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
At 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>

~~~
wnoise
If you're at risk of making a horrible pun, you should rewrite. A deliberate
horrible pun is much preferable.

------
moron4hire
I'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.

------
weichi
It'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
In 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
His 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?

------
mithaler
Our company's PHP framework has a system like this in our database logic.

We only use one implementation of it. Ever.

------
giberson
Interestingly, 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
Um, 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.

------
minimax
That 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...](http://groups.google.com/group/rec.humor.funny/browse_thread/thread/9a260fa129930384/aba12607e86a2392)

------
netmau5
Sure 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
I came here to say that: the article can be summarised as "Java guy discovers
YAGNI, gives good funny factorial example".

------
Roboprog
He 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.

------
btilly
What 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.

------
singular
I 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.

------
deepGem
This 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'.

------
mmilkin
Err 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>]

------
loungin
Wow... 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
I 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
Use Readability[1], and stop nagging.

[1] <http://lab.arc90.com/experiments/readability/>

~~~
inetsee
Thank 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.

------
nickolai
Well, 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!"

------
augiehill
Excellent 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.

------
mcasaje
I 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.

------
roadnottaken
This is why I like perl. A one-liner can just be a one-liner.

------
yason
Rule: 1, 2, N.

------
lisper
> The smart Java developer would know when to stop.

But a _really_ smart developer would know not to use Java in the first place
;-)

