Hot and spicy ...

Using ZODB Blobstorage with Pyramid (repoze.bfg)

Category: Technology, Web-Applications
Tags: ,

When writing applications using Pyramid web framework a simple option to persist data is using the ZODB. It is sort of built in and very easy to ease. Although being a very stable, reliable and fast database, ZODB does not handle binary data very well. But there is a solution for this: Storing binary data (blobs) transparently outside of the database.

ZODB in newer versions has blob support built in but you need to activate it and handle it the rigth way. Here I want to share my findings and some code to make you successfully use blobs in your Pyramid application. Some parts of the code are inspired by z3c.blobfile.

Click here to display full code example

This code enables you to save binary objects to ZODB. Upon commit the binary data is transparently saved to the file system. This is done by using code like this (assuming that the module containing the code above is called blobfile.py):

[python]
import mimetypes
from blobfile import File

# assuming that we use jQuery Uploadify
data = request.POST.get(‘Filedata’)
filename = request.POST.get(‘Filename’)

obj = app.objectByUid(’123456′)

blob = File(data=data, contentType=mimetypes.guess_type(filename)[0], filename)
setattr(obj, ‘attachment’, blob)
[/python]

The only part missing is the delivery of files upon request. First lets define a route for uploads:

[xml]
path="/attachment/:uid/:fieldname"
name="download-attachment"
view=".core.downloadAttachment"/>
[/xml]

The hard work is done in the downloadAttachment method.

[python]
def downloadAttachment(context, request):
obj = app.objectByUid(request.matchdict.get(‘uid’))
blob = getattr(obj, request.matchdict.get(‘fieldname’))

res = Response(content_type=blob.contentType,
conditional_response=True)

res.headers.add(‘Content-Disposition’, ‘attachment;filename=%s’ % blob.fileName)

res.app_iter = blob # must be blob.file.File
res.content_length = blob.size
res.last_modified = blob.modified
return res
[/python]

Directly using the Saxon API for XSL transformation (no TraX, no XOM)

Category: Technology
Tags: , ,

It can happen that you want to directly access all Saxon functionality. This may be true for cases when the TraX serializer does not perform correctly (e.g. XSLT 2.0 stylesheets that rely on indentation, special output) or you want to influence parameters not accessible using TraX, XOM or others. Directly accessing the Saxon API is not that easy so I’m posting some code here to make life easier for others. This code won’t work out of the box but might give you an idea.

This code has been tested with Saxon PE 9.1.x. Just include saxon9pe.jar with license key into your CLASSPATH.

Click here to display full code example

Building interactive Javascript charts

Category: Technology, Web-Applications
Tags: , ,

Visualizing data in your web application can be achieved by using many frameworks. In one recent project the customer wanted to have an application that helps analyzing data provided by gas stock exchange markets. It was crucial to not use a flash based framework and to provide interactivity for the user.

I had to choose between libraries like Flot, FusionCharts, JS Charts, Emprise JS Charts and Highcharts. After some analysis these 5 Javascript libraries provide all functionality needed to generate interactive charts. But only Highcharts combines functionality, a very stable interface and a rich set of API methods with an eye pleasing design.

Have a look at this chart where data is shown for 2 years. Highcharts includes a very powerful tooltip function and makes it easy to implement your own functionality (like computing the moving average or providing custom zoom levels).

Here the code. Should be easy enough to understand. First the HTML:

[html]

[/html]

And then the Javascript to include.

[javascript]
var masterchart, detailchart;
var lastprice, lastdate;
var year = 2011;

function clearSeries(chart) {
if (chart.series.length>1) {
chart.series[1].remove(true);
}
}

function movingAverage(chart,range, days) {
$.getJSON(‘chart/moving-average-simple’,
{parameter : range, days : days, year : year},
function(data) {
start = data[0];
end = data[1];
chart.xAxis[0].setExtremes(start, end);

clearSeries(chart);
chart.addSeries(
{
type: ‘line’,
name: ‘Moving average for ‘ + range,
data : data[2],
color: ‘#FC0C10′,
lineWidth: 1
}
);

masterchart.xAxis[0].removePlotBand(‘mask-before’);
masterchart.xAxis[0].addPlotBand({
id: ‘mask-before’,
from: start,
to: end,
color: ‘rgba(0, 0, 0, 0.2)’
});
});
}

