

The MicroPHP Fallacy - ircmaxell
http://blog.ircmaxell.com/2012/01/microphp-fallacy.html

======
symbiotic
I don't think there's any disagreement about using the right tool for the job.
What I took from the original MicroPHP Manifesto is that the solution is not
to have a ton of hammers to choose from. Instead, make sure you have a couple
different types of hammer heads and a couple different types of handles that
you can mix and match so that the right hammer is always available.

This way your toolbox is much lighter and easier to carry around (easier to
keep up to date with improvements to the code and easier to maintain). I think
it's about breaking things into smaller pieces.

~~~
ErrantX
I used to feel this way. However I tended to find myself, on most projects,
spending a surprising amount of time tweaking incompatibilities between the
various lightweight libraries I was using. And it was a bit of an effort to
unify things like logging and error reporting.

Which is when I realised the utility of a bulky framework; for the most part
it is a suite of libraries that work together/are compatible but which
_someone else maintains for me_ :)

This was a big step for me.

(although I still use the lightweight approach for smaller projects)

~~~
symbiotic
That's a reasonable complaint, but maybe it means we need better lightweight
libraries with well thought out interfaces or better library management like
deweller suggested in the comments on the original thread.

~~~
ErrantX
That would be good - but then you begin to talk about a unified logging
interface and standardisation like folder structure, class loading, class
interfaces and so on.

At which point it's basically a framework (perhaps without the
routing/initialisation code).

One thing I would like to see (no idea if it exists) is a core package
architecture (that did all of the above) and let you hang packages as and when
you need them.

I've been keeping an eye out for such a thing for a while with no joy.

------
sequoia
I'm excited to see that there is discussion going on here! I might suggest
that the "manifesto" author did not say "I'm a PHP developer" to be limiting
(i.e. I only write PHP) but to contrast with being e.g. a "Cake developer" or
a "Rails developer." Assuming this is a reasonable interpretation, he is
actually making the same "Don't tie yourself to one framework" point that OP
is making here. So: agreement! (I think.)

I don't know how relevant this is but I couldn't help but notice that the
"hammer" analogy for frameworks was an interesting choice in light of Joel
S.'s well known "Hammer Factory Factory" article.
[http://discuss.joelonsoftware.com/default.asp?joel.3.219431....](http://discuss.joelonsoftware.com/default.asp?joel.3.219431.12)
Was this a coincidence or intentional? Anyway I thought it was a funny
coincidence. :)

~~~
digitallimit0
Yeah, by being a "PHP developer" rather than say, a Zend developer, he was
making that right-hammer-for-the-job argument back in the original article
long before ircmaxell got around to implying anything else. I think there's a
lot of agreement here that got lost in "simple isn't always better!"

~~~
Periodic
Looking at it now I see you're right. "PHP developer" is meant to be less
limiting than the options the author of the MicroPHP Manifesto was
considering.

When it was brought up in the context of this article, I read it as someone
being proud to be a developer of PHP. Among many academic crowds and HN it
feels like PHP is a dirty word.

------
gwillen
Of the two methods he shows, I want to cast a strong dissenting vote that I
prefer method number 1. In method 1, the complexity of the operation -- and
it's not that much complexity, let's be honest here! -- is all in one place
where I can examine and work with it, but there's not so much that it's a
barrier to understanding.

By contrast, in method 2, the complexity is hidden. If there's a bug in method
2, I have way more levels of abstraction to dig through before I've got a clue
what's going on. If someone else wrote method 2, I've got probably three or
four source files to do archaeology in before I can even be sure what it does.

~~~
ircmaxell
If that's all that your code does, then that's fine to use #1. But in a larger
class, it's needlessly cluttering the class with operations below its
abstraction level. Why should a logger care about file locks and the such? Why
should you care about file locks when editing the logger? Hint: You shouldn't
normally.

As far as "the complexity is hidden", you're absolutely right. I want that
complexity hidden. By hiding the complexity in this way, I can reduce
duplication and at the same time make the code far easier to read. Sure, you
do need to dig through more levels of abstraction if you need to debug
something. But abstracting in this way enables bugs to be fixed far easier,
since the methods are really small and simple, the "ripple" effect is far
easier to understand and contain.

