NAME¶
Magpie::Intro - Introduction to the whys and wherefores of Magpie
VERSION¶
version 1.141660
Introduction to Magpie¶
This document introduces the underlying concepts that inform Magpie's design.
For a more practical how-to, see ***link***.
What is Magpie?¶
In the animal world, the Magpie (Pica pica) is an intelligent, mischievous bird
with a reputation for pilfering shiny objects. In the enlightened world of
Modern Perl, Magpie is an attempt to combine the best ideas (shiny objects)
from the community's long history of Web development frameworks into a truly
mature and intelligent environment.
Ambitious? You bet. And we're in good company, we think. Perl itself is a magpie
and always has been. Originally designed to fuse the best features of a slew
of *NIX utilities into cohesive whole that made easy things easy and hard
things possible, Perl has continuously evolved by adopting and internalizing
the best features from each new generation of languages and tools that have
been invented since (many of which were themselves influenced by Perl). At the
same time, the Perl community has constantly evolved through a similar
process. Community support, development infrastructure, even what constitutes
"good Perl code" have all evolved by an iterative process of
adoption -> extension -> invention. This is why we're making Magpie. We
believe that by combining the best features of various popular Web development
frameworks-- together with our own bits of invention-- we can create a
development environment where easy things are easy and hard things are
possible.
Implemented as a Plack::Middleware component, Magpie provides a rapid
application development framework for both browser-based Web applications and
RESTful Web services by removing (or at least greatly reducing) the redundant
aspects of day-to-day application coding. Magpie's design is heavily informed
by the study of Finite State Machines.
Magpie's basic goals and design principles can be summed up as follows:
- •
- The most important entity in Web development the Resource. By convention
and explicit design, Magpie should be Resource-oriented.
- •
- Magpie should provide a clear, well-defined interface for separating
application state-detection from the event hander methods that are
executed in response to a given state. This promotes fast, focussed,
incremental development.
- •
- In any given Magpie application, event hander methods may be divided
across one or more of a series of Application Classes, each of which may
have its own state/event mapping logic that determines which events will
be fired. This encourages modularity and code reuse.
- •
- In addition to the Application Class(es), a Magpie application pipeline
will also contain one Output Class that generates the content for the
requesting client. This encourages reusability by letting us expose the
same application logic to different types of Web clients.
- •
- All Magpie's base component and helper classes must be easily replaceable
with user-defined classes; This promotes invention, user contribution and
project longevity.
- •
- Magpie's core code must be environment-agnostic, allowing developers to
deploy applications under Mod_per1/Apache versions 1 and 2, as well as any
Web server offering the Common Gateway Interface (CGI). User-defined
application classes and custom components are free to favor one
environment over another but Magpie's core must remain neutral.
- •
- Magpie must be judiciously magical-- providing just enough Perlish
wizardry to make writing applications easy, while not presuming or
enforcing a One True Way(tm) that unduly limits developers' freedom.
Resource-Oriented Application Development¶
The URL Is Not The Resource, The Resource Is Not The Thing¶
When a client sends a request via HTTP to a given URL they are asking for a
Representation of a Resource, not the Resource itself. Unfortunately,
the first generation of Web frameworks that tried to implement practical
RESTful architectures often mixed things up and made it seem like the URL was
the Resource and the Resource was the Thing.
To illustrate the distinctions, let's suppose that you want to implement a CRUD
(Create, Read, Update, Delete) interface to an "orders" table in
your database. After some discussion, you decide to use a RESTful API and so
you reach for one of the popular tools that purports to make the process
simple. The early stages of the project are promising-- set-up is nearly
trivial and in a very short time you have unit tests demonstrating a working
HTTP endpoint for your order data.
But wait, a POST to the "/order" endpoint requires more than a
one-to-one relationship with the database's "order" table. You have
to check product availability for each item in the order, you have to access
the "customers" and "customer_addresses" tables to grab
the client's address to calculate shipping, etc. Where does all that extra
logic go? Do you cram it into the validation stage? Do you create different
Controller methods to handle those tasks?
Soon, you find that the hands-off "connect the database table to the
Web" application you thought you were building is turning into a series
of hacks, work-arounds, and one-offs. The tool that was supposed to make
things easier now actually ties your hands. You're wondering why this all
seems so hard and you begin to suspect that REST is just another in a long
line of overcomplicated bondage fads that look great on paper but fall to
pieces under their own complexity when you try to do anything substantial. But
the problem isn't REST-- that's just an architectural style-- the problem is
that REST-on-MVC treats the "orders" table as the Resource and
tightly couples the Web API to that physical asset.
Dispatching¶
Altered States¶
In general, an application can be seen as being in (or having) a series of
application states. Consider the typical online registration
application. First, the user is presented with an HTML form into which they
type their desired username, password, personal details and other information.
We can think of this as the "prompt state" since the core action
involves
prompting the user to sign up. Once the user has filled in the
form, they hit the submit button to send the input to a URL on the server that
implements an interface that is able to read that incoming data. Once the
request if received, the data is often verified for fitness-- first by logic
on the server side that verifies that the data is complete and appropriate;
then by the user, who is given a read-only HTML page reflecting his or her
input for review. Let's call this the "validation state". Presented
with the information they have entered, the user may choose to return to the
prompt state by clicking a "Make Changes" button, or to proceed with
registration by clicking the "Register" button. (Note that the
application itself often proactively returns to the prompt state if it finds
the user's input to be unfit). When both the user and the system are satisfied
with the input, the verified data is sent to the server by clicking the
"Register" button presented during the validation state. The server
receives the data, creates the new user account, and responds with an HTML
document containing a polite message thanking them for registering. We'll call
this the "complete state".
In short, we can say that the typical user registration application is a single
entity that can be in one or another of three distinct states (prompt,
validation, and complete).
---------- -------------- ------------
| Prompt | | Validation | | Complete |
| State |-[User Input]->| State |-[Data Accepted]-->| State |
---------- -------------- ------------
^------[Data Rejected]------|
State Diagram for Online Registration
Despite the fact that this principle of state-based development and design is
understood (if only intuitively) by most experienced Web developers, much of
the code running on the Web today remains a mix of blocks of real
application-level programming wrapped by largely redundant application state
detection logic. We have learned through experience the benefits of separating
an application's logic from its presentation, yet we persist in mixing
application state detection with code that reacts to those states. Magpie
exists because its developers and users have found that separating application
state detection from behavioral logic offers similar benefits to those that
come from drawing a clear line between application logic and presentation--
namely, the logical division of labor/time, and the ability to create
uncluttered more maintainable code faster, and the freedom to reuse resources
by decoupling distinct aspects of the application implementation.
Magpie works by mapping
application states, determined by user input and
other factors, to
event handler methods, that implement the behavior
associated with that state. In Magpie, developers need only register and
implement the specific bits of code that react to a given application state,
Magpie makes sure that correct event (or events) are fired.
Magpie's core distribution provides a simple Web application infrastructure
along with a few commonly useful state-to-event mapping mechanisms that have
proven themselves useful over time, but makes no other presumptions or
proscriptions about the design or implementation of a given application. The
point is to reduce brittleness and redundancies while ensuring that developers
are free to implement their application in the way that makes most sense to
them.
__END__
AUTHORS¶
- •
- Kip Hampton <kip.hampton@tamarou.com>
- •
- Chris Prather <chris.prather@tamarou.com>
COPYRIGHT AND LICENSE¶
This software is copyright (c) 2011 by Tamarou, LLC.
This is free software; you can redistribute it and/or modify it under the same
terms as the Perl 5 programming language system itself.