The PEAK Developers' Center   Diff for "PeakDatabaseApplications" UserPreferences
 
HelpContents Search Diffs Info Edit Subscribe XML Print View
Ignore changes in the amount of whitespace

Differences between version dated 2003-10-11 21:48:02 and 2005-03-08 15:03:29 (spanning 11 versions)

Deletions are marked like this.
Additions are marked like this.

= Introduction =
 
Note: this page is an incomplete draft; please see IntroToPeak for a tutorial.
 
 
PEAK is an excellent platform for building Python database applications. Using a combination of several PEAK packages one can build powerful and flexible database applications quickly and easily.
 
= First Steps: Binding and Naming =
 
We should first discuss briefly the PEAK packages we'll be working with, primarily {{{peak.binding}}}, {{{peak.naming}}}, and {{{peak.storage}}}.
We should first discuss briefly the PEAK packages we'll be working with, starting with `peak.binding` and `peak.naming`.
 
Peak's {{{binding}}} package provides powerful utilities for building component-based applications. This typically means that you create a top-level application class of some sort which instantiates the various component objects needed to accomplish the task at hand. With peak.binding these "component objects" will be able to find each other, most often by defining properties that "bind to" other objects in the hierarchy. Here's a quick example:
Peak's `binding` package provides powerful utilities for building component-based applications. This typically means that you create a top-level application class of some sort which instantiates the various component objects needed to accomplish the task at hand. With `peak.binding` these "component objects" will be able to find each other, most often by defining properties that "bind to" other objects in the hierarchy. Here's a quick example:
 
{{{
#!python

    worker = binding.Make(Worker)
 
    def run(self):
        storage.beginTransaction(self)
        self.worker.doWork()
        storage.commitTransaction(self)
 
if __name__ == '__main__':
    from peak.api import config

    app.run()
}}}
 
As subclasses of {{{binding.Component}}}, the {{{Application}}} and {{{Worker}}} classes are capable of taking part in a component hierarchy. Such a hierarchy needs a "root" object at its base -- we use {{{config.makeRoot()}}} to create a component root object on line 17. On line 18 we instantiate an Application object, specifying that {{{root}}} will be its parent. When creating {{{binding.Component}}}-based objects by hand like this, one must always pass a parent object as the first parameter. When using binding within a class definition (as done on lines 4, 10, and 11) the parent object for the new component will be determined automatically.
As subclasses of `binding.Component`, the `Application` and `Worker` classes are capable of taking part in a component hierarchy. Such a hierarchy needs a "root" object at its base -- we use `config.makeRoot()` to create a component root object on line 20. On line 21 we instantiate an `Application` object, specifying that `root` will be its parent. When creating `binding.Component`-based objects by hand like this, one must always pass a parent object as the first parameter. When using bindings within a class definition (as done on lines 4, 10, and 11) the parent object for the new component will be supplied automatically, if needed.
 
This small example is already a working database application. It opens a connection to a [http://www.sqlite.org/ SQLite] database file, runs a query using against a table, and prints the results. It also demonstrates one of the most useful aspects of the binding package: the ability to create an object once and make use of it in another part of the application. In database applications you usually want a single connection to a database server which will be shared throughout the application. Without binding one would have to either create the connection object and pass it to every new object that needed it, or provide it to the rest of the application using a singleton mechanism of some kind.
This small example is already a working database application. It opens a connection to a [http://www.sqlite.org/ SQLite] database file, runs a query against a table, and prints the results. It also demonstrates one of the most useful aspects of the binding package: the ability to create an object once and make use of it in another part of the application. In database applications you usually want a single connection to a database server which will be shared throughout the application. Without binding one would have to either create the connection object and pass it to every new object that needed it, or provide it to the rest of the application using a singleton mechanism of some kind.
 
The former technique is highly error prone and forces the application to be "tightly coupled" -- that is, objects need to know quite a bit about each other and are usually highly dependent on each other's interfaces and structure. Changing one object in a tightly coupled application often requires changes to a number of other objects, and in large applications these inter-dependencies are not always known by every programmer or are easily missed. Tightly coupled software tends to be extremely brittle as a result.
 
The singleton approach can help quite a bit by ensuring that only one instance of a certain type of object exists and that it can be found relatively easily. In Python this is often achieved through a separate module and module-level variables. Singletons are not especially flexible, however, as they typically need to be obtained by a very specific name (e.g. {{{myapp.config.db}}}), thus maintaining a certain level of tight coupling. What is typically needed in larger applications is a flexible way to create, lookup, and use singleton-like objects. This is what PEAK's binding system provides.
The singleton approach can help quite a bit by ensuring that only one instance of a certain type of object exists and that it can be found relatively easily. In Python this is often achieved through a separate module and module-level variables. The great drawback of a singleton, however, is that there's only one of it. Classes that use singletons are less reusable, because you can't create instances that use different values for a singleton. (Because then it wouldn't be a singleton!) So, classes that use singletons are still tightly coupled.
 
What is typically needed in larger applications is a flexible way to create, lookup, and use "singleton-like" objects. PEAK calls such objects "service components", and part of what PEAK's `binding` package provides is easy access to such components, using looser forms of coupling such as:
 
 * lookup by interface (line 4)
 * lookup by naming service (line 10)
 * "publishing" components by interface (also line 10)
 * automatic creation of needed components (line 11)
 
When a class embeds all its dependencies in "attribute bindings" like these, the class can easily be reused via subclassing or by simply setting attributes on instances.
 
... to be continued ...

PythonPowered
ShowText of this page
EditText of this page
FindPage by browsing, title search , text search or an index
Or try one of these actions: AttachFile, DeletePage, LikePages, LocalSiteMap, SpellCheck