

Python Web Frameworks' Complexity - mariuz
http://mindref.blogspot.com/2012/11/python-web-excessive-complexity.html

======
jacobian
Note that this article is by the author of wheezy, a framework that just
happens to do quite well on this particular metric.

Yes, I'm a maintainer of Django, so I'm biased too. But look: there's a good
argument to be made that parts of (even of all of) Django is too complex.
This, however, is not that argument; this is just a made-up metric.

ETA: I misspoke above: McCabe isn't made up. I meant to write that this was a
_cherry-picked_ metric. Leaving the above as is because people have already
replied to it.

~~~
JulianWasTaken
I happen to agree that this kind of measurement is pretty much useless here
and that I don't pick my web framework via cyclomatic complexity, but let's
not be too disingenuous. He's not making up a metric, it's a thing, and an
occasionally useful one IMO.

~~~
jacobian
Sorry, I didn't mean to suggest he was making up a metric.

Yes, McCabe is a real thing. I haven't really found it that useful myself --
I'm not sure that you can adequately measure something fuzzy like "complexity"
through static control flow analysis -- but sure, I'm willing to accept that
it could be useful in certain circumstances.

What I am saying is that this guy is cherry-picking a specific metric (out of
many that he could choose) that makes his tool looks good. I could just as
easily come up with a metric that sorts Django to the top of an arbitrary
list. That wouldn't be useful, either.

~~~
JulianWasTaken
Ah OK. Sorry, misread. Agreed. Oh and maybe the metric you're looking for that
puts django on top is "# of users" ;) :trollface:.

~~~
dsil
"# of users" is a metric I use to choose which framework to use. For one, it
makes it much more likely that a problem I'm having can be solved with a
google or forum or stackoverflow search.

I think that alone makes it a much better metric to judge the experience
you'll have with a framework than its cyclomatic complexity (at least for a
user of a framework, maybe not as a developer)

~~~
raylu
A bit off topic here, but I feel that this is a terrible metric.

The reason it's impossible to find answers for how to fix problem X in Windows
(besides it being terribly designed) is that there are a ton of users who are
trying to be helpful and providing bad advice.

Googling for solutions to an Ubuntu problem is starting to look grim too. Read
some bug reports on Launchpad and then read some on the Debian bug tracker;
there's a clear difference in signal/noise.

Circling back to the original point: if a web framework is simple, you can
figure out the problem by just reading the code rather than looking online for
solutions (many of which are in the form "oh, framework Y automatically does Z
for you so you have to...").

~~~
mattdawson
I don't care how simple a framework is. There are _always_ dusty corners that
are hard to understand. There will always be bugs. And the ability to get help
from fellow users when you hit those is, in my experience, crucial.

------
wink
The wikipedia entry at <http://en.wikipedia.org/wiki/Cyclomatic_complexity>
notes 10 as a _module_ threshold.

This is a bit like comparing apples and oranges, usually you'd use 10 as a
rough number for your method/function whatever, not for a whole framework. The
whole point of modularization/refactoring is to have small parts, I've never
heard of any mention regarding to cyclomatic complexity that you cannot use a
multitude of small modules.

So to sum it up, it's nice that someone tried to compare python web
frameworks, but the method of comparison is misleading at best and wrong at
worst.

~~~
jre
I'm not familiar with this complexity metric, but I immediately wondered if
the results had been normalized with regard to the number of lines of code or
modules in each framework (The wikipedia article doesn't say anything about
normalization). Django does a lot more stuff than bottle or Flask. So if you
just sum up complexity of their modules, it's pretty obvious which one will
come out ahead.

------
beatpanda
It's not clear to me whether this "excessive complexity" has an actual
performance impact or is just a subjective measure of complexity.

Django, one of the worst offenders according to your chart, also happens to be
a mature project in wide use that works really well and handles most edge
cases where, perhaps, some "less complex" frameworks would fall down.

So what does this measurement mean in practical terms? How should I balance
this score against the benefit of the framework?

~~~
freshhawk
The other frameworks would "fall down" or you would need to write a small
amount of glue code?

While Django is mature, I'm using it right now in fact, I find that I spend a
hell of a lot of time trying to figure out why Django is doing a specific
thing or how to convince it to do the exact thing I want.

I'm convinced, after a few years of Django work and a year or so of Flask (or
just werkzeug libraries), that Django is the wrong level of complexity for a
web framework.

