How we came to use Arhitecture Decision Records (ADR)

TL;DR

We realized that there has to a better way to record past decisions made on a project. Clubhouse and Git are limited when it comes to this. ADR offers a better understanding of why something needed to be changed, when it happened, what options were available, how it was implemented.

Our workflow

In most of the cases when we start a new project there are a few things that get set-up.

  • Each project will have a folder in OneDrive or Dropbox structured in a conventional way
  • The project has a Git repository
  • A Clubhouse workspace is set.

Other things are also done, password storage, contact details linked with the project, and so on, but that is not relevant for this article.

After that we have Clubhouse details set, stories added, epics created, milestones set and sprints.

Between Clubhouse and Git, there is enough control to see what happened or needs to be done, who did something and the immediate changes of files. If you also use version control on your app it’s even better, this way you can see what is new from version to version and follow the pull request (usually from dev to production or staging).

The issue

While all that sounds good, there still is a part that is left behind.

For example, you decide to change the payment gateway on your app. In order to have this change, there was a discussion that started for a reason (context), there were some options, a decision was made to go with one of the options, someone took that decision at a certain point in time, that decision has some consequences that you understood.

In the Clubhouse + Git setup you can’t catch all these details. Replace Clubhouse with any project management tool, it’s still the same.

Another example: you added an extra mandatory field in the registration form.
Why did you need that?
What other options did you have?
What decision was made?
When did it happen?
What consequences came from this?
Who was involved in the decision making?

ADR to the rescue

You might’ve already noticed that there is a pattern in the above examples and that will be present in the ADR structure.

What is an ADR?

Architecture decision record (ADR) is a document that will capture an important architectural decision in your project.

This document has some different structure options, but they all include the same elements.

  • Context (*)
  • Date (*)
  • Status (*)
  • Options
  • Decision (*)
  • Consequences (*)
  • People involved

(*) – mandatory

Why use ADR?

It’s a good way to keep track of changes and put them in context.
Might not seem that important at the moment, but it will be really helpful when you came back to a project 3 months later and you can’t remember why those changes were made in the first place.

It will also provide insightful information for the people that might come after you to work on the project or for new team members. Having a quick scan over the ADR folder and see why some things are the way they are it’s good way to get up to speed with what happened.

ADR structure

We decided to create an ADR structure to use in your projects.
At the project parent level, we have a docs directory that includes an adr folder.
In that adr folder we create files with a certain name structure 0001-ADRNameDescriptive.md.
Each ADR has a certain file structure.

You can find all these details in our ADR structure repository + some VSCode snippets for ADR.

Final thoughts and ADR example

We literally stumbled upon the idea of ADRs. I didn’t know what you search for in order to find this. It was a tweet that came up and was mentioning ADRs and from there I just connected the dots, did some research, and found out about this way of keeping track of important architectural decisions.

The repository that we linked above has more information, structure, links to external articles about ADR and it also includes some VSCode snippets for ADR.

Give it a try in one of your projects. It might seem like some extra work, but it’s worth it in the long run.

How to easily create multiple Custom Taxonomies in WordPress?

The main point of this article is to show you how to create multiple Custom Taxonomies using a more easy and re-usable approach.

We’re going to create a file called custom-taxonomies.php and place it a folder called ‘config’ inside your theme.

In custom-taxonomies.php we’re going to create a class that will generate Custom Taxonomies. It will be called DM_Project_Custom_Taxonomy.

					

<?php
class DM_Project_Custom_Taxonomy {

} // End class

new DM_Project_Custom_Taxonomy;

In here we create 3 fuctions: a __construct, one to define the custom taxonomies and one that will register them.

					

<?php
class DM_Project_Custom_Taxonomy {

    public function __construct() {
		
    }

    public function all_custom_taxonomies() {

    }

    private function dm_register_custom_taxonomy( $data ) {

    }

} // End class

new DM_Project_Custom_Taxonomy;

In the all_custom_taxonomies function we define all the custom post types that we want to use and will pass that data into the dm_register_custom_taxonomy.

					

public function all_custom_taxonomies() {
	$custom_taxonomies = [
		[
			'taxonomy_type' => 'custom_taxonomy',
			'singular' => 'Custom Taxonomy',
			'plural' => 'Custom Taxonomies',
			'slug' => 'custom-taxonomy',
			'custom_post_type' => 'post',
		],
		[
			'taxonomy_type' => 'second_custom_taxonomy',
			'singular' => 'Second Custom Taxonomy',
			'plural' => 'Other Custom Taxonomies',
			'slug' => 'second-custom-taxonomy',
			'custom_post_type' => 'my_custom_taxonomy_type',
		],


	];

	foreach ($custom_taxonomies as $key => $custom_taxonomy) {
		$this -> dm_register_custom_taxonomy( $custom_taxonomy );
	}
}

