by someone13 on 2/12/13, 2:59 AM with 145 comments
by haberman on 2/12/13, 6:06 AM
I think this is a good point. I think that it's hard to get from there to "more classes are always better" though. More classes don't always make a design more flexible. You have to consciously design for flexibility and reusability, and even then it takes a lot of deep thought and hard work to get your interfaces right, such that they are truly reusable in practice.
by contingencies on 2/12/13, 6:06 AM
Joe Armstrong: "I think the lack of reusability comes in object-oriented languages, not in functional languages. Because the problem with object-oriented languages is they've got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. If you have referentially transparent code, if you have pure functions-all the data comes in its input arguments and everything goes out and leaves no state behind-it's incredibly reusable. You can just reuse it here, there, and everywhere. When you want to use it in a different project, you just cut and paste this code into your new project. Programmers have been conned into using all these different programming languages and they've been conned into not using easy ways to connect programs together. The Unix pipe mechanism-A pipe B pipe C-is trivially easy to connect things together. Is that how programmers connect things together? No. They use APIs and they link them into the same memory space, which is appallingly difficult and isn't cross-language. If the language is in the same family it's OK-if they're imperative languages, that's fine. But suppose one is Prolog and the other is C. They have a completely different view of the world, how you handle memory. So you can't just link them together like that. You can't reuse things. There must be big commercial interests for whom it is very desirable that stuff won't work together."
- Peter Seibel, Coders at Work: Reflections on the Craft of Programming
by 10098 on 2/12/13, 7:29 AM
by Locke1689 on 2/12/13, 7:05 AM
First, write nothing. If you can solve your problem without writing code (or even better, by deleting code), that is the best solution.
Next, write code which fits your architecture. Sometimes functional composition is the best system for representing your computational structure. Tree operations, for example, are especially amenable to recursive function-based computation.
Sometimes, when you are writing a state machine, for example, an object is the best possible representation. Objects are entirely focused around hidden-implementation finite state machines, and thus mirror your computation almost exactly.
Funny how most people who have only practical training in a handful of languages and no programming language theory at all tend to advocate for the one style of programming that they know well. When all you have is a hammer...
Note: The small paragraph at the end of this article seems to hedge by agreeing with me and essentially calling the reader to disregard what he previously wrote. If he had followed my step one he could have avoided writing the entire article. Think of the complexity saved!
by Uchikoma on 2/12/13, 6:34 AM
The one API that is not powerful enough is Collection. There you have the top layer without the LEGO building blocks. Compare this to the Scala collection API which has the top layers and the building blocks.
For a good API you need both, building blocks to tailer to your specific need (20% of the time) and an easy top layer (80%) to prevent writing the same stuff all the time.
by viraptor on 2/12/13, 8:58 AM
Just from the JSON example:
- Why do I need a class for streaming JSON - Python's got a perfectly good `yield` for returning tokens in such situations.
- Why would I ever design the JSON library to be extendable at the tokenizer level? If you need serialiser / deserialiser, why not just provide a map of types to callbacks / callback as a parameter? Do you really want to extend JSON format itself?
- The 2GB JSON example is just weird. If you care about such use cases, you a) most likely have a limit on data size at webserver level, b) use proper formats for handling that size of data (I really doubt there's no better data representation once you get to GB sizes).
I see his point of view, but he's arguing for one single "hammer" solution, rather than arguing against the monolithic design. His story seems to present some weird back-story really: "I needed to make my data easier to handle, so I started automatically serialising objects into JSON, then they became huge so I have to start streaming them otherwise just parsing of them takes way too long".
by fab13n on 2/12/13, 8:20 AM
Now you can bundle related functions together in a structure, but this structure is morally a module, not an object, let alone a class. Some languages will force you to encode those modules as classes / prototypes / singletons, but that's just a design pattern to circumvent a limitation of the language.
by chewxy on 2/12/13, 4:03 AM
Try this:
packer = msgpack.Packer()
serialized = packer.pack('stuff you wanna pack')
unpacker = msgpack.Unpacker()
unpacker.feed(serialized)
print unpacker.unpack()
I had originally used this, but then as my API scope extended to more than just using msgpack, having a common API interface for json (i.e. the .loads() and .dumps() method) was found to be more useful.And while I agree with most of the article, I don't think writing more classes is a one-size-fits-all solution. Classes IMO, only makes sense from a heavily OOP point of view.
by notallama on 2/12/13, 5:15 AM
in java, c++, or c#, to add a variable to a class, you have to repeat its name 4 times. once to declare, once in the constructor parameters, and once on each side of the assignment. why am i writing the same thing 4 times for what should be a core part of the language?
in haskell, you write it once (i'm not saying haskell's records are nice, but they got that part right). same with rust.
and with a function, you write it once.
by wyuenho on 2/12/13, 10:28 AM
Expanding on Armin's dichotomy, top-down designs like Python's open() or jquery plugins start with giving 70-80% of users APIs that are as simple as possible for their most frequent use cases while shielding them from the sausages underneath.
Bottom-up designs like Java's standard library or POSIX start with LEGO building blocks that solve the most fundamental pieces of largely academic computer science problems and just give them out to their end users and expect them to be able to assemble Tower Defense by solving this LEGO puzzle first.
The problem with sticking entirely to their 2 approaches is that you end up either ignoring power users or making healthy adults with normal IQs feel stupid. There is no reason you can't serve 100% of your user base by incrementally evolving your API approaches and provide 2 sets of APIs within the same library, with the top-down easy one shielding the bottom-up sausage factory that takes care of the meat grinding for you. Most API designers don't realize this and won't ever go there. Extremists and egoists with lots of opinions will spending hundreds of man years to promote their One True Way of doing things. They'll say things like "no leaky abstractions!" or "these enterprise people are just making things too complicated to create jobs!", when the simple truth is probably just that they don't understand how people think.
Make your libraries easy to do things that are easy, but make hard things possible too.
by splicer on 2/12/13, 4:54 AM
by comex on 2/12/13, 5:53 AM
But yes, in the JSON cases, having more flexibility than a single 'loads' is clearly justified.
by cgopalan on 2/12/13, 6:32 AM
However, in certain cases, like where I need to write a public API, I have found that having classes as wrappers to the functionality helps it a bit. So really, the "stop-writing-classes-unless-you- absolutely-need-to" guideline still holds true for me.
by ankitml on 2/12/13, 8:55 AM
So he asks for using abstractions instead on no abstraction (block code) but if you have other ways of abstracting code, please go ahead. THis article is good for people with few / no tools, people who are still learning
by redangstrom on 2/12/13, 5:49 AM
On the streaming verus resident working set argument... Most of what most programmers deal with doesn't have to scale to deal with huge streaming datasets, so it doesn't get the attention.
by jakejake on 2/12/13, 6:54 AM
by pyeek on 2/12/13, 10:48 AM
I think Armin's post is somewhat in line with the following post from the google testing blog. http://googletesting.blogspot.com/2008/12/static-methods-are...
by Offler on 2/12/13, 9:23 AM
by cwp on 2/12/13, 10:53 PM
For example, Python's lack of variable declarations sometimes leads to bugs involving scoping. (I've run into this a couple of times myself). Does this quirk become more of an issue in heavily functional code? Are there other language quirks that become troublesome in heavily OO code? In what circumstances might one style be preferred over another?
by jerf on 2/12/13, 1:55 PM
by INTPenis on 2/12/13, 8:45 AM
It's tasked with returning records from parsed zones and every single record is a class. I like it and I don't understand the first sentence of this blog post.
Try not to put too much weight on what others tell you, make up your own mind. It's a classic human issue.
by benatkin on 2/12/13, 5:57 AM
by mafro on 2/12/13, 5:50 AM
Some libraries manage to skip the token part. (I'm looking at you
simplejson, a library that even with the best intentions in mind
is impossible to teach stream processing)
by Ingaz on 2/12/13, 6:20 AM
It looks the same as XML SAX vs DOM: you feed NN-Mb to DOM-parser (SQLServer xml-datatype for example) and you have problems. No matter: classes or functions.
by quasque on 2/12/13, 4:16 PM
by ehutch79 on 2/12/13, 1:04 PM
by iso-8859-1 on 2/12/13, 12:44 PM
by dakimov on 2/12/13, 7:34 AM
There is no professional culture and new generations of developers successfully forget all the experience previous generations have accumulated.
Also, some piece of advice from a seasoned programmer to the web-programming-children: if you are not really a serious developer, if you write your freaking websitee on Django, or whatever a framework there is, you don't really need a methodology, because you are doing an easy task, you can write in whatever language/style/paradigm you like, even on Brainfuck. But please don't extrapolate your humble experience to the entire industry and don't tell people working on large complicated (real) projects how they must write code, because they have some experience you don't have.
by leppie on 2/12/13, 7:12 AM
static String readFirstLine(String filename) { try { BufferedReader br = new BufferedReader(new FileReader(path)); ....
So people writes this everyday, yet still fail to do it correctly...
Also, this article was written 1 day in the future. The future looks bleak to me...
by akaru on 2/12/13, 5:26 AM