For every minute I've saved by having django handle the edge case or having
some great feature built in I feel like I've lost a few minutes to fighting
against the framework when my use case doesn't fit into the expected usage and
I'm fighting against a fairly rigid framework.

This feeling is what I think the OP is trying to get at with the "excessive
complexity" measurement, although using a single metric like this is probably
not the answer. It does fit decently well with my impressions of the
frameworks listed (among the ones I've used anyway) but this is a messy and
subjective problem.

I've found myself firmly in the "libraries > frameworks" camp because of this
issue so I'm certainly biased towards liking this metric, even with it's
faults.

~~~
crucialfelix
Same here. I tried valiantly to do some class based views the other day and my
spidey sense started going off. Maybe I'll find time later to get those the
way I want them but I suspect they will suck up more time than they will save.

It's a general problem with hierarchies of inheritance. Too many separate
places where the actual functionality is, so you have to learn all of them and
hold them in your head to understand the few pithy lines of code in front of
you.

And that's the issue with the admin and forms. Hard to keep track

~~~
camus
> It's a general problem with hierarchies of inheritance.

And what do you suggest to make it easier for you to read, spaghetti code ?
Django makes great use of mixins, mixins you can re-use to make your own views
if you dont like the default generic views.

~~~
crucialfelix
That's what I was doing, using mixins. In a way it's no different than
stacking decorators, but soon enough you get helper methods being called and
cooperations between helper methods and you have no memory which class its
implemented it.

An IDE can help but that's an indicator that the solution has a readability
problem.

------
jimwise
Beyond the question of how meaningful these metrics are, wouldn't it be a more
useful metric to look at how complex the code you write when you _use_ each
framework is, rather than the code that _implements_ each framework?

I suspect -- but don't know -- that these might even turn out to be inversely
correlated for some types of frameworks. DSL-based frameworks often require
some interesting tricks to get right.

So which is better? A complex framework that lets you write simple, concise
code? Or a simple framework that requires a lot of boilerplate and complexity
to use?

~~~
obviouslygreen
I think the answer to your question, and probably the point of asking it, is
that It Depends. If you're writing a very simple web service that will be
accessed by millions of clients for a small set of straightforward operations,
you'll probably want to pick the framework with the smallest footprint and
write a very little bit of custom code. If you're writing a vastly complex
system to mingle support for new and legacy data and integrate with many
disparate third party services, you will want a framework that does a lot
behind the scenes to make your own code as painless as possible.

For everything else, aside from Mastercard, there's room for argument and
discussion... but I think the only universal takeaway is that most or all of
the frameworks mentioned have solid use cases, and none of them work for
everyone in every circumstance.

------
magnusgraviti
I visited KyivPy where the author of Wheezy.Web described his project. So I
want to share own thoughts about it.

It has all basic things you would like to have. I mean you can work with
templates engine you want, forms, middlewares etc.

Speaking about Django we can find it is not just Django. It is also hundreds
of django apps like django-social-auth, South, django-celery, django-mptt etc.

This new framework has no such huge community for now. On the other side the
author did a good work. You can use pretty complete framework on Python3 when
the most of others can't offer the same. And it is not 2to3. If I correctly
remember impressions of the code it was written on Python3 and then ported to
python2.

So, I like it. You can use classes or functions for handling requests. You
have modules so you can install just wheezy.http and not so many other parts
and I believe we should choose the right tool to solve the problem. In one
case it can be Django, in others we can take Wheezy.web.

------
chewxy
I agree that a lot of python web frameworks are excessively complex. However,
sometimes complexity is warranted.

I use web.py, flask and bottlepy depending on the required complexity of a
project. They intuitively feel less complex. If I need a step up from web.py,
I'd be inclined to go with Pyramid (reddit is built on Pylons, which is a
precursor to Pyramid and before that, they used web.py)

To me it's a tradeoff between coding speed and project size/speed/performance.
For example, if you use Bottlepy to write a typical webapp, you'd have to
write your own session handlers (or use Beaker), and you'd have to write your
own utils to transform and sanitize data etc.

However, using Bottle.py for a cookie dropping service? 30 lines of code and
you have a very robust and scalable cookie dropping service. Ditto to using
bottle for adserving and ad decisioning off redis.

Flask however, in my opinion works well for public API endpoints, while web.py
works very very well for web frontends