And the dm_register_custom_taxonomy will look like this

					

private function dm_register_custom_taxonomy( $data ) {

	$singular  = $data['singular'];
	$plural    = ( isset( $data['plural'] ) ) ? $data['plural'] : $data['singular'] . 's';
	$custom_taxonomy = $data['taxonomy_type'];
	$slug = $data['slug'];
	$custom_post_type = $data['custom_post_type'];

	$labels = array(
		'name'               => _x( $plural, 'post type general name', 'dm-artillerie-theme' ),
		'singular_name'      => _x( $singular, 'post type singular name', 'dm-artillerie-theme' ),
		'menu_name'          => _x( $plural, 'admin menu', 'dm-artillerie-theme' ),
		'name_admin_bar'     => _x( $singular, 'add new on admin bar', 'dm-artillerie-theme' ),
		'add_new'            => _x( 'Add New', $singular, 'dm-artillerie-theme' ),
		'add_new_item'       => __( 'Add New ' . $singular, 'dm-artillerie-theme' ),
		'new_item'           => __( 'New ' . $singular, 'dm-artillerie-theme' ),
		'edit_item'          => __( 'Edit ' . $singular, 'dm-artillerie-theme' ),
		'view_item'          => __( 'View ' . $singular, 'dm-artillerie-theme' ),
		'all_items'          => __( 'All ' . $plural, 'dm-artillerie-theme' ),
		'search_items'       => __( 'Search ' . $plural, 'dm-artillerie-theme' ),
		'parent_item_colon'  => __( 'Parent ' . $plural . ':', 'dm-artillerie-theme' ),
		'not_found'          => __( 'No ' . $plural . ' found.', 'dm-artillerie-theme' ),
		'not_found_in_trash' => __( 'No ' . $plural . ' found in Trash.', 'dm-artillerie-theme' )
	);

	$args = array(
		'labels'             => $labels,
		'description'        => __( $singular .'.', 'dm-artillerie-theme' ),
		'public'             => true,
		'publicly_queryable' => true,
		'show_ui'            => true,
		'show_in_menu'       => true,
		'query_var'          => true,
		'rewrite'            => array( 'slug' => $slug ),
		'capability_type'    => 'post',
		'has_archive'        => false,
		'hierarchical'       => false,
		'menu_position'      => null,
		'supports'           => array( 'title', 'author', 'thumbnail', 'excerpt', 'comments' )
	);

	register_taxonomy( $custom_taxonomy, array($custom_post_type) , $args );

}

If you want to do a small adjustment you can also define a variable from ‘textdomain’. In my case that is ‘dm-artillerie-theme’ and it’s hardcoded in there.

Now in the __construct we make sure to init the all_post_types function

					

public function __construct() {
	add_action( 'init', array( $this, 'all_custom_taxonomies' ) );
}

Your final code in the custom-taxonomies.php file should look like this:

					

<?php
class DM_Project_Custom_Taxonomy {

    public function __construct() {
        add_action( 'init', array( $this, 'all_custom_taxonomies' ) );
    }

	public function all_custom_taxonomies() {
		$custom_taxonomies = [
			[
				'taxonomy_type' => 'custom_taxonomy',
				'singular' => 'Custom Taxonomy',
				'plural' => 'Custom Taxonomies',
				'slug' => 'custom-taxonomy',
				'custom_post_type' => 'post',
			],
			[
				'taxonomy_type' => 'second_custom_taxonomy',
				'singular' => 'Second Custom Taxonomy',
				'plural' => 'Other Custom Taxonomies',
				'slug' => 'second-custom-taxonomy',
				'custom_post_type' => 'my_custom_post_type',
			],


		];

		foreach ($custom_taxonomies as $key => $custom_taxonomy) {
			$this -> dm_register_custom_taxonomy( $custom_taxonomy );
		}
	}