Think about how long it took you to understand what log() did. With the first
one, you needed to parse a whole lot of detail (including the flag passed to
fopen, the two exception checks, the arguments passed to flock, the fprintf
declaration and the flock call arguments). With the second, all you needed to
do is read the two steps: 1. createLogMessage() and 2. file->append($message).
At a glance you know what the method is supposed to be doing.

Why is there such a hang up that people want to know what code is doing at all
levels? If you name your APIs well, you should be able to look at the method's
name (and perhaps its arguments in some cases) and know without a doubt what
it's doing (at least to the abstraction level the API is designed for). If you
really need to know details, you can go deeper, but I know when I read
$file->append($message) that I'm appending a message to a file. I don't need
to worry about anything else 99.9% of the time. So I'd rather get the clean
win with well named APIs, than spend my time sifting through methods like the
first one...

~~~
gwillen
If your abstractions are beautiful and clean, then you're absolutely right --
hiding the complexity is great! But you know what? 99% of the time, your
abstractions are shitty and leaky. And then I need to know what's under them
in order to work with them confidently.

So yes, absolutely hide complexity. But hide it judiciously; hide it only when
you know you have a clean, well-designed and well-constructed abstraction that
won't leak to the outside. But if you hide complexity behind a leaky
abstraction, which most of them are; then now, as they say, you have two
problems.

~~~
rickmb
I feel the concept of "leaky abstractions" is being abused way too much as an
argument against all abstraction.

Except in the well known cases, like trying to abstract away SQL to give it an
OO interface, the leakiness of abstractions is rarely a big issue if those
abstractions are decently designed. Not even beautiful and perfectly clean,
just good enough for their purpose.

Yeah, it sucks in those rare cases where the abstraction makes it hard to
figure out what the hell is actually happening, but the extra effort is
nothing compared to the amount of pain saved by having that abstraction
throughout the rest of the development process.

All plumbing will spring a leak some time (and sometimes with pretty costly
consequences), but that in itself is no argument against plumbing.

------
lux
The code example given seems a bit disingenuous, since the same level of
complexity is present in the code, only the parts of it are broken up into
single-purpose methods that may or may not be overkill depending on the needs
of the project. For example, you can swap `$this->file` with a different
object to write to alternate logging backends, but you could just as easily
replace `$this->logFile` with an alternate stream wrapper to do the same thing
in the original example...

For reference, here's the first example:

    
    
        public function log($message, $level) {
            $f = fopen($this->logFile, 'a');
            if (!$f) {
                throw new LogicException('Could not open file for writing');
            }
            if (!flock($f, LOCK_EX | LOCK_NB)) {
                throw new RuntimeException('Could not lock file');
            }
            fprintf($f, '%s [%s] %s - %s', $this->machineName, date('Y-m-d H:i:s'), $level, $message);
            flock($f, LOCK_UN);
            fclose($f);
        }
    

And here's what your improved example would actually be:

    
    
        /* In $this->file's class */
        public function append ($message) {
            $f = fopen($this->logFile, 'a');
            if (!$f) {
                throw new LogicException('Could not open file for writing');
            }
            if (!flock($f, LOCK_EX | LOCK_NB)) {
                throw new RuntimeException('Could not lock file');
            }
            fwrite($f, $message);
            flock($f, LOCK_UN);
            fclose($f);
        }
        
        /* In Log class */
        public function createLogMessage ($message, $level) {
            return sprintf('%s [%s] %s - %s', $this->machineName, date('Y-m-d H:i:s'), $level, $message);
        }
        
        public function log($message, $level = 'notice') {
            $message = $this->createLogMessage($message, $level);
            $this->file->append($message);
        }
    

Just a nitpick, but sometimes we over-abstract because we're too used to doing
so. To me, a separate `createLogMessage()` method that just wraps a
`sprintf()` seems like a sign of that.

