| | 1 | = What is "global state" = |
| | 2 | |
| | 3 | This generally refers to variables in memory that are available to any code running within a given context |
| | 4 | |
| | 5 | this is a manifestation of [http://en.wikipedia.org/wiki/Scope_(computer_science) scoping] |
| | 6 | |
| | 7 | A global variable is one that is local in one context, and global for all contained contexts. |
| | 8 | |
| | 9 | Generally globals are added during import time, and are defined as module level variables |
| | 10 | |
| | 11 | so if we have a module foo, that assigns at the module level to a variable named x like: |
| | 12 | |
| | 13 | {{{#!python |
| | 14 | x = 5 |
| | 15 | }}} |
| | 16 | |
| | 17 | then foo.x is globally shared across any code that imports foo within that running process |
| | 18 | |
| | 19 | There are several contexts in which a variable can be defined. This variable becomes available to this context and any containing context, but not in any parent contexts. |
| | 20 | |
| | 21 | [http://en.wikipedia.org/wiki/Shared_memory machine] > [http://docs.python.org/reference/executionmodel.html process] > [http://docs.python.org/library/threading.html#threading.local thread] > [http://en.wikipedia.org/wiki/Green_threads greenlet] |
| | 22 | |
| | 23 | == Why remove global state: == |
| | 24 | |
| | 25 | ''First we could ask why is it there in the first place?'' |
| | 26 | |
| | 27 | Global state allows coordination between many different areas of a framework without having to explicitly pass that information around. |
| | 28 | |
| | 29 | There are several reasons to remove the use of global state in Django, and these can be grouped into areas that improve isolation, create a better runtime experience, and add more flexibility in the use of the framework. |
| | 30 | |
| | 31 | === Isolation: === |
| | 32 | |
| | 33 | * Multiple Django projects on single server ([http://en.wikipedia.org/wiki/Multitenancy multitenancy]) |
| | 34 | |
| | 35 | |
| | 36 | |
| | 37 | * Make unit testing easier as configuration is self contained - easier to isolate tests, integration test vs unit test |
| | 38 | |
| | 39 | === Better runtime experience: === |
| | 40 | |
| | 41 | * Being more explicit about where global state is used, and when it is created, it provides a good place for a process initialization hook |
| | 42 | * By having less configuration stored globally, it allows for more dynamic reconfiguration of framework behavior at runtime (including per-request changes), fewer required server restarts |
| | 43 | |
| | 44 | === More Flexible: === |
| | 45 | |
| | 46 | * More structured organization of non-global configuration would set the stage to allow more granular configuration on a per INSTALLED_APP basis. |
| | 47 | * Make it easier to use Django components as just another python library, including outside the direct context of a web application |
| | 48 | |
| | 49 | |
| | 50 | ''"Explicit is better than implicit."'' --zen of Python |
| | 51 | |
| | 52 | if some function depends on a variable being "magically" defined, without it being clear where the variable was set - that code is less clear |
| | 53 | |
| | 54 | Immutable is less evil than mutable - it can alleviate erratic and surprising behavior, but doesn't improve the situation with regards to isolation. |
| | 55 | |
| | 56 | An well articulated litany of some of the issues related to global state in Django was [http://simonwillison.net/2009/May/19/djng/ put forth by Simon Willioson]. Specifically the idea of having a dynamic runtime configuration.(good comments too about chaining callables) |
| | 57 | |
| | 58 | |
| | 59 | == What areas of Django suffer from problems with global state == |
| | 60 | |
| | 61 | '''note each of these areas can be flushed out with specific subissues, solutions, and notes.''' |
| | 62 | |
| | 63 | === template system === |
| | 64 | |
| | 65 | |
| | 66 | https://code.djangoproject.com/ticket/17093 |
| | 67 | |
| | 68 | === settings === |
| | 69 | |
| | 70 | === signals === |
| | 71 | |
| | 72 | === WSGI handler === |
| | 73 | |
| | 74 | === urlconf/urlreverse === |
| | 75 | |
| | 76 | === db === |
| | 77 | |
| | 78 | === translations === |
| | 79 | |
| | 80 | https://code.djangoproject.com/ticket/14894 |
| | 81 | |
| | 82 | === management commands === |
| | 83 | |
| | 84 | === testing === |
| | 85 | |
| | 86 | https://code.djangoproject.com/ticket/11593 |
| | 87 | |
| | 88 | == What are some possible approaches to handling reasonable amounts of global state: == |
| | 89 | |
| | 90 | [http://werkzeug.pocoo.org/docs/local/ Flask] (uses werkzeug) keeps a stack of threadlocal objects. |
| | 91 | |
| | 92 | Pyramid contains a single list of "application registries" in a [http://docs.pylonsproject.org/projects/pyramid/dev/api/config.html#pyramid.config.global_registries global_registry] - this is the single bit of global state. A registry is bound with other configuration information into a [http://docs.pylonsproject.org/projects/pyramid/dev/api/config.html Configurator] object. |
| | 93 | |
| | 94 | https://github.com/Pylons/pyramid/blob/master/pyramid/config/__init__.py |
| | 95 | |
| | 96 | http://docs.pylonsproject.org/projects/pyramid/dev/api/registry.html |
| | 97 | |
| | 98 | '''A common issue solved with a bit of global, sort out location in the filesystem:''' |
| | 99 | |
| | 100 | The Pyramid configurator object accepts a 'package' argument which should be the python path location of a package - otherwise the current package/module, so the python file that defines the Configurator object becomes a positional anchor in the filesystem. |
| | 101 | |
| | 102 | Flask does [http://flask.pocoo.org/docs/design/ something very similar], using __name__ to locate your Flask application. |
| | 103 | |
| | 104 | People routinely do this using __file__ in Django settings.py |
| | 105 | |
| | 106 | == Some related discussions: == |
| | 107 | |
| | 108 | A good discussion on what role the framework should play in owning the request and response: |
| | 109 | http://lucumr.pocoo.org/2009/8/5/pro-cons-about-werkzeug-webob-and-django/ |
| | 110 | |
| | 111 | an explanation of how process global data effects code running in mod_wsgi: |
| | 112 | http://code.google.com/p/modwsgi/wiki/ProcessesAndThreading#Sharing_Of_Global_Data |
| | 113 | |
| | 114 | Armin why I can't stand thread.local (and others) July 10, 2006 |
| | 115 | main issues are that is magic and hard to understand why some globals should be mutable, and others not |
| | 116 | cached as pocoo version is 404 |
| | 117 | http://meineartikel.labs.nzz.ch/user/pneff/set/python/id/1Wg |
| | 118 | |
| | 119 | http://justindriscoll.us/2008/02/objects-with-shared-state-in-python.html |
| | 120 | a way of using a class level attribute reflected into all instances |
| | 121 | |
| | 122 | == odds and ends, tangents == |
| | 123 | |
| | 124 | http://www.python.org/dev/peps/pep-3104/ |
| | 125 | |
| | 126 | Dynamic Scoping in python |
| | 127 | http://www.voidspace.org.uk/python/articles/code_blocks.shtml |
| | 128 | |
| | 129 | http://stackoverflow.com/questions/1920053/what-is-so-bad-with-threadlocals |
| | 130 | |
| | 131 | http://stackoverflow.com/questions/3227180/why-is-using-thread-locals-in-django-bad |
| | 132 | |