    private function dm_register_custom_taxonomy( $data ) {

        $singular  = $data['singular'];
        $plural    = ( isset( $data['plural'] ) ) ? $data['plural'] : $data['singular'] . 's';
        $custom_taxonomy = $data['taxonomy_type'];
        $slug = $data['slug'];
        $custom_post_type = $data['custom_post_type'];

        $labels = array(
            'name'               => _x( $plural, 'post type general name', 'dm-artillerie-theme' ),
            'singular_name'      => _x( $singular, 'post type singular name', 'dm-artillerie-theme' ),
            'menu_name'          => _x( $plural, 'admin menu', 'dm-artillerie-theme' ),
            'name_admin_bar'     => _x( $singular, 'add new on admin bar', 'dm-artillerie-theme' ),
            'add_new'            => _x( 'Add New', $singular, 'dm-artillerie-theme' ),
            'add_new_item'       => __( 'Add New ' . $singular, 'dm-artillerie-theme' ),
            'new_item'           => __( 'New ' . $singular, 'dm-artillerie-theme' ),
            'edit_item'          => __( 'Edit ' . $singular, 'dm-artillerie-theme' ),
            'view_item'          => __( 'View ' . $singular, 'dm-artillerie-theme' ),
            'all_items'          => __( 'All ' . $plural, 'dm-artillerie-theme' ),
            'search_items'       => __( 'Search ' . $plural, 'dm-artillerie-theme' ),
            'parent_item_colon'  => __( 'Parent ' . $plural . ':', 'dm-artillerie-theme' ),
            'not_found'          => __( 'No ' . $plural . ' found.', 'dm-artillerie-theme' ),
            'not_found_in_trash' => __( 'No ' . $plural . ' found in Trash.', 'dm-artillerie-theme' )
        );

        $args = array(
            'labels'             => $labels,
            'description'        => __( $singular .'.', 'dm-artillerie-theme' ),
            'public'             => true,
            'publicly_queryable' => true,
            'show_ui'            => true,
            'show_in_menu'       => true,
            'query_var'          => true,
            'rewrite'            => array( 'slug' => $slug ),
            'capability_type'    => 'post',
            'has_archive'        => false,
            'hierarchical'       => false,
            'menu_position'      => null,
            'supports'           => array( 'title', 'author', 'thumbnail', 'excerpt', 'comments' )
        );

        register_taxonomy( $custom_taxonomy, array($custom_post_type) , $args );

    }


} // End class

new DM_Project_Custom_Taxonomy;

In functions.php add the PHP file that you just worked on:

					

require_once('config/custom-taxonomies.php');

Using this code you’ll be able to generate multiple custom taxonomies without having to repeat the code and easily assigning the post type.

This is also a very clean way of keeping your code and not putting everything in functions.php. Use separate files and just call them from function.php.

You can find a similar article on how to create multiple Custom Post Types with the same approach.

 

How to easily create multiple Custom Post Types in WordPress?

We’re going to create a more easy to manage the way of generating multiple Custom Post Types.

First of all, we’re going to create a file that we’ll call it post-types.php and place it in a folder inside your theme called ‘config’.

In post-types.php we’ll create a class that generates Custom Post Types. I’ll call it DM_Project_Post_Types.

					

<?php
class DM_Project_Post_Types {


} // End class

new DM_Project_Post_Types;

In here we create 3 fuctions: a __construct, one to define the custom post types and one that will register them.

					

<?php
class DM_Project_Post_Types {

    public function __construct() {
        
    }

    public function all_post_types() {
     
    }

    private function dm_register_post_type() {

    }


} // End class

new DM_Project_Post_Types;

In the all_post_types function we define all the custom post types that we want to use and will pass that data into the dm_register_post_types.

					

    public function all_post_types() {
        $post_types = [
            [
                'post_type' => 'director',
                'singular'  => 'Director',
                'slug'      => 'director',
            ],
            [
                'post_type' => 'photographer',
                'singular'  => 'Photographer',
                'slug'      => 'photographer',
            ],


        ];

        foreach ($post_types as $key => $post_type) {
            $this -> dm_register_post_type( $post_type );
        }
    }

If you need to add custom data for ‘plural’ or other arguments, you can add them in the all_post_types function and pass them in dm_register_post_type to be used.

And the dm_register_post_type will look like this

					

    private function dm_register_post_type( $data ) {

        $singular  = $data['singular'];
        $plural    = ( isset( $data['plural'] ) ) ? $data['plural'] : $data['singular'] . 's';
        $post_type = $data['post_type'];
        $slug      = $data['slug'];

        $labels = array(
            'name'               => _x( $plural, 'post type general name', 'dm-artillerie-theme' ),
            'singular_name'      => _x( $singular, 'post type singular name', 'dm-artillerie-theme' ),
            'menu_name'          => _x( $plural, 'admin menu', 'dm-artillerie-theme' ),
            'name_admin_bar'     => _x( $singular, 'add new on admin bar', 'dm-artillerie-theme' ),
            'add_new'            => _x( 'Add New', $singular, 'dm-artillerie-theme' ),
            'add_new_item'       => __( 'Add New ' . $singular, 'dm-artillerie-theme' ),
            'new_item'           => __( 'New ' . $singular, 'dm-artillerie-theme' ),
            'edit_item'          => __( 'Edit ' . $singular, 'dm-artillerie-theme' ),
            'view_item'          => __( 'View ' . $singular, 'dm-artillerie-theme' ),
            'all_items'          => __( 'All ' . $plural, 'dm-artillerie-theme' ),
            'search_items'       => __( 'Search ' . $plural, 'dm-artillerie-theme' ),
            'parent_item_colon'  => __( 'Parent ' . $plural . ':', 'dm-artillerie-theme' ),
            'not_found'          => __( 'No ' . $plural . ' found.', 'dm-artillerie-theme' ),
            'not_found_in_trash' => __( 'No ' . $plural . ' found in Trash.', 'dm-artillerie-theme' )
        );

        $args = array(
            'labels'             => $labels,
            'description'        => __( $singular .'.', 'dm-artillerie-theme' ),
            'public'             => true,
            'publicly_queryable' => true,
            'show_ui'            => true,
            'show_in_menu'       => true,
            'query_var'          => true,
            'rewrite'            => array( 'slug' => $slug ),
            'capability_type'    => 'post',
            'has_archive'        => false,
            'hierarchical'       => false,
            'menu_position'      => null,
            'supports'           => array( 'title', 'author', 'editor', 'thumbnail', 'excerpt', 'comments' )
        );

        register_post_type( $post_type, $args );

    }