(not saying I haven't been equally guilty of this 1000x before :)

~~~
jakejake
The OP doesn't include the implementation of "createLogMessage" because he is
suggesting that this method would be part of a framework, and by using it you
can focus your mind on your application code, rather than boring details like
checking for file locks on a log file.

I do think that choosing where to abstract and where to split functionality is
the "art" of the code and we obsess about as we master the craft. So I can
appreciate your code example!

I personally like to have a dedicated log function. That way you can refactor
from using a file to perhaps a database table or any other method of logging.
I personally expose our error logs as RSS and subscribe to the feed - I find
it a really easy way to monitor because I'm too lazy to go looking at error
log files every day!

~~~
lux
I was assuming the log() method was also part of the framework, and that this
was just a framework-level excerpt... ;)

Perhaps such a core Log class could use a separate createLogMessage() method
(or formatMessage() as I'd probably name it) that could be overridden in a
subclass more easily than overriding the entire log() method.

I definitely agree that the API design and finding that balance is a big part
of what makes coding an artform!

------
stdbrouw
> Programming in a language involves limiting thoughts and implementations to
> only constructs that the language directly supports. However, programming
> _into_ a language involves finding the solution they want to do, and then
> determining how to express those thoughts in the language.

Learning how to program involves learning to think like a computer, and seeing
the world in terms of loops and filters and manipulations. Mastering a
specific programming language takes that one step further, because you become
so familiar with it that you start thinking in terms of the specific
constructs and the idiom that it offers. The speed gains are enormous once
your brain adapts to that way of thinking, and I wouldn't give that up for
anything.

I appreciate the sentiment – be a programmer, not the master of one specific
way of programming – but I think there are better ways to achieve that goal
than by programming "into" a language. The Pragmatic Programmer credo, for
example, to learn a new language ever year, is much more appealing.

------
lincolnwebs
This perfectly encapsulates my unease about the MicroPHP Manifesto. Neither
drummer was doing it wrong; they both chose the most fitting tools. The
reviling of "overkill" solutions is a natural step in becoming an experienced
developer but that doesn't mean it should top HN every time someone has that
epiphany.

------
astrodust
If using an example involving Dave Grohl can't set this straight, nothing
will.

~~~
sequoia
But where does Rick Allen fit in here? I must know!!

------
digitallimit0
His last bit on the latter part of the manifesto "I like simple, readable
code" seems pretty unnecessary. I doubt the original article's author would
argue against good coding practices like abstraction layers. And really, the
example he provides doesn't even stand against "simple" or "readable".
Abstracted code is exactly that.

~~~
astrodust
You know what "simple, readable code" is? It's something that hasn't been
exposed to the real world.

Once your application has been in circulation, exposed to the elements,
hostile or indifferent users, it will develop barnacle-like patches that look
ugly but serve a specific and important purpose.

You can keep code clean(er) if you're vigilant, but sometimes there's no way
to express very complicated logic in a concise manner. Often abstraction looks
cleaner but generally only hides complexity and can tend to increase
complexity on the whole.

~~~
chernevik
As a noob I find terms "simple, readable code" really confusing. I recently
had to learn some PHP (I'm mostly Python) to implement a seemingly stupid
simple interface between some HTML form input and a REST API. Should be
simple, right?

But there is all this weirdness validating data inputs like dates. And we have
to process the form data data so each field input goes to the proper API
field. And hey look that mapping only varies in its _data_ among form / API
target pairings, so I should abstract that code out into a function or I'll be
chasing bugs through the copied-and-pasted. The API provides a library for
formulating requests but this doesn't expose some key functionalities to unit
testing so I ant to revise to do that. Et cetera.

And, the next thing I know this thing is umpty-ump lines, and while the
scripts actually processing the data are reasonably legible, they're sitting
over a tangle of stuff that's rather harder to navigate. I've got classes to
manipulate various core data to produce various data structures supporting
sundry activities, but this essentially means those data structures are
abstractions and thus hard to inspect when trying to remember how some process
is working or what's going wrong. (The unit tests are worthwhile if only b/c
their check values provide concrete examples of how those derived structures
look.) To make the code "simple" in one place, I've created complexity
elsewhere.

Obviously, this is in part a novice problem. If I can lay out and document the
supporting code better everything gets easier to follow. But still, 5000 lines
to input some form data, am I doing this right?

So is "simple, readable code" that helpful as a goal? At the end of the day it
seems like there is X degree of complexity in any of these tasks, and any
strategy to "simplify" is really just a framework for deciding where to place
what complexities. And if that's right, then "simple, readable code" can
become either a time suck or a discouragement in a hurry. I'm either playing
Whack-A-Mole as I chase Complexity from one corner to the next and back to the
start, or I'm going home depressed b/c I'm too stupid to write "simple,
readable code". It sounds great, I suppose it is where people end up when they
get good, so it's probably very helpful as an indicator of whether you're good
yet. But I'm not sure it's very helpful for figuring out how to get to good.

~~~
kansface
I'd suggest you read Code Complete. It clocks in around 1000 pages and you
probably don't have to read every single corner, but it would be for the best.

Code Complete documents several best practices in coding based on internal
reviews of large coding projects and publications. The point of the book is
that your code will have fewer bugs and be easier to maintain.

Priorities for coding go something like this:

1\. make it work

2\. optimize for maintenance (ie, make it easy to read)

3\. optimize for flexibility/speed (only if necessary!!!!)

You should not be chasing complexity from one corner to the next; complexity
should nearly always be pushed down and sequestered where it can't infect
other code. Simple, readable code is the primary goal. Perhaps it was Knuth?
who said programmers should enjoy reading code on the weekend. I couldn't
disagree more! Good code should have the opposite qualities of a good book.
Every single step along the way should be perfectly obvious as if no other way
existed; plot twists in code are bad! Elegance is good, while cleverness tends
to be bad. Working on existing code is much harder than writing new code. What
hope do you have with maintenance if you write something at the limits of your
comprehension?

About 70-80% of the lifetime of any work on given code is actually in
maintenance, not in writing it. Optimize for this. Documenting is not
necessarily helpful, either. You should not document shit as being shit;
instead, you should change the bad code!

Other things are mentioned too, like function length, number of arguments to
functions, variable span length, and variable pass through. Really, give it a
read.

~~~
chernevik
Code Complete is very helpful, read it several years ago when I was starting.
The biggest take-aways were DRY and proper encapsulation / abstraction. I
should probably go back to it, I currently struggle with figuring out where to
put stuff but maybe the stuff that went over my head the first time would help
with that.

thx

------
billpatrianakos
This article wasn't really necessary. Okay, so the guy who wrote the MicroPHP
Manifesto didn't use a perfect analogy. So what? I'm pretty sure we all got
his point. Everything that got refuted here in this post didn't need to be
refuted. We're all smart enough to understand that the MicroPHP Manifesto was
a reaction to large, sometimes complicated frameworks that caused the author
frustration. All he was saying was that he just wants to use less code and
simplify things. Who can argue with that? Even a novice developer would
understand that his manifesto wasn't _the one true way_. It's just something
to think about before diving into Zend or Cake by default.

Why nitpick? There's always more to what you read than just the words on
screen. Considering the motivation and circumstances behind the MicroPHP
Manifesto I can't see why anyone would make it out to be something it isn't,
bad analogies or not.

~~~
lincolnwebs
I believe it was both necessary and not a nitpick. While I agree choosing Cake
or Zend by default is a fool's errand, the MicroPHP Manifesto read like
someone who'd just found CodeIgniter for the first time.

~~~
grumpycanuck
I suggest you do some research about the author of the MicroPHP manifesto
before throwing snark out there like that.

Ed is a personal friend (and we do a podcast together) with many, MANY years
of experience building applications using PHP. While I don't agree with him on
some points in there, he does deserve to not be shit on by people who can't be
bothered to do 30 seconds of research about the author.

~~~
lincolnwebs
I didn't "shit on him", I criticized his tenor in that article.

