Skip to content

Commit

Permalink
Updating documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
malthe committed Nov 1, 2009
1 parent bfe061d commit 660c86b
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 89 deletions.
4 changes: 3 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ supported, but not required (see `using WebOb`_).
You can use the publisher to write web applications. It was designed
with both small and large applications in mind. The documentation
includes a tutorial and examples which show how to solve common
problems.
problems (see also the `user's guide`__).

:mod:`Otto` works with Python 2.6 or newer.

__ usersguide_

License
-------

Expand Down
97 changes: 12 additions & 85 deletions docs/guidelines.rst
Original file line number Diff line number Diff line change
@@ -1,90 +1,17 @@
==================
Guiding principals
==================
.. _guidelines:

Fun is important
================
Guidelines
==========

I like creating things. Ever since I was a little kid I would spend
days on end building with Legos. For me programming is like having
an endless stream of Lego bricks in any size, shape and color I can
think of. That is why I got into it, I just wanted to play and have
fun!
This section outlines the principles on which this library is built,
which extends to how we'd like to see it evolve.

You might have a different story. But I bet that, like I, you didn't
start coding for the money. Let's face it, there are probably more
effective ways of doing that. My guess would be that for some reason
or other you got to have fun when programming.
Library vs Framework

Fun, or lack thereof, is the main driver behind Otto. We wanted
to have a system which made web-development an enjoyable experience
again. Something which puts us in control instead of being
controlled.
We believe it's inherent to frameworks to introduce anti-patterns
and to require a particular development *model*.

Having fun gives energy, makes you more productive, happy and even
more healthy. So when faced with the choice of doing something, why
not pick the option that's more fun?

No conceptual baggage
=====================

Baggage is junk which you have to haul with you wherever you go. It
slows you down when traveling, makes your back hurt and exhausts you
faster. This is also true for conceptual baggage, which is baggage
you have to lug around in your mind.

That is why systems should try to avoid introducing radically new
concepts. A Python developer should not have to re-learn the
language because someone other than Guido introduced something new.

An example of conceptual baggage from the zope.interface
package. Can you guess what the `implements` call is going to do?::

class Foo(object):
interface.implement(IFoo) # <-- What is this supposed to do?

Python just does not have a concept like a function call which
modifies something outside of it's normal scoping
rules. "Directives" like these just do not make sense and introduce
new conceptual baggage.

Frameworks suck, try to avoid them
==================================

Coding is about solving problems your way. Frameworks are about
requiring you to structure your code in their way. At one point your
way and the frameworks way will collide. What makes perfect sense to
you will be made impossible by the framework.

You then have to rethink your problem in terms the framework might
support, probably going as far as forgoing the optimal solution. The
force and restrictions a framework imposes on you, telling what you
can and cannot do, just sucks. It drains energy and creativity. It's
just not fun.

A way to handle this problem is by take note of a few possible (this
list is not exhaustive) guidelines:

- A framework is anything where you plug your code into

- Frameworks usually have globals, don't use them.

- Globals are only to be introduced by the developer of an
application, not by a library or framework.

- Make it easy to alter behavior by using the object-oriented paradigms:

- Sub-classing and overriding methods is a fine way to let people
customize your code.

- Favor delegation over sub-classing.

- Put code in control by giving it all you can. This means that
plug-ins should receive as much state as you can reasonably give
them. Err on the side of giving to much, it's easier to ignore
state then to make it magically appear when you need it.

tip::

Extend and replace before plugging in place. That which is
passed around does not have to be globally bound.
The primary motivation for writing and using frameworks is to
increase productivity, but it's not clear that this is an actual
outcome. On the other hand, it is evident that there are actual
negative effects of working with or within a framework.
3 changes: 3 additions & 0 deletions otto/docs/reference.rst → docs/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
Reference
=========

Routes
------

Match dictionary

Expressions on the form ``:key`` match any string and passes the
Expand Down
72 changes: 72 additions & 0 deletions docs/usersguide.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
.. _usersguide:

User's Guide
============

This section is a guide on how to write web applications using this
library.

Philosophy
----------

In not being a framework, but a library, projects begin with an empty
module and a copy-paste of the *hello world* application. The
objective is to embrace the empty module and avoid the pitfalls
inherent to development outside a framework.

*I like to create things. As a kid I would spend days building
with Lego bricks. Programming is like an endless stream of bricks
of every size, shape and color; that is why I got into it, to play
and have fun!* - Jeroen Vloothuis

The library was built from the experience of working with various
other libraries and frameworks, or rather, because of it. Many lessons
learned have inspired its design, which adheres to the following
principles:

**Must be fun**

It means never having to say you're sorry.

**It's your code**

It's inherent to frameworks to take over control.

Programming is about solving problems. Frameworks are about
spelling the solution in the language of the framework and then
hand over control. Sometimes it's a perfect fit, but often enough
it's a poor fit or an outright bad fit. Everything's a compromise,
but it becomes a compromise more quickly when you're using a
framework that's not an optimal fit.

Warning signs:

- Plugins

- Globals

**Few dependencies**

Conceptual baggage wears you out.

Python has enough concepts of its own. It's tempting to introduce
new playing rules, but in the long term, conceptual baggage incurs
bitrot.

An example from :mod:`zope.interface`::

class Foo(object):
zope.interface.implements(IFoo)

What is this code supposed to do? It's not obvious from this
snippet. Python does not provide a reference to a class while it's
still being defined.

We have tried to weed out all dependencies which aren't absolutely
necessary such that you can decide which code to depend on.

**Use the right abstractions**

Python is an object-oriented language. With the right abstractions
in place, this paradigm makes it easy to reuse existing code.

8 changes: 5 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@

# documentation
INTRO = open(os.path.join(here, 'otto', 'docs', 'getting_started.rst')).read()
REFERENCE = open(os.path.join(here, 'otto', 'docs', 'reference.rst')).read()
REFERENCE = open(os.path.join(here, 'docs', 'reference.rst')).read()
USERSGUIDE = open(os.path.join(here, 'docs', 'usersguide.rst')).read()
GUIDELINES = open(os.path.join(here, 'docs', 'guidelines.rst')).read()

long_description = "\n\n".join((README, INTRO, REFERENCE, CHANGES))
long_description = "\n\n".join((
README, INTRO, REFERENCE, USERSGUIDE, GUIDELINES, CHANGES))
long_description = long_description.replace('.. code-block:: python', '::')
long_description = re.sub(r':mod:`(\D+)`', '*\\1*', long_description)

Expand All @@ -42,7 +45,6 @@
keywords="wsgi publisher router",
author="Malthe Borch",
author_email="mborch@gmail.com",

install_requires=install_requires,
license='BSD',
packages=find_packages(),
Expand Down

0 comments on commit 660c86b

Please sign in to comment.