By default I added a $plural variable that will just add an ‘s’ at the end of the custom post type single in case you don’t define a plural in all_post_types.

If you want to do a small adjustment you can also define a variable from ‘textdomain’. In my case that is ‘dm-artillerie-theme’ and it’s hardcoded in there.

Now in the __construct we make sure to init the all_post_types function

					

    public function __construct() {
        add_action( 'init', array( $this, 'all_post_types' ) );
    }

Your final code in the post-types.php file should look like this:

					

<?php
class DM_Project_Post_Types {

    public function __construct() {
        add_action( 'init', array( $this, 'all_post_types' ) );
    }

    public function all_post_types() {
        $post_types = [
            [
                'post_type' => 'director',
                'singular'  => 'Director',
                'slug'      => 'director',
            ],
            [
                'post_type' => 'photographer',
                'singular'  => 'Photographer',
                'slug'      => 'photographer',
            ],


        ];

        foreach ($post_types as $key => $post_type) {
            $this -> dm_register_post_type( $post_type );
        }
    }

    private function dm_register_post_type( $data ) {

        $singular  = $data['singular'];
        $plural    = ( isset( $data['plural'] ) ) ? $data['plural'] : $data['singular'] . 's';
        $post_type = $data['post_type'];
        $slug      = $data['slug'];

        $labels = array(
            'name'               => _x( $plural, 'post type general name', 'dm-artillerie-theme' ),
            'singular_name'      => _x( $singular, 'post type singular name', 'dm-artillerie-theme' ),
            'menu_name'          => _x( $plural, 'admin menu', 'dm-artillerie-theme' ),
            'name_admin_bar'     => _x( $singular, 'add new on admin bar', 'dm-artillerie-theme' ),
            'add_new'            => _x( 'Add New', $singular, 'dm-artillerie-theme' ),
            'add_new_item'       => __( 'Add New ' . $singular, 'dm-artillerie-theme' ),
            'new_item'           => __( 'New ' . $singular, 'dm-artillerie-theme' ),
            'edit_item'          => __( 'Edit ' . $singular, 'dm-artillerie-theme' ),
            'view_item'          => __( 'View ' . $singular, 'dm-artillerie-theme' ),
            'all_items'          => __( 'All ' . $plural, 'dm-artillerie-theme' ),
            'search_items'       => __( 'Search ' . $plural, 'dm-artillerie-theme' ),
            'parent_item_colon'  => __( 'Parent ' . $plural . ':', 'dm-artillerie-theme' ),
            'not_found'          => __( 'No ' . $plural . ' found.', 'dm-artillerie-theme' ),
            'not_found_in_trash' => __( 'No ' . $plural . ' found in Trash.', 'dm-artillerie-theme' )
        );

        $args = array(
            'labels'             => $labels,
            'description'        => __( $singular .'.', 'dm-artillerie-theme' ),
            'public'             => true,
            'publicly_queryable' => true,
            'show_ui'            => true,
            'show_in_menu'       => true,
            'query_var'          => true,
            'rewrite'            => array( 'slug' => $slug ),
            'capability_type'    => 'post',
            'has_archive'        => false,
            'hierarchical'       => false,
            'menu_position'      => null,
            'supports'           => array( 'title', 'author', 'editor', 'thumbnail', 'excerpt', 'comments' )
        );

        register_post_type( $post_type, $args );

    }


} // End class

new DM_Project_Post_Types;

Now in functions.php add the PHP file that you just worked on:

					

require_once('config/post-types.php');

You will be able to generate as many custom post types you want and control the aspect of each of them without repeating the code. You also endup with a clean functions.php file and it will be easier to read in the future.

You can use this approach on other customizations that you’re doing on the site, creating a separate PHP file and call them from inside functions.php.

You can find a similar article on how to create multiple Custom Taxonomies with the same approach.