DEV Community

Felipe Norato Lacerda
Felipe Norato Lacerda

Posted on

Feature and Behavior Schematics - The Composition Approach

Some weeks ago I started to study how to create schematics to deliver faster and creating code patterns. I could try lots of techniques in this meantime to make the schematics to my team, like:

  • Use Template files;
  • Apply string manipulations;
  • Path manipulation to move files;
  • Filtering files by props.

And also my favorite one. That allows you to create complete flows, but without big complexity. This is the Schematic Composition!

This technique provides you to combine the schematics you created and external ones, like Angular schematics, to build powerful schematics that could create a whole structure for a feature.

It's important to alert you that this is a 20% technical and 80% philosophic post. 😂

I wrote a post explaining more about creating schematics and how to simplify that using just one line. There you can see how to apply path, templates, string manipulation.

Why is this technique so useful?

We can think we are using the functional programming approach. Each schematic is a function, that has its responsibility and could be joined by another Schematic to compose a big flow.

Sharing the responsibility to many functions we reduce the complexity, so it is easy to maintain and reuse.

Another big benefit in creating small schematics is when you need to create just a part of a feature or flow, you can call this one schematic alone.

There are some cases that you didn't have defined the design and architecture pattern at the beginning of the project. So we create some pages, start to define the patterns and, finally, create the schematics to each single component part of this pattern. When you start to revisit the old pages to apply the patterns you can just use the schematics you need to rewrite the old component.

Basically, we can use the Feature Schematic to create a new feature from scratch and the Behavior Schematic to compose the Feature Schematic to apply the new code to an existent feature.

I, personally, like to think in using the Feature Schematic like a Façade to join lots of Behavior Schematics and create a complete feature or flow.

The Behavior Schematics needs to be more generic as possible to be used alone and to compose many other Feature Schematics if it is required.

It is very important to define patterns of code and layout to make these schematics really productive, but how granular and how you will implement this is up to your needs.

Now I will explain to you how I implement the schematics to my current project and I defined the Feature and Behavior Schematics approach.

You can follow the examples on schematic-composition at my github.

The Behavior Schematic

To explain the conception about this we will implement a form and a table and create one behavior schematics for each one. To make it simple, we will use the angular material schematics to create the components for us. So here, is the first example: How to extend an external schematics

We just use the method externalSchematic with the collection name, schematic name and the options. 😄

import { chain, externalSchematic, Rule } from '@angular-devkit/schematics';

export default function(schema: any): Rule {
  return chain([
    externalSchematic('@angular/material', 'table', {
      name: [schema.name, 'table'].join('-'),
      project: schema.project
    })
  ]);
}

Here we reuse the @angular/material:table schematic and it generates some files.

Alt Text

The same we will do to create the form.

import { chain, externalSchematic, Rule } from '@angular-devkit/schematics';

export default function(schema: any): Rule {
  return chain([
    externalSchematic('@angular/material', 'addressForm', {
      name: [schema.name, 'form'].join('-'),
      project: schema.project
    })
  ]);
}

For both schematics, I set the same schema just name and project properties.

{
  "$schema": "http://json-schema.org/schema",
  "id": "form",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Library name",
      "$default": {
        "$source": "argv",
        "index": 0
      }
    },
    "project": {
      "type": "string",
      "description": "Library name"
    }
  },
  "required": ["name", "project"]
}

Feature Schematic

For this schematic, we can face it as the Façade to join the other schematics. The method to call the schematics from your collection is schematic, where you only need to pass the schematic name and the options. It's easy!

The extra thing I add here is the module schematic for the feature.

import { Schema } from '@schematics/angular/component/schema';
import {
  chain,
  externalSchematic,
  Rule,
  schematic
} from '@angular-devkit/schematics';

export default function(schema: Schema): Rule {
  return chain([
    externalSchematic('@schematics/angular', 'module', {
      name: schema.name,
      project: schema.project,
      routing: true
    }),
    schematic('table', { ...schema }),
    schematic('form', { ...schema })
  ]);
}

You can see, when we call this Feature Schematic it will call the Behavior Schematics.

Alt Text

Well done!

This example is for you to think you can use schematics to create things for you. I did thought this when I realized how powerful is this and how much it could help me in other past projects.

Top comments (0)