function loadMasterChart() {
options = {
chart: {
renderTo: ‘master-chart-container’,
defaultSeriesType: ‘line’,
zoomType: ‘x’,
height: 80,
margin: [10, 55, 16, 55],
events: {
selection: function(event) {
ex = event.xAxis[0];
detailchart.xAxis[0].setExtremes(ex.min, ex.max);

masterchart.xAxis[0].removePlotBand(‘mask-before’);
masterchart.xAxis[0].addPlotBand({
id: ‘mask-before’,
from: ex.min,
to: ex.max,
color: ‘rgba(0, 0, 0, 0.2)’
});

return false;
}
}
},
tooltip : {
formatter: function() {
return ” + Highcharts.numberFormat(this.y, 2) + ‘ EUR am ‘
+ Highcharts.dateFormat(‘%d.%m.%Y’, this.x);
}
},
title: {
text: null
},
exporting: {
enabled:false
},
legend: {
enabled:false
},
credits: {
enabled:false
},
xAxis: {
type: ‘datetime’,
min: Date.UTC(year-1, 8, 1),
max: Date.UTC(year, 11, 31),
maxZoom: 14 * 24 * 3600000, // fourteen days, 1000msec*60sec*60min
title: {
text: null
},
plotBands: [{
id: 'mask-before',
from: Date.UTC(year-1, 8, 1),
to: Date.UTC(year, 11, 31),
color: 'rgba(0, 0, 0, 0.2)'
}]
/*labels: {
formatter: function() {
return Highcharts.dateFormat(‘%m/%y’, this.value);
}
}*/
},
yAxis: {
title: {
text: null
},
min: 0.1,
startOnTick: true,
endOnTick : true,
showFirstLabel: false
},
plotOptions: {
line: {
dataLabels: {
enabled: false
},
enableMouseTracking: false,
lineWidth: 1,
marker: {
enabled: false,
states: {
hover: {
enabled: false
}
}
}
}
},
series: []
};

masterchart = new Highcharts.Chart(options);
}

function loadDetailChart() {
options = {
chart: {
renderTo: ‘detail-chart-container’,
defaultSeriesType: ‘line’,
zoomType: ”,
height: 300
},
tooltip : {
formatter: function() {
return ” + Highcharts.numberFormat(this.y, 2) + ‘ EUR am ‘
+ Highcharts.dateFormat(‘%d.%m.%Y’, this.x);
}
},
title: {
text: null
},
legend: {
enabled:false
},
credits: {
enabled: false
},
xAxis: {
type: ‘datetime’,
min: Date.UTC(year, 0, 1),
max: Date.UTC(year, 11, 31),
maxZoom: 14 * 24 * 3600000, // fourteen days, 1000msec*60sec*60min
title: {
text: ‘Datum’
}
/*labels: {
formatter: function() {
return Highcharts.dateFormat(‘%m/%y’, this.value);
}
}*/
},
yAxis: {
title: {
text: ‘EUR / MWh’
},
min: 0.1,
startOnTick: true,
endOnTick : true,
showFirstLabel: false
},
plotOptions: {
line: {
dataLabels: {
enabled: false
},
enableMouseTracking: true,
lineWidth: 1,
marker: {
enabled: false,
states: {
hover: {
enabled: true
}
}
}
}
},
series: []
};

detailchart = new Highcharts.Chart(options);
}

function loadData(onlydata) {
$.getJSON(‘/load/chart-data’, function(data) {

masterchart.addSeries(
{
type: ‘line’,
data : data,
color : ‘#25597E’
}
);

detailchart.addSeries(
{
type: ‘line’,
data : data,
color : ‘#0099FF’
}
);
});
}

