The PEAK Developers' Center   GraphvizTutorial UserPreferences
 
HelpContents Search Diffs Info Edit Subscribe XML Print View
Version as of 2003-02-27 14:18:36

Clear message


1 Creating Domain Models With PEAK: GraphViz Example

This tutorial will show you how to use the peak.model package to create "domain model" objects for some simple applications. Our chosen subject matter for the domain model will be GraphViz, the open-source graph visualization toolkit from AT&T. The GraphViz dot tool takes input files that look like this:

 
digraph finite_state_machine { 
        rankdir=LR; 
        size="8,5" 
        orientation=land; 
        node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8; 
        node [shape = circle]; 
        LR_0 -> LR_2 [ label = "SS(B)" ]; 
        LR_0 -> LR_1 [ label = "SS(S)" ]; 
        LR_1 -> LR_3 [ label = "S($end)" ]; 
        LR_2 -> LR_6 [ label = "SS(b)" ]; 
        LR_2 -> LR_5 [ label = "SS(a)" ]; 
        LR_2 -> LR_4 [ label = "S(A)" ]; 
        LR_5 -> LR_7 [ label = "S(b)" ]; 
        LR_5 -> LR_5 [ label = "S(a)" ]; 
        LR_6 -> LR_6 [ label = "S(b)" ]; 
        LR_6 -> LR_5 [ label = "S(a)" ]; 
        LR_7 -> LR_8 [ label = "S(b)" ]; 
        LR_7 -> LR_5 [ label = "S(a)" ]; 
        LR_8 -> LR_6 [ label = "S(b)" ]; 
        LR_8 -> LR_5 [ label = "S(a)" ]; 
} 
 
and turns them into pictures that look like this:

Many people have created interesting tools that use GraphViz to draw diagrams of workflow processes, clickpaths through a website, profiler call charts, even UML class diagrams. Most such programs use hardcoded templates for their .dot files and can be difficult to change because you have to know both the dot language and the application area of the software. In this tutorial, we'll develop a sophisticated framework for creating .dot files from application data that will give you flexible, object-oriented control over the visual objects to be rendered by GraphViz. We'll begin with a very simple structure using only three classes, and then, step by step, we'll show you more advanced ways to use the peak.model tools as we gradually enhance the framework's power and flexibility. Along the way, we'll share tips and techniques for ways to make the best design decisions for your own applications, in similar situations.

1.1 The Basics

Before beginning any software development effort, it's important to know your scope and requirements, so let's lay out ours for this project. We want to develop a framework that makes creating GraphViz diagrams easy, for a variety of application areas. We are only interested in dot graphs, which are always directed graphs (i.e. every line has a direction to it, even if no arrows are drawn). Also, we don't need or want to be able to read or modify GraphViz files, just write them. To ensure that we have a useful framework, we'll want to develop a few simple applications that create useful output. And for our "grand finale", we'd like to be able to create a script that uses the framework to create class diagrams of the framework itself, or perhaps generate UML diagrams from an XMI file. Last, but not least, we'd like to use a minimalistic, evolutionary approach, where we "do the simplest thing that could possibly work" at each stage.

Alright, so let's get started. We're creating a domain model, so we need to know what kind of objects are in our problem domain. GraphViz graphs include the ideas of nodes and edges. An edge is directed, and connects two nodes. Nodes have names, by which they can be referenced. So here is the simplest possible PEAK domain model for such a thing:

    1 from peak.api import model
    2 
    3 class Node(model.Element):
    4 
    5     class name(model.Attribute):
    6         referencedType = model.String
    7 
    8 class Edge(model.Element):
    9 
   10     class fromNode(model.Attribute):
   11         referencedType = Node
   12 
   13     class toNode(model.Attribute):
   14         referencedType = Node

Let's go through the above, piece by piece. Obviously, we have our Node and Edge classes to represent nodes and edges. What's not so obvious is why they inherit from model.Element, or what all those nested model.Attribute classes are for.

1.1.1 The Service-Element-Feature Pattern

One of the basic contributions of the ?TransWarp framework was the idea that applications essentially consist of Services, Elements, and Features. Services are the objects which represent or compose "the application" itself, while Elements are the problem-domain objects that are managed and manipulated via the Services. Finally, Features are the objects which compose Elements: attributes, methods, relationships, even UI views or database field mappings. Features are usually contained in the body of an element's class.

The peak.model package provides base classes that support common usage patterns of Elements and Features. For example, model.Element provides support for persistence, keyword-based instance construction, and metadata about an object's features.

For features, peak.model provides the model.StructuralFeature base class, and its subclasses Attribute, Collection, Sequence, DerivedFeature, and structField. The subclasses are really just "syntactic sugar" for specifying metadata like whether the feature is derived (i.e. calculated) or stored, whether it's an ordered sequence or an unordered collection, etc. Like other Python "features" (i.e. standard methods and attributes), peak.model features are specified in the body of their containing element's class. Unlike other Python features, peak.model features are defined using a class statement. (More on the whys and hows of this later.)

1.1.2 Defining Features

In our first example domain model, we use model.Attribute because we don't need a collection or sequence for any of our object attributes.


PythonPowered
EditText of this page (last modified 2003-02-27 14:18:36)
FindPage by browsing, title search , text search or an index
Or try one of these actions: AttachFile, DeletePage, LikePages, LocalSiteMap, SpellCheck