Live data from Hacker News

Criminal Overengineering

coderoom.wordpress.com

21–30 of 67 posts

Re: Criminal Overengineering

#21

Earlier quoted context omitted.

> So what's wrong with using a switch statement if all you have are 3 operations? Because you won't always have only three operations. What about division? Exponentiation? Square root? Factorial? Arbitrary user-defined functions? What if you didn't anticipate an operation one of your clients needs? If you use standard OO principles, your client can rectify that problem; if you use a switch statement, they can't. > Ev…

I would guess that 95% of extensible systems are never extended :-)

By the clients, sure. But by the original authors?

This design (it's the basic "convert a switch statement to polymorphism" refactoring) turns a ball of mud switch statement into several independently comprehensible classes. Operations can be understood, verified and tested apart from the whole evaluation apparatus.

No doubt many programmers today massively (perhaps even criminally) overengineer their software, but the fact remains, the example chosen by the author is a really bad one.

Re: Criminal Overengineering

#22
post #3

I completely disagree with the example given in this blog. I don't have time to give a full explaination but I believe the google clean code talks gives a far better arguement than I ever could. On the general principle I agree that overengineering is to be avoided, but I actually think the example shows a clear disregard for Object Orientated principles. http://www.youtube.com/watch?v=4F72VULWFvc

One of my lecturers wrote the following at the top of our course notes: Contrary to popular opinion using OOP does NOT mean "thou shalt make every last thing an object"

Really, it depends on your environment. In Smalltalk, most things are objects. Not surprisingly, it turns out to be easiest to make most things objects. I find that Smalltalk is best when a program is mostly objects, there's a sprinkling of short-ish procedural methods whose workings are hidden by encapsulation, and perhaps a handful of long optimized algorithmic methods.

I suspect that in Self, it's easier to make more things objects. (jk - everything is an object in Self.) Objects aren't quite as easy to use in C++ and Java. The cost is higher, so the opportunities to use objects with a good cost/benefit payoff are fewer. That's all there is to it.

Does this generalize? In most Functional languages, functions are really easy to use, and can be used in flexible and powerful ways. What's the best way to program in them? Why, using functions! Yup, seems to work. Fancy that!

Re: Criminal Overengineering

#23

Argh. Apparently there are two very popular types of article in the software blog world: Type 1: YAGNI (like this example): Do less now. Refactor later as needed. It won't be needed, most likely. Chill out. (All driven by the question, "Dude, wtf? 100 lines of boilerplate for a 5 line case statement? Snap out of it.") Type 2: Architect astronautics: Do more now. Build for the next version. You will need more then, so…

My conclusion, as I watch my own code wander back and forth in the space between the two poles, is: One needs a lot of practice!

Re: Criminal Overengineering

#24
post #7

I don't think I've ever read a rant about code smells which couldn't be trivially fixed with basic functional programming principles.

It also depends on the language. I bought a book about functional programming in Java once. I found it painful.

Re: Criminal Overengineering

#25

TLDR: Don't solve for problems that don't exist.

I think a better way to put it is:

    1 - only solve problems that already exist
    2 - only accept solutions less painful than the problem
Really, if programmers could stick to this, this would be all the methodology we'd need!

Re: Criminal Overengineering

#26

I think this one line sums up my views about a lot of trendy software development practices: > If you're about to take a hundred lines to write what you could in ten, stop and ask yourself this: what the fuck ? TDD advocacy is my pet hate for this today. I read an article the other day that managed to turn Hello, world into about half a dozen source files and dozens of lines of code, all pulled together with a makefi…

Are you sure you didn't see the forest for the trees? As far as I know, there is not a huge industry demand out there for Hello World applications, but there is a demand for simple examples when explaining concepts.

Re: Criminal Overengineering

#27
post #4

Earlier quoted context omitted.

So what's wrong with using a switch statement if all you have are 3 operations? Even if more operations had to be added I'd probably let it grow to the point where the method the switch is in was getting a bit unwieldy then look at refactoring it using a pattern if I really thought it would be worth it.

> So what's wrong with using a switch statement if all you have are 3 operations? Because you won't always have only three operations. What about division? Exponentiation? Square root? Factorial? Arbitrary user-defined functions? What if you didn't anticipate an operation one of your clients needs? If you use standard OO principles, your client can rectify that problem; if you use a switch statement, they can't. > Ev…

[deleted]

Re: Criminal Overengineering

#28
I think frameworks have to be engineered carefully; the use of the strategy pattern in the example is a typical and is very soundly used in a framework. I think the problem is that developers write far too many frameworks than they should. Interestingly enough, it's code that isn't extensible that ends up being a framework -- mostly because the authors have time to focus on documentation, support, user interface and the like.

Re: Criminal Overengineering

#29
post #7

I don't think I've ever read a rant about code smells which couldn't be trivially fixed with basic functional programming principles.

It also depends on the language. I bought a book about functional programming in Java once. I found it painful.

You should seriously consider checking out Clojure. It's awesome.

Re: Criminal Overengineering

#30

Argh. Apparently there are two very popular types of article in the software blog world: Type 1: YAGNI (like this example): Do less now. Refactor later as needed. It won't be needed, most likely. Chill out. (All driven by the question, "Dude, wtf? 100 lines of boilerplate for a 5 line case statement? Snap out of it.") Type 2: Architect astronautics: Do more now. Build for the next version. You will need more then, so…

I feel your pain - I struggle with the same thing. But I think it's possible, to some extent, to have the best of both worlds.

An ideal of clean, logical design actually satisfies both #1 and #2. You don't write any more than you need to, but you architect it sensibly so if you need to modify it in the future, there's a natural way to do it.

A case study: you are responsible for maintaining a moderately sized mailing list.

Type 1: Maintains a comma+newline separated list of name/email pairs in a text file, parse it with a 3 line perl script that sends an email for each regex match. Done in 15 minutes. YAGN anything else.

Type 2: Builds a fully relational model in a database with seperate tables for names and addresses, backed by Hibernate with a complete class hierarchy including AbstractRecords (in case you want to store records other than name/email pairs), RecordFactories (In case we need to generate lists of records from another source), AbstractRecordDAO (in case we need to use a different Database or ORM framework), EmailFactories, AbstractMailerImpl, etc, etc, etc, planning in the architecture for anything anyone might ever want to do with a mailing list.

Both of these are wrong, IMO.

The correct solution is to write one database table, or one cleanly formatted file, with a program with perhaps two classes that abstract apart the data loading and the mailing tasks. One class loads the data into a simple Map structure, and the other that handles iterating the map and doing the mailing.

It only takes a bit longer to write than #1, and is infinitely simpler than #2. It doesn't anticipate every future need, but when one comes, there's a logical point to start adding the functionality. If I have to do something new with the list, I don't have to completely rewrite my program (like #1 does), I just write a new class that uses the existing data structure. Just as extensible as #2, with a tenth of the work. And easy to see what's going on.

Post reply on HN