Published on

Introducing the Alliance Platform

Authors
  • Name
    Dave Coates

Welcome to the Alliance Platform blog!

This will be used to communicate updates to the Alliance Platform and associated libraries as things are fixed, improved or added.

Philosophy

The Alliance Platform is a collection of libraries (external), code (in template repo) and tooling (codegen) aimed at making development easy to understand and code quick to implement. It has a particular focus on making CRUD easier to work with but is by no means limited to only that.

The main core third party externally maintained libraries we use are django and django-restframework with some smaller libraries thrown in the mix as required.

We maintain our own set of open source libraries that we have full control over - prestojs, alliance-utils and csvpermissions.

And finally the template project contains some apps (common_lib, common_crud, django_react_template, codegen) that are generic but are easier to deal with as a directly managed dependency in the project rather than trying to build a sufficiently capable abstraction suitable for an external library. This allows customisations easily per project.

Over time some of this template project apps may become separately maintained libraries as we discover, through usage, that the interface is suitably stable and complete. The primary goal though is to make things quick and easy and part of that is avoiding getting stuck trying to workaround limitations in a library you have no control over.

Codegen

There's a lot of scaffolding required to create CRUD or DRF APIs. The manual codegen in the template assists by creating all the base classes and templates for you. Currently we support codegen on DRF (ViewSet, Serializer, FilterSet), CRUD views and Presto Forms.

This video goes over the usage of it and what's generated:

Django First

The approach with djrad was to define your API in django and then the frontend completely with React. With the Alliance Platform the approach is inverted. Where possible use django views, forms & templates and only when necessary enhance it with React.

This has a few key advantages. It's generally easier to understand. There's a view, template and everything is contained in a single request - there's no accumulation of state as the app runs as in a SPA that can make things harder to reason about. There's also plenty of documentation and stackoverflow questions about django.

With modern websites behaving more like apps you quickly reach the limits of what static templates can achieve and need to enhance it with javascript. To facilitate this the django_react_template app provides some template tags to make it easy to render components from a template and pass data from django.

Using this approach you could easily replace a HTML select box with a javascript version that supports autocomplete, replace a whole form with a React component but still handle submissions from a django form or completely take over rendering while retaining the overall layout and navigation from the base django template. This makes switching between pure django views and javascript enhanced views as seamless as possible and eliminates the need to duplicate the layout in React.

This video goes over rendering React components and integrating PrestoJS with django:

See django_react_template for more details.

CRUD

Within the template there's an app called common_crud that provides base classes for dealing with CRUD operations. These classes use django TemplateView's and ModelForm's and are quite minimal when compared to django-admin but easier to customise. Out of the box they look like:

Maple
Lake
Maple
Lake

See common_crud in for more details.

Presto

Presto is a library we've written that tries to retain some of the benefits of djrad (eg. frontend models & caching, forms) while making it more modular, easier to understand and customise, and have no dependency on the backend.

djrad generated frontend models automatically from backend serializers and was a bit of a black box as to what was going on and difficult to customise the fields on the model. Presto has it's own concept of frontend model - the ViewModel - and we support generating it automatically using the view_model_codegen decorator. This runs automatically as part of the devserver in development ensuring the frontend models always match the backend but with the ability to both fully inspect how the model has been defined and customise all details of it.

The codegen will output a base class like:

import { CharField, viewModelFactory } from '@prestojs/viewmodel'

export default class BaseUser extends viewModelFactory({
  firstName: new CharField(),
  lastName: new CharField(),
  email: new CharField(),
}) {
  static label = 'User'
  static labelPlural = 'Users'
  static modelName = 'User'
}

This class you never modify as it will be replaced whenever codegen runs. The first time a descendant class is also generated in which you can make whatever modifications you need:

import BaseUser from './generated/BaseUser'

export default class User extends BaseUser.augment({
  addressIds: new ListField({
    childField: new IntegerField({
      label: 'Addresses',
    }),
  }),
}) {
  getLabel(): string {
    if (this._assignedFields.includes('firstName') && this._assignedFields.includes('lastName')) {
      return (this.firstName + ' ' + this.lastName).trim() || this.email
    }
    return this.email
  }
}

The devserver console output will show details about codegen:

Auto Codegen Output

See the Auto Codegen documentation for more details.

Server Choices

Generating choices from the server often becomes a necessary requirement once you have foreign key fields that have many records. Having an autocomplete lookup avoids loading too much data and being slow and makes it easier to find records through filtering.

djrad achieved this by handling foreign key lookups via an API endpoint that was generated as part of model registration. There's no registration with Presto and we achieve this using an explicit decorator - server_choices

It's usage is simple:

@server_choices(["project_manager", search_fields=["name"]]
class ProjectSerializer(ModelSerializer):
    ...

This enables an endpoint for this model that can then be called from the frontend.

To make it easy to interact with API's of this nature (which may be paginated) Presto has AsyncChoices and SelectAsyncChoiceWidget. The Auto Codegen takes care of generating this for you.

The Auto Codegen & Rendering Components video show above contains details about it:

Documentation

It's early days but we are starting to produce more documentation and as part of making that more visible and easier to consume each project created from the template will have it's own documentation site for everything in the template. External libraries (including alliance-utils etc) will have their own separate documentation.

Having the documentation generated from the project means you can always refer to what is current for a particular project even if the template project has moved on.

The documentation is generated automatically from the source and is available on the gitlab pages url for your project: https://GROUP.pages.internal.alliancesoftware.com.au/PROJECT/

You can view the most recent version from the template here.

As you start to use this please raise an issue or (even better) open a MR if you find incorrect, unclear or missing documentation

Going Forward

We're planning regular releases for the template both for bugfixes and new features. We'll communicate these changes through this blog, Slack and the weekly meeting.

As you use the Alliance Platform you'll inevitably find bugs or hit limitations that we need to address. Please ask in #tech-support in Slack but in the case where it requires changes it would be great if you can open an issue yourself in the relevant repository. This makes it easy for us to communicate back to you when your issue has been resolved or updated.