function preloadTheme() {
Highcharts.setOptions({
colors: ['#0099FF', '#0099FF', '#ED561B', '#DDDF00',
'#24CBE5', '#64E572',
'#FF9655', '#FFF263', '#6AF9C4'],
chart: {
borderWidth: 0,
plotBackgroundColor: ‘rgba(255, 255, 255, .9)’,
plotShadow: false,
plotBorderWidth: 1,
margin : [12, 55, 20, 55]
},
title: {
style: {
color: ‘#000′,
font: ‘bold 16px “Trebuchet MS”, Verdana, sans-serif’
}
},
subtitle: {
style: {
color: ‘#666666′,
font: ‘bold 12px “Trebuchet MS”, Verdana, sans-serif’
}
},
xAxis: {
gridLineWidth: 1,
lineColor: ‘#000′,
tickColor: ‘#000′,
labels: {
style: {
color: ‘#000′,
font: ’11px Trebuchet MS, Verdana, sans-serif’
}
},
title: {
style: {
color: ‘#333′,
fontWeight: ‘bold’,
fontSize: ’12px’,
fontFamily: ‘Trebuchet MS, Verdana, sans-serif’

}
}
},
yAxis: {
minorTickInterval: ‘auto’,
lineColor: ‘#000′,
lineWidth: 1,
tickWidth: 1,
tickColor: ‘#000′,
labels: {
style: {
color: ‘#000′,
font: ’11px Trebuchet MS, Verdana, sans-serif’
}
},
title: {
style: {
color: ‘#333′,
fontWeight: ‘bold’,
fontSize: ’12px’,
fontFamily: ‘Trebuchet MS, Verdana, sans-serif’
}
}
},
legend: {
itemStyle: {
font: ’9pt Trebuchet MS, Verdana, sans-serif’,
color: ‘black’

},
itemHoverStyle: {
color: ‘#039′
},
itemHiddenStyle: {
color: ‘gray’
}
},
labels: {
style: {
color: ‘#99b’
}
}
});
}

$(document).ready(function() {
preloadTheme();
loadData(false);
});
[/javascript]

Management: The Supporting Leader

Category: Management

During a project with one of my biggest customers I recently had a discussion about different management techniques and one concept (called “The Supporting Leader”) proved especially interesting and is worth a short entry here.

Being successful at sports requires you to train yourself for many hours and always having the target in mind. As stated in a very interesting book by Daniel Levitin (see [1]) ten thousand hours of practice is required to achieve the level of mastery associated with being a world-class expert — in anything. I’m of the opinion that this also and especially stands for leadership and management. In a world where competition between companies grows stronger (mainly triggered by globalization and fast changing markets) new ways of management and leadership have to be explored to gain this level of mastery and to be successful.

One of the basic steps towards a good leadership is the focus on self management (see [2]): People not being able to manage themselves and setting personal standards won’t be good in managing other people. As in self management, leading an organisation, a project and other people is a dynamic process and is influenced by many factors. It is not possible to control all of these factors because there always will be environmental and personal issues that can’t be (fully) controlled.

So let’s change our point of view: Many management related books and techniques focus on tools and behavioural patterns to take full control over the environment. This often fails in practice because of the complexity and amount of data that needs to be analyzed to gain full control. The best way to deal with this situation is to develop a bunch of different behaviours that can successfully deal with different challenges (or subsets).

This is the so called “situative-supporting leadership” that describes the dynamic selection of different leadership patterns according to the situation (it does not mean that you give leaders your support as described in [3]). This gives the manager more degrees of freedom and boosts creativity and productivity.

To achieve this goal you need to shift from a control driven concept (dictator) towards one that appreciates other opinions and gives room for visions (mediator).

References

Using external libraries with the Google-Web-Toolkit

Category: Technology, Web-Applications
Tags: , ,

During some projects I needed to include external Javascript libraries in order to add functionality not provided by GWT. For a recent project the goal has been, to work with data even in cases where the server is disconnected. There are many solutions for this problem like Google Gears or the HTML5 offline database specification but all these solutions suffer from the problem that you either have to install an extension or your browser has to support this.

Another approach is to persist objects to an offline database written in Javascript. Currently there is only one useable library for this use case that is called TaffyDB. This solution works astonishingly well and makes it easy to sync data to and from the server at a later stage.

For a prototype I started to develop a simple extension that integrates TaffyDB into the Google-Web-Toolkit. I am glad to have the permission to share some code excerpts. In near future I will release the complete source, if you are interested drop me a note.

Here some code to give you an idea how to use the extension. The inclusion of Javascript is described in this article.

[java]
TaffyDB.getInstance().initDB();
assert TaffyDB.taffyAvailable() == true;
assert TaffyDB.getInstance().count() == 0;
TaffyDB.getInstance().insert(new Person(“Simon”));
assert TaffyDB.getInstance().count() == 1;
assert TaffyDB.getInstance().findByExample(new Person(“Simon”), null).size() == 1;
assert TaffyDB.getInstance().find(new Person(), “forename=’Simon’”).size() == 1;
Person theperson = TaffyDB.getInstance().find(new Person(), “forename=’Simon’”).get(0);
TaffyDB.getInstance().remove(theperson);
assert TaffyDB.getInstance().find(new Person(), “forename=’Simon’”).size() == 0;
assert TaffyDB.getInstance().count() == 0;
[/java]

