forked from orbit-oss/flask
Rewrote becoming big and foreword
This commit is contained in:
parent
9e1111c2fb
commit
bca1acf1f3
2 changed files with 72 additions and 56 deletions
|
|
@ -3,54 +3,74 @@
|
|||
Becoming Big
|
||||
============
|
||||
|
||||
Your application is becoming more and more complex? Flask is really not
|
||||
designed for large scale applications and does not attempt to do so, but
|
||||
that does not mean you picked the wrong tool in the first place.
|
||||
Your application is becoming more and more complex? If you suddenly
|
||||
realize that Flask does things in a way that does not work out for your
|
||||
application there are ways to deal with that.
|
||||
|
||||
Flask is powered by Werkzeug and Jinja2, two libraries that are in use at
|
||||
a number of large websites out there and all Flask does is bring those
|
||||
two together. Being a microframework, Flask is literally a single file.
|
||||
What that means for large applications is that it's probably a good idea
|
||||
to take the code from Flask and put it into a new module within the
|
||||
applications and expand on that.
|
||||
two together. Being a microframework Flask does not do much more than
|
||||
combinding existing libraries - there is not a lot of code involved.
|
||||
What that means for large applications is that it's very easy to take the
|
||||
code from Flask and put it into a new module within the applications and
|
||||
expand on that.
|
||||
|
||||
What Could Be Improved?
|
||||
-----------------------
|
||||
Flask is designed to be extended and modified in a couple of different
|
||||
ways:
|
||||
|
||||
For instance it makes a lot of sense to change the way endpoints (the
|
||||
names of the functions / URL rules) are handled to also take the module
|
||||
name into account. Right now the function name is the URL name, but
|
||||
imagine you have a large application consisting of multiple components.
|
||||
In that case, it makes a lot of sense to use dotted names for the URL
|
||||
endpoints.
|
||||
- Subclassing. The majority of functionality can be changed by creating
|
||||
a new subclass of the :class:`~flask.Flask` class and overriding
|
||||
some methods.
|
||||
|
||||
Here are some suggestions for how Flask can be modified to better
|
||||
accommodate large-scale applications:
|
||||
- Flask extensions. For a lot of reusable functionality you can create
|
||||
extensions.
|
||||
|
||||
- get rid of the decorator function registering which causes a lot
|
||||
of troubles for applications that have circular dependencies. It
|
||||
also requires that the whole application is imported when the system
|
||||
initializes or certain URLs will not be available right away. A
|
||||
better solution would be to have one module with all URLs in there and
|
||||
specifying the target functions explicitly or by name and importing
|
||||
them when needed.
|
||||
- switch to explicit request object passing. This requires more typing
|
||||
(because you now have something to pass around) but it makes it a
|
||||
whole lot easier to debug hairy situations and to test the code.
|
||||
- integrate the `Babel`_ i18n package or `SQLAlchemy`_ directly into the
|
||||
core framework.
|
||||
- Forking. If nothing else works out you can just take the Flask
|
||||
codebase at a given point and copy/paste it into your application
|
||||
and change it. Flask is designed with that in mind and makes this
|
||||
incredible easy. You just have to take the package and copy it
|
||||
into your application's code and rename it (for example to
|
||||
`framework`). Then you can start modifying the code in there.
|
||||
|
||||
.. _Babel: http://babel.edgewall.org/
|
||||
.. _SQLAlchemy: http://www.sqlalchemy.org/
|
||||
Why consider Forking?
|
||||
---------------------
|
||||
|
||||
Why does Flask not do all that by Default?
|
||||
------------------------------------------
|
||||
The majority of code of Flask is within Werkzeug and Jinja2. These
|
||||
libraries do the majority of the work. Flask is just the paste that glues
|
||||
those together. For every project there is the point where the underlying
|
||||
framework gets in the way (due to assumptions the original developers
|
||||
had). This is natural because if this would not be the case, the
|
||||
framework would be a very complex system to begin with which causes a
|
||||
steep learning curve and a lot of user frustration.
|
||||
|
||||
There is a huge difference between a small application that only has to
|
||||
handle a couple of requests per second and with an overall code complexity
|
||||
of less than 4000 lines of code and something of larger scale. At some
|
||||
point it becomes important to integrate external systems, different
|
||||
storage backends and more.
|
||||
This is not unique to Flask. Many people use patched and modified
|
||||
versions of their framework to counter shortcomings. This idea is also
|
||||
reflected in the license of Flask. You don't have to contribute any
|
||||
changes back if you decide to modify the framework.
|
||||
|
||||
If Flask was designed with all these contingencies in mind, it would be a
|
||||
much more complex framework and harder to get started with.
|
||||
The downside of forking is of course that Flask extensions will most
|
||||
likely break because the new framework has a different import name and
|
||||
because of that forking should be the last resort.
|
||||
|
||||
Scaling like a Pro
|
||||
------------------
|
||||
|
||||
For many web applications the complexity of the code is less an issue than
|
||||
the scaling for the number of users or data entries expected. Flask by
|
||||
itself is only limited in terms of scaling by your application code, the
|
||||
data store you want to use and the Python implementation and webserver you
|
||||
are running on.
|
||||
|
||||
Scaling well means for example that if you double the amount of servers
|
||||
you get about twice the performance. Scaling bad means that if you add a
|
||||
new server the application won't perform any better or would not even
|
||||
support a second server.
|
||||
|
||||
There is only one limiting factor regarding scaling in Flask which are
|
||||
the context local proxies. They depend on context which in Flask is
|
||||
defined as being either a thread or a greenlet. Separate processes are
|
||||
fine as well. If your server uses some kind of concurrency that is not
|
||||
based on threads or greenlets, Flask will no longer be able to support
|
||||
these global proxies. However the majority of servers are using either
|
||||
threads, greenlets or separate processes to achieve concurrency which are
|
||||
all methods well supported by the underlying Werkzeug library.
|
||||
|
|
|
|||
|
|
@ -17,24 +17,20 @@ may be necessary in larger or more complex applications.
|
|||
For example, Flask uses thread-local objects internally so that you don't
|
||||
have to pass objects around from function to function within a request in
|
||||
order to stay threadsafe. While this is a really easy approach and saves
|
||||
you a lot of time, it also does not scale well to large applications.
|
||||
It's especially painful for more complex unittests, and when you suddenly
|
||||
have to deal with code being executed outside of the context of a request,
|
||||
such as in cron jobs.
|
||||
you a lot of time, it might also cause some troubles for very large
|
||||
applications because changes on these thread-local objects can happen
|
||||
anywhere in the same thread.
|
||||
|
||||
Flask provides some tools to deal with the downsides of this approach, but
|
||||
the core problem remains. Flask is also based on convention over
|
||||
configuration, which means that many things are preconfigured and will
|
||||
work well for smaller applications but not so well for larger ones. For
|
||||
example, by convention, templates and static files are in subdirectories
|
||||
within the Python source tree of the application.
|
||||
Flask provides some tools to deal with the downsides of this approach but
|
||||
it might be an issue for larger applications. Flask is also based on
|
||||
convention over configuration, which means that many things are
|
||||
preconfigured and will work well for smaller applications but not so well
|
||||
for larger ones. For example, by convention, templates and static files
|
||||
are in subdirectories within the Python source tree of the application.
|
||||
|
||||
But don't worry if your application suddenly grows larger
|
||||
and you're afraid Flask might not grow with it. Even with
|
||||
larger frameworks, you'll eventually discover that you need
|
||||
something the framework just cannot do for you without modification.
|
||||
If you are ever in that situation, check out the :ref:`becomingbig`
|
||||
chapter.
|
||||
However Flask is not much code and built in a very solid foundation and
|
||||
with that very easy to adapt for large applications. If you are
|
||||
interested in that, check out the :ref:`becomingbig` chapter.
|
||||
|
||||
A Framework and an Example
|
||||
--------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue