Do’s and Don’ts of Alfresco Development

Recently I had the pleasure of going up to NYC to speak with Alfresco customers and prospects about architecting Alfresco solutions and how to align that with efforts around digital transformation.  Part of that talk was a slide that discussed a few “do’s and don’ts” of designing Alfresco extensions.  Somebody suggested that I write down my thoughts on that slide and share it with the community.  So…  Here you go!

Do:

Stick with documented public APIs and extension points.

In early versions of Alfresco it wasn’t exactly clear what parts of the API were public (intended for use in extensions) or private (intended for use by Alfresco engineering).  This was mostly fixed in the 4.x versions of the product.  This was mostly a problem for people building things out on the Alfresco Java API.  Today, the Java API is fully annotated so it’s clear what is and is not public.  The full list is also available in the documentation.  Of course Alfresco’s server side Javascript API is public, as is the REST API (both Alfresco core and CMIS).  Alfresco Activiti has similar API sets.

Leverage the Alfresco SDK to build your deployment artifacts

During my time in the field I saw some customers and Alfresco developers roll their own toolchain for building Alfresco extensions using Ant, Gradle, Maven or in some cases a series of shell scripts.  This isn’t generally recommended these days, as the Alfresco SDK covers almost all of these cases.  Take advantage of all of the work Alfresco has done on the SDK and use it to build your AMPs / JARs and create your Alfresco / Share WAR file.  The SDK has some powerful features, and can create a complete skeleton project in a few commands using Alfresco archetypes.  Starting Alfresco with the extension included is just as simple.

Use module JARs where possible, AMPs where not

For most of Alfresco’s history, the proper way to build an extension was to package it as an AMP (Alfresco Module Package).  AMPs (mostly) act like overlays for the Alfresco WAR, putting components in the right places so that Alfresco knows where to find them.  Module JARs were first added in Alfresco 4.2 and have undergone significant improvements since introduction and are now referred to as “Simple Modules” in the documentation.  Generally, if your extension does not require a third party JAR, using a Simple Module is a much cleaner, easier way to package and deploy an extension to Alfresco.

Unit test!

This should go without saying, but it’s worth saying anyway.  In the long run unit testing will save time.  The Alfresco SDK has pretty good support for unit tests, and projects built using the All-In-One Archetype have an example unit test class included.

Be aware of your tree, depth and degree matter

At its core, the Alfresco repository is a big node tree.  Files and folders are represented by nodes, and the relationships between these things are modeled as parent-child or peer relationships between nodes.  The depth of this tree can affect application design and performance, as can the degree, or number of child nodes.  In short, it’s not usually a best practice to have a single folder that contains a huge number of children.  Not only can this make navigation difficult if using the Alfresco API, but it can also create performance troubles if an API call tries to list all of the children in a gigantic folder.  In the new REST APIs the results are automatically paged which mitigates this problem.

Use the Alfresco ServiceRegistry instead of injecting individual services

When using the Alfresco Java API and adding new Spring beans there are two ways to inject Alfresco services such as NodeService, PermissionService, etc.  You can inject the individual services that you need, or you can inject the ServiceRegistry that allows access to all services.  On the one hand, injecting individual services makes it easy to see from the bean definition exactly what services are used without going to the code.  On the other hand, if you need another service you need to explicitly inject it.  My preference is to simply inject the registry.  A second reason to inject the registry is that you’ll always get the right version of the service.  Alfresco has two versions of each service.  The first is the “raw” service, which has a naming convention that starts with a lower case letter.  An example is nodeService.  These services aren’t recommended for extensions.  Instead, Alfresco provides an AoP proxy that follows a naming convention that starts with an upper case letter, such as NodeService.  This is the service that is recommended and is the one that will be returned by the service registry.

Don’t:

Modify core Alfresco classes, web scripts, or Spring beans

Alfresco is an open source product.  This means that you can, in theory, pull down the source, modify it as much as you like and build your own version to deploy.  Don’t do that.  That’s effectively a fork, and at that point you won’t be able to upgrade.  Stick with documented extension points and don’t modify any of the core classes, Freemarker templates, Javascript, etc.  If you find you cannot accomplish a task using the defined extension points, contact Alfresco support or open a discussion on the community forum and get an enhancement request in so it can be addressed.  Speaking of extension points, if you want an great overview of what those are and when to use them, the documentation has you covered.

Directly access the Alfresco / Activiti database from other applications

Alfresco and Activiti both have an underlying database.  In general, it is not a best practice to access this database directly.  Doing so can exhaust connection pools on the DB side or cause unexpected locking behavior.  This typically manifests as performance problems but other types of issues are possible, especially if you are modifying the data.  If you need to update things in Alfresco or Activiti, do so through the APIs.

Perform operations that will create extremely large transactions

When Alfresco is building its index, it pulls transaction from the API to determine what has changed, and what needs to be indexed.  This works well in almost all cases.  The one case where it may become an issue is if an extension or import process has created a single transaction which contains an enormous change set.  The Alfresco Bulk Filesystem Import Tool breaks down imports into chunks, and each chunk is treated as a transaction.  Older Alfresco import / export functionality such as ACP did not do this, so importing a very large ACP file may create a large transaction.  When Alfresco attempts to index this transaction, it can take a long time to complete and in some cases it can time out.  This is something of an edge case, but if you are writing an extension that may update a large number of nodes, take care to break those updates down into smaller parts.

Code yourself into a corner with extensions that can’t upgrade

Any time you are building an extension for Alfresco or Activiti, pay close attention to how it will be upgraded.  Alfresco makes certain commitments to API stability, what will and will not change between versions.  Be aware of these things and design with that in mind.  If you stick with the public APIs in all of their forms, use the Alfresco SDK and package / deploy your extensions in a supported manner, most of the potential upgrade hurdles will already be dealt with.

Muck around with the exploded WAR file.  

This one should go without saying, but it is a bad practice to modify an exploded Java WAR file.  Depending on which application server you use and how it is configured, the changes you make in the exploded WAR may be overwritten by a WAR redeployment at the most inopportune time.  Instead of modifying the exploded WAR, create a proper extension and deploy that.  The SDK makes this quick and easy, and you’ll save yourself a lot of pain down the road.

This list is by no means comprehensive, just a few things that I’ve jotted down over many years of developing Alfresco extensions and helping my peers and customers manage their Alfresco platform.  Do you have other best practices?  Share them in the comments!

5 thoughts on “Do’s and Don’ts of Alfresco Development

  1. Since I mentioned I have some counter-points/remarks and Peter already got triggered by my tweet, I guess there is no point in waiting until I actually have time for a well-thought-out reply…

    Regarding public API I agree to 90%, but have to point out that quite a few utilities (even essential ones like DictionaryBootstrap) are technically not “public API”. E.g. there is no efficient processing of large data sets (see BatchProcessor) in the public API. Any bundled 3rd-party library can never be marked/documented as public API using the annotation-based approach Alfresco is taking, so in effect there isn’t even a way to do basic logging with only public API.
    Also be aware that Alfresco is a commercial entity and will prioritise enhancement requests primarily as fits into its business plan and as available resources permits. Various enhancement requests and code contributions have been lingering for years or even been closed as “too old”. Customer-status / filing with support provides only limited emphasis for requests (I have had customers waiting for years on requests – with code contributions – and even had some closed after ~4 years).
    Alfresco has a natural tendency to avoid expanding the scope of what is “public API” in order to reduce long-term efforts for engineering/maintenance. So even though you are using an open source product you are basically being told “look & don’t touch” in a similar way as a proprietary vendor will only allow you to use certain documented API / config options.

    “Leverage the Alfresco SDK to build your deployment artifacts” – But don’t let yourself be limited by it. The SDK is perfect for getting started. But it includes quite a few opinionated patterns / processes that can get in your way if you are doing more than just a run-of-the-mill “model + action + Share config” customisation. Since the SDK is just a glorified Maven-based build setup, anyone with decent Maven know-how should be able to achieve a setup that may fit their development approach better with little effort. Some community members (like myself) provide the custom setups they are using as part of their open source activities.

    “The Alfresco SDK has pretty good support for unit tests” – What the SDK supports are integration tests. In order to actually run “pure” unit tests (without starting up an in-process Alfresco instance), you may have to force your way around the integration test support.

    “[Don’t] Code yourself into a corner with extensions that can’t upgrade” – That should have been the main message up-front in my opinion. Sticking to public API as much as possible, not messing with Alfresco classes/beans etc. are some of the ways you can try to avoid that.
    Some basic recommendations are sadly missing though: “Understand what you are doing” and “Apply critical thinking to tips/recommendations/suggestions you are being given”. Too often do I see developers (customer, community and even partners) just “winging it” or using a trial&error approach (a.k.a. the “agile” process) with poorly-understood code/config samples found on StackOverflow, a forum or some half-decade old blog post.

    Lastly, just to make sure my remarks are not misconstrued: Anyone starting with Alfresco, anyone who is involved in only a few Alfresco customisation projects or only for a limited time in their day-to-day job, should definitively stick to letter of these kinds of recommendations. But when you are a trained, professional software architect with years of experience building business applications in full-time engagements (not just Alfresco), I would assume you know how to evaluate the trade-offs that come with leaving the holy path, take responsibility for any mistakes/incorrect assumptions you make along the way, and don’t need the vendor holding your hand / telling you what you should/shouldn’t do on a class-by-class basis.

    It is almost 12am here, and there are a few other points going through my mind, but I don’t want to ramble on. I hope I have made some sense and avoided coming off as someone claiming “I am a rockstar” without a care in the world…

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s