------
nostrademons
There's a pretty strong correlation between "frameworks that are actually
used" and "frameworks with high complexity" here. That makes sense to me: most
of the software systems I've worked with that are actually _used_ have a lot
of warts to them. It comes from having users, who never seem to want to do the
simple thing.

------
dbecker
There appears to be only a loose correlation between McCabe complexity and
"excessive complexity." It's not clear how the author converts from one to the
other.

One would hope that the difference in ordering comes from accounting for the
amount of functionality in each project (and even if you prefer bottle to
django, you have to admit that django builds in more functionality.)

But, again, it's unclear how that conversion happened. I'm wondering if the
author ranked "excessive complexity" however he wanted, and the McCabe
complexity is just there to give this the veneer of scientific authenticity.

------
lambda
This article would have been a lot better with examples of where that
complexity is (particular functions, where the complexity score comes from,
etc), and what suggested refactorings help to reduce that complexity. That
would make it possible to judge if this is a reasonable metric, or if this is
just some overly-strict tool that dings perfectly reasonable code, which some
frameworks happen to trigger more than others.

------
ishbits
I was going to rant about django, but I think my issue is applicable to all
wsgi applications. I develop APIs that often involve long polling as well as
streaming, and while I can do this with most frameworks, the choice of the
server in front can make or break my implementation.

This I've settled on tornado as my framework and server.

------
elithrar
This doesn't make great sense - why is this particular kind of complexity a
bad thing?

Most Python frameworks, regardless, seem to score quite well-Flask,
Turbogears, Bottle-in contrast to Django, which is to be expected as it
doesn't try to be simple (it is, however, well documented and easy to learn).

~~~
bickfordb
According to the Wikipedia article increased cyclomatic complexity leads to
harder test code and the increased likelihood of more defects.

I'm curious how the analysis in the blog post works. In languages like Python
it's common to hide branches inside of data structure lookups like the
following:

    
    
      def f(): 
         ...
    
      def g():
         ...
    
      def h(x):
       return {
        True: f,
        False: g}[not x]()

~~~
ul5255
Slightly off-topic but why would you build up a dictionary in h(), then index
it, then call the function being returned? The dictionary must be garbage
collected later too. To me this seems rather inefficient compared to a simple
if/then/else. I think readability also suffers.

~~~
3amOpsGuy
It's likely the parent has listed this way for brevity of the post, while
still trying to show the potential for complexity, which I believe is the key
point here and i would agree with it.

The dict-as-a-switch expression is common to python, but it can be masked as
the parent has shown in larger examples.

I have no idea how we could apply static analysis techniques to a construct
like this. To be honest I tend to avoid this approach on readability grounds.
It could be cleaned up with a dict subclass but I think inlining the dict call
mechanics is simpler to read, even if it produces larger code, leads to
repetition and couples you to this approach (which would be a strong
consideration in the case of writing a library - where this type of code is
most prevelant).

------
mercurial
This test doesn't look right. For instance, Django comes with its own ORM, and
a bunch of stuff in contrib. Does the test count the code in contrib as well?
To be fair, you would need to take for instance Flask, and add SQLAlchemy and
a bunch of extension to get a meaningful score.

------
pajju
Isn't the McCabe metric simply a measure of software complexity?

This method is designed for individual modules. Here you've applied for the
complete system. What sense does this make? Resulting metric is not conveying
any meaningful information. And higher numbers mean its not necessarily worse;
it just means the program is more complex, which may be due to more
functionality.

Right way to compare it - Level the scope of the frameworks (e.g. add
SQLAlchemy to pyramids) and compare again. Bring all to equal levels.

<https://en.wikipedia.org/wiki/McCabe_Metric>

------
nnq
...what if having this complexity "packaged" in the framework prevents it for
cropping up in your application code? (yeah, this usually happens when you do
things "the framework way", but most web apps are pretty unoriginal so picking
a framework that "fits" and walking "it's way" is a good idea most of the
time...)

...though it would be interesting to see this metric applied to a Ruby
framework like Rails

------
magnusgraviti
I.e. wheezy.web doesn't use middleware + tags for csrf. It is Python3 without
2to3 crap. And I agree with Aaron Swartz that framework must handle input,
output and how to work with server. Logic, templates, databases must be free
to choose. Wheezy.web is a set of modules here so we must not install bunch of
stuff like Django for something simple. And we can use all of it for something
difficult.