Now some code to demonstrate some techniques on how to integrate external libraries like TaffyDB. It will give you some hints on how to pass objects using JSNI. First the insertion:
[java]
/**
* Persists a single object into database.
* @param item the item to persist
*/
public final void insert(IGWTSerializable item) {
IGWTSerializable processed = executeHook(HookType.BEFORE_INSERT, item);
_insert(processed.toJSON(null).getJavaScriptObject());
executeHook(HookType.AFTER_INSERT, null);
}

private final native void _insert(JavaScriptObject input) /*-{
$wnd.db.insert(input);
}-*/;
[/java]

Now some code to get objects.

[java]
/**
* Retrieves all objects exactly matching the data given in the object
*/
public final List findByExample(T item, String[] includefields) {
JSONObject obj = ((IGWTSerializable)item).toJSON(includefields);
JavaScriptObject jsob = _find(obj.getJavaScriptObject());
JSONArray ar = new JSONArray(jsob).isArray();

if (ar != null)
return (List)((IGWTSerializable)item).copyOf().fromJSON(ar);

return new ArrayList();
}

/**
* Searches TaffyDB for objects matching the given one
* @return a JSONArray containing the objects searched or empty Array
*/
private final native JavaScriptObject _find(JavaScriptObject search) /*-{
dbresult = $wnd.db.find(search);

result = new Array();
for (i=0;i obj = $wnd.db.get(dbresult[i])[""+i+""];
result[i] = obj;
}

return result;
}-*/;
[/java]

Google-Web-Toolkit: Injecting Javascript

Category: Technology, Web-Applications
Tags: , ,

In some of my projects I needed to use an external Javascript library to enable the use of features not provided by GWT extensions. Although this is easy if you’ve done it, it is not so self explaining for newbies. I teached a course on the Google-Web-Toolkit for some students and someone told me Google didn’t yield much useful information. So I’m posting a short how-to here.

There are two ways of injecting Javascript into your application

  • Include a reference to the file just as you would do it in plain HTML. Then access methods provided by the library from your code. For some usecases this is ok but it has a severe drawback: You can not distribute your GWT code as JAR because you can not access external Javascript files from the JAR using a reference in your HTML code.
  • The better solution is to dynamically include the Javascript on module load. This has no drawbacks and enables you to distribute your code at will. It also makes sure that you have full control over the inclusion and the version of the library you include.

First you need to include the Javascript file into your project. To do this just put it directly under your.package.client package. In the next step you need to reference the imported Javascript file by using the ClientBundle provided by GWT:

[java]
package your.package.client;

import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.TextResource;

/**
* Extend the {@link ClientBundle} to provide Javascript
* resource linkage.
*
* @author Simon Pamies
*/
public interface MyJSBundle extends ClientBundle {

@Source(“my-extension.js”)
TextResource myExtensionJS();

}
[/java]

Having declared this bundle you can now create the class that does most of the hard work of injecting the resource into your application:

[java]
package your.package.client;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.HeadElement;
import com.google.gwt.dom.client.ScriptElement;
import com.google.gwt.dom.client.Element;

/**
* Wrapper around functionality used to inject
* external Javascript code into your application.
*
* @author Simon Pamies
*/
public class MyJavaScriptInjector {

private static HeadElement head;

public static void inject(String javascript) {
HeadElement head = getHead();
ScriptElement element = createScriptElement();
element.setText(javascript);
head.appendChild(element);
}

private static ScriptElement createScriptElement() {
ScriptElement script = Document.get().createScriptElement();
script.setAttribute(“language”, “javascript”);
return script;
}

private static HeadElement getHead() {
if (head == null) {
Element element = Document.get().getElementsByTagName(“head”)
.getItem(0);
assert element != null : “HTML Head element required”;
HeadElement head = HeadElement.as(element);
JavaScriptInjector.head = head;
}
return JavaScriptInjector.head;
}

}
[/java]

Now it is easy to inject the resource in your onModuleLoad() function:

[java]
public class MyConnector implements EntryPoint {

public void onModuleLoad() {
MyJSBundle bundle = GWT.create(MyJSBundle.class);
MyJavaScriptInjector.inject(bundle.myExtensionJS().getText());
}
}
[/java]

Skinning for Plone 4

Category: Web-Applications
Tags: , , ,

Although my focus for web application technology is once again more and more switching from Plone to Pyramid and Java related technologies (like the Google-Web-Toolkit) I just updated two of my contributions to make them work with Plone 4.

