| 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 | |