The most important one is anthill.skinning (the other one eases exporting content from the ZMI). This extension allows you to easily skin Plone. By skinning I define the process of changing the layout of Plone to one that matches the specifications given by a customer. This process has never been easy when using Plone and I always preferred using a generic skinning mechanism rather than changing Plone templates.

For small to mid sized websites and even for some bigger ones it is easier to just plug in another layout and only adapting parts you need. Until now I’ve accompagnied more than 350 projects using Plone and using a generic skinning mechanism has proved to be very effective in terms of time and resources.

Pros

  • No need to understand the complex plone template logic
  • You do not have to make so much changes to original layout
  • No need to write a new handbook for editors – take any recent plone book because the edit skin stays the same
  • Less work when updating to a new Plone version because you didn’t touch much of the templates
  • Almost no limitations for your theme/design that could be imposed by the fact that you need to include all the edit functionality (tabs, …) into your theme
  • By not having to fiddle with Plone inner logic/templates that much you save much time

Cons

  • Editors have no in-place editing – although you can change to the edit view on every context there’s one more click needed
  • Including plone portlets into your theme is a little more complex

How it looks like (Plone 4 plain) – Pay attention to the link “Show Preview”

After clicking on the preview link another template is loaded that has only a loose connection to Plone. You still have access to all important functionality like generation of a navigation or breadcrumb and content retrieval.

If you are interested follow the instructions on the extension page.

Serializing objects using the Google-Web-Toolkit

Category: Technology, Web-Applications
Tags: , ,

There are many extensions and even more how-tos and discussions on how to serialize objects when using the Google-Web-Toolkit. The basic question is: How can I use POJOs (Plain-Old-Java-Objects) in my application and pass them to a server (serialize) and how can I convert objects coming from the server (deserialize)?

The most general answer is: Use the great JSON parser and related object types provided by GWT. But this doesn’t solve the problem of having no clue what properties a POJO has. There is no reflection mechanism included and it won’t be in near future. So upon serialization you don’t know what properties an object has und this holds also for deserialization where you don’t know which setters to invoke.

There are many solutions out there but the most require a pre-compilation step where the information about properties is saved to a file (XML, JSON, …). I’m no fan of this solution because it requires you to perform an additional step. There is a simple method where all your data stays in your code. It is not the most beautiful one but it has worked for me in many projects.

So lets take a look at a class that mimics a Person that is serializable:

[java]
/**
* Class that mimics a Person.
*
* @author Simon Pamies
*
*/
public class Person extends GWTSerializable {

public static HashMap schema = new HashMap() {{
putAll(GWTSerializable.schema); // “inherit” schema fields

put(“forename”, new JSONString(“”));
put(“name”, new JSONString(“”));
}};

public Person() {
}

public Person(String forename, String name) {
setForename(forename); // use setter
this.set(“name”, name); // direct access
}

public String getFullName() {
return this.get(“forename”) + ” ” + this.get(“name”);
}

public void setForename(String forename) {
this.set(“forename”, forename);
}

@Override
public IGWTSerializable copyOf() {
return new Person();
}

@Override
public HashMap schema() {
return schema;
}
}
[/java]

As you can see here I’m declaring a schema that has typed fields. I do not use POJO properties here but I’m getting the same result and even more: I have a property structure that can be easily reflected and I have a full fledged Java object. The biggest problem here is that you can have typos in attribute names. But this can be solved by introducing constants.

The hard work is performed by the GWTSerializable class (see at the end of this post). Now you can just perform operations like these:

[java]
// create a new Person object and perform
// any operations you want
Person simon = new Person(“Simon”, “Pamies”);
Window.alert(simon.getFullName());
simon.setForename(“Marcel”);

// save to server
POST(“/actions/create-person”, simon.toJSON());

// get from server
JSONObject something_from_server = GET()
Person simon = new Person().fromJSON(something_from_server);

// pass this object to a native Javascript method
someNativeJavascriptMethod(simon.toJSON().getJavaScriptObject());
[/java]

This is just to give you an idea about how I’m doing serialization in my projects. This is not the most beautiful approach and has some drawbacks but it proved stable and useable. As a last example the code to deserialize objects (from GWTSerializable). Please drop me a note for the complete code or hints.

[java]
public List fromJSON(String input) {
return fromJSON(JSONParser.parseStrict(input).isArray());
}

public IGWTSerializable fromJSON(JSONValue input) {
JSONObject jobj = input.isObject();

// We need to have a fresh instance for each iteration
IGWTSerializable inst = this.copyOf();

for (String key : jobj.keySet()) {

JSONValue val = jobj.get(key);

if (val.isString() != null)
inst.set(key, jobj.get(key).isString().stringValue());

else if (val.isNumber() != null)
inst.set(key, jobj.get(key).isNumber().doubleValue());

else if (val.isBoolean() != null)
inst.set(key, jobj.get(key).isBoolean().booleanValue());

// currently we accept only strings
else if (val.isArray() != null) {
List result = new ArrayList();
for (int g = 0; g < val.isArray().size(); g++) {
JSONValue arrayval = val.isArray().get(g);
if (arrayval instanceof JSONString) {
result.add(arrayval.isString().stringValue());
} else {
/* only String typed content currently allowed */
}
}
inst.set(key, result.toArray(new String[] {}));
}

}

return inst;
}

public List fromJSON(JSONArray jray) {

// Server always must return arrays even for single objects
List ilist = new ArrayList();

for (int i = 0; i < jray.size(); i++) {
IGWTSerializable obj = fromJSON(jray.get(i));
ilist.add(obj);
}

return ilist;
}
[/java]

Pyramid (former repoze.bfg) installation using buildout

Category: Web-Applications
Tags: ,

In order to create a new project using the Pyramid web application server just follow the following steps

  • Create a virtualenv environment
    [bash]
    $ virtualenv2.6 –no-site-packages myproject
    $ cd myproject/
    [/bash]
  • Update setuptools
    [bash]$ bin/easy_install -U setuptools[/bash]
  • Download bootstrap.py
    [bash]$ wget http://python-distribute.org/bootstrap.py
    $ mkdir downloads[/bash]
  • Create a raw buildout.cfg file
    [text][buildout]
    index = http://d.pypi.python.org/simple

    eggs-directory = eggs
    download-cache = downloads

    parts =
    pyramid

    eggs =
    ZopeSkel

    develop =

    [pyramid]
    recipe = zc.recipe.egg
    dependent-scripts = true
    eggs =
    pyramid
    interpreter = py[/text]

  • Initialize the environment
    [bash]$ bin/python bootstrap.py
    $ bin/buildout
    [/bash]
  • Create your application
    [bash]$ mkdir src && cd src/
    $ ../bin/paster create -t pyramid_starter myproject[/bash]
  • Adopt your buildout and add src/myproject to develop-eggs and myproject to eggs parameter in [pyramid] section.

    [text][buildout]
    index = http://d.pypi.python.org/simple

    eggs-directory = eggs
    download-cache = downloads

    parts =
    pyramid

    eggs =
    ZopeSkel

    develop = src/myproject

    [pyramid]
    recipe = zc.recipe.egg
    dependent-scripts = true
    eggs =
    pyramid
    myproject
    interpreter = py[/text]

  • Rerun buildout and start your application
    [bash]$ bin/buildout
    $ bin/paster serve src/myproject.core/development.ini[/bash]

ACMM – A way to define what improvement means

Category: Management
Tags: , ,

If you want to effectively manage change in one organization you need tools and models that help you controlling the change process. One of the most important things in such processes is to always know wheter change led to improved processes or how far you are away from an optimized structure.

So it is crucial to gradually gain control over unstructured processes and architecture. One possible model to achieve this goal is the Architecture Capability Maturity Model (ACMM, based on the general concept CMMI developed by SEI). It is focused on IT architecture related change management.

During a project for a bigger company I helped to identify problematic areas in their IT architecture and presented ACMM to the management as a possible model to kickstart their change process. One of the main problems there has been that IT architecture was heavily project driven and product development stalled.

ACMM is

  • a place to start
  • a common language and a shared vision
  • a framework for prioritizing actions
  • no inflexible set of rules but a collection of best practices

It describes an evolutionary improvement path from an ad hoc, immature process to a mature, disciplined process. It groups all possible processes relevant for the IT architecture into a set of key elements and for each group it defines 5 maturity levels.

Key elements are Architecture process, Development, Business, Top-Management, User, Communication, Security, Operations and Investments. You can put each of these elements into one of the following maturity levels

To put this model into action you normally follow the following steps (in short)

  • Actual status analysis
  • Mapping your processes into key elements
  • Maturity level for each element?
  • Target analysis
  • Which level do you want to reach for each element?
  • Creation of a score card that defines the way to go (tasks, involvments)

After a fixed timeframe (one year) you create an updated score card and check if you have reached your goals. Keep in mind that ACMM is only a border around other actions that need to be taken! Check the links for more details.



Copyright © 2010, Simon Pamiés