FOUR WINDS TECH BLOG

WEBサイト制作・WEBアプリケーション開発が得意な会社の技術ブログ

プログラミングできなくてもブラウザで簡単にAPIを作成できるOSSのHeadless CMS「Strapi」の機能と使い方

モダンなWEBサイト制作・WEBシステム開発では、いわゆるJamstackと呼ばれるアーキテクチャを採用することが増えています。

このようなアーキテクチャを採用する場合はFirebaseのようなmBaaSを利用したり、自身でAPIを開発したり、データを永続的に保存するための方法が必要です。

APIを開発する場合、LaravelやCakePHPなどのフレームワークを利用して開発することも可能ですが、少なくない工数が発生します。

Strapiはオープンソースで開発されているHeadless CMSで、初期設定さえエンジニアが行えば誰でも管理画面を通じてGUIでAPIを作成できます。

strapi.io

この記事ではStrapiのインストールと基本的な使い方について紹介します。

Headless CMSとは

ユーザーに表示するための画面がないCMSをHeadless CMSといいます。

WordPressなどのCMSでは、サイトへの訪問者にはテーマで設定したページデザインで表示されますが、Headless CMSはユーザーに表示するためのページデザインは提供しません。コンテンツの管理およびコンテンツのAPIだけを提供します。

画面がないと不便と思う方もいらっしゃいますが、管理しているコンテンツをWEBだけでなくスマホアプリやデスクトップアプリなどでも表示したい場合、最初からStrapiのようなHeadless CMSで管理することで、コンテンツを一元的に管理でき、API開発にかかる工数も削減できるメリットがあります。

コードを記述せずにデータの構造を定義するだけでAPIを作成できるので、プロトタイピングやモックアップの作成、DXにおけるノーコード・ローコード開発にも向いています。

Strapiとは

オープンソースで開発されているNode.js製のHeadless CMSです。

strapi.io

次のようなことができます。

  • コンテンツの管理
  • 役割ごとに権限を設定
  • APIの提供
  • プラグインによる機能の拡張
  • CMSのカスタマイズ

インストール方法

それでは早速インストール方法を説明します。

strapi.io

公式ガイドではいくつかの方法が紹介されていますが、環境によってはエラーが発生する場合があるため、この記事では別の方法でインストールします。

前提

この記事では次のソフトウェアが事前にインストールされている前提で説明します。

ソフトウェア バージョン
Node.js 14.x
npm 6.x
yarn 1.22.x

strapiコマンドをインストール

以下のコマンドでグローバルにstrapiコマンドをインストールします。

yarn global add strapi

Strapiプロジェクトを作成

以下のコマンドでStrapiプロジェクトを作成します。

strapi new --no-run --dbclient=mysql --dbhost=localhost --dbport=3306 --dbname=database --dbusername=root --dbpassword=password strapi

※データベースの接続情報はconfig/database.jsに保存されます。このファイルはデフォルトではバージョン管理の対象に含まれるため、上記コマンドを実行する際に実際の接続情報を指定しないことをおすすめます。

実行が完了すると、次のようなメッセージが表示されます。

Creating a new Strapi application at /var/www/playground/strapi.

Creating a project from the database CLI arguments.
Creating files.
Dependencies installed successfully.

Your application was created at /var/www/playground/strapi.

Available commands in your project:

  yarn develop
  Start Strapi in watch mode.

  yarn start
  Start Strapi without watch mode.

  yarn build
  Build Strapi admin panel.

  yarn strapi
  Display all available commands.

You can start by doing:

  cd /var/www/playground/strapi
  yarn develop

環境変数を設定する

データベースの接続情報や公開URLなどは環境(開発環境/ステージング環境/本番環境)などによって変わることが多いです。

Strapiではそのような場合に設定を簡単に変更できるように、.envによる環境変数の設定に対応しています。

環境変数を設定するには、プロジェクトのルートディレクトリに移動し、.env.exampleをコピーして.envファイルを作成します。

cd ./strapi
cp .env.example .env

作成した.envファイルを編集し、次のように変数を設定します。

HOST=0.0.0.0
PORT=1337
DATABASE_HOST=mysql
DATABASE_PORT=3306
DATABASE_NAME=strapi
DATABASE_USERNAME=root
DATABASE_PASSWORD=root
PUBLIC_URL=http://strapi.playground.test
IS_PROXIED=true

※データベースの接続情報や公開URLなどは適宜ご自身の環境にあわせて変更してください

その他、環境変数で設定可能な値と内容についてはドキュメントをご確認ください。

strapi.io

Strapiを起動する

以上でStrapiを起動する準備ができましたので、次のコマンドで起動してみます。

yarn develop

※本番環境でStrapiを起動する場合はyarn startコマンドを実行します。

ブラウザでhttp://localhost:1337にアクセスすると、welcomeページが表示されます。

welcomeページのガイドに従って最初のユーザーを作成します。

基本的な操作

コンテンツタイプを作成する

WordPressにおける投稿タイプのように、管理するコンテンツのタイプを作成します。

ダッシュボードではこのような画面が表示されます。

メニューから「Content-Types Builder」 を選択します。

f:id:four-winds:20210204172559p:plain

「Content-Types Builder」ではコンテンツタイプを管理できます。

「Create new collection type」を選択します。

f:id:four-winds:20210204172624p:plain

コレクションの情報を入力するモーダルウィンドウが表示されます。

f:id:four-winds:20210204172645p:plain

基本設定

Display name

コンテンツタイプの表示名を入力します。英語で複数形で入力するのをおすすめします。

例: 管理するコンテンツが本であればbooksを入力します。

高度な設定

f:id:four-winds:20210204172713p:plain

Draft/publish system

下書き機能を利用する場合、ONにします。

Collection name

システム内で利用するコンテンツタイプの識別子です。APIのURIとデータベースにテーブル名に影響します。

「Display name」を英語で複数形で入力している場合、何も入力しなくても問題ありません。

各項目を入力して、「続ける」をクリックします。

コレクションのフィールドを入力するモーダルウィンドウが表示されます。

f:id:four-winds:20210204172749p:plain

「Text」を選択してみます。

基本設定

f:id:four-winds:20210204172812p:plain

Name

フィールド名を入力します。

Types

フィールドに入力する内容が短い文字列の場合は「Short text」、長い文字列の場合は「Long text」を選択します。

255文字以内なら「Short text」、255文字より多ければ「Long text」がおすすめです。

高度な設定

f:id:four-winds:20210204172838p:plain

  • 入力形式
  • 必須
  • 最小
  • 最大

など、追加のフィールド情報を指定できます。

「Add another field」をクリックして、同様に「Rich text」で本文を入力するフィールドも追加します。

追加したら、「終了」をクリックします。

フィールドを追加したら、「保存」をクリックします。

f:id:four-winds:20210204172913p:plain

コンテンツタイプを追加するとStrapiが再起動します。

少し待って画面を更新すると、作成したコンテンツタイプがメニューに表示されます。

f:id:four-winds:20210204172940p:plain

コンテンツを作成する

メニューをクリックして、「Postsを追加」をクリックします。

f:id:four-winds:20210204173004p:plain

各フィールドを入力し、「保存」をクリックします。

f:id:four-winds:20210204173025p:plain

保存すると、右上の「Publish」ボタンが有効になります。

「Publish」をクリックすると作成したPostが公開されます。

f:id:four-winds:20210204173042p:plain

ロールと権限を設定する

コンテンツタイプを追加したら、アクセス権を設定する必要があります。

メニューから[設定 > ロールと権限]を選択し、「Public」の右側のえんぴつのアイコンをクリックします。

f:id:four-winds:20210204173059p:plain

Postsのアクションにすべてチェックを入れ、「Save」をクリックします。

f:id:four-winds:20210204173115p:plain

APIを確認

http://localhost:1337/postsにアクセスすると、作成したPostsのデータがJSONで取得できていることがわかります。

[
  {
    "id": 2,
    "title": "タイトル",
    "content": "本文.........本文本文",
    "published_at": "2021-02-04T06:41:43.000Z",
    "created_at": "2021-02-04T06:41:37.000Z",
    "updated_at": "2021-02-04T06:41:43.000Z"
  }
]

※ブラウザに表示されるJSONは整形はされません、見やすくするために執筆時に整形しています。

基本的な操作方法は以上です。

まとめ

オープンソースのHeadless CMS「Strapi」について紹介しました。

標準でインストールされているプラグインを利用することでwebhookの設定も可能なため、Laravelなどのフレームワークと組み合わせれば様々な機能が実現できます。

APIの開発が必要になった場合はぜひ利用を検討してみてください。

Herokuにアプリケーションをデプロイする方法(Laravel編)

開発したアプリケーションをインターネットに公開する際に、VPSやAWSのEC2を利用できます。

しかし、VPSやEC2などのサービスは基本的にサーバの管理を自身で行わなければいけません。

サーバ管理ではディスク容量に十分な空きスペースがあるか、CPUやメモリなどのリソースに余裕があるかなど、様々なメトリクス(指標)を把握・管理しなければいけないため、インフラが得意でなかったりアプリケーションの開発に集中したい場合などには時間をかけられない・かけたくない時もあります。

Herokuではインフラの管理はすべてマネージド(Herokuが管理してくれる)ので、サーバを管理する必要がなくなります。

この記事ではLaravelアプリケーションをHerokuにデプロイする方法について説明します。

Herokuとは

jp.heroku.com

Herokuはアプリケーションを実行するための環境を用意してくれるプラットフォームで、サーバの管理の他、アドオンを追加することでAWS S3やデータベースサーバを追加することもできます。

またビルドパックと呼ばれるビルド設定を追加したり、自身でビルドスクリプトを記述することでPHPやNode.js、Javaなど様々な言語のアプリケーションをデプロイできます。

Herokuを使ってみる

※アプリケーションは既に作成済みの前提です。この記事では新しいLaravelプロジェクトでアプリケーションをデプロイします。

※アカウントは登録済の前提です。アカウントがない場合は次のページから登録できます。

signup.heroku.com

Herokuの操作は管理画面からもできますが、CLI(コマンドラインインターフェース)も提供されています。

この記事ではCLIからの操作を説明します。

Heroku CLIをインストールする

次のページのガイドに従って、Heroku CLIのインストールおよびheroku loginコマンドまで実行します。

devcenter.heroku.com

アプリケーションを作成する

次のコマンドでアプリケーションを作成できます。

heroku apps:create

上記コマンドを実行すると、アプリケーション名(例: arcane-gorge-56836)が表示されます。

他のコマンドを実行する際に指定するので、アプリケーション名を控えておきます。

もしアプリケーション名がわからなくなった場合はheroku appsコマンドを実行するか、管理画面から確認できます。

ビルドパックを追加する

Laravelのアプリケーションを実行するにはサーバにPHPをインストールしたり、Composerで管理している依存パッケージをインストールしたりする必要があります。

heroku/phpビルドパックを追加すると、上記のようなPHPアプリケーションを実行する環境を作成する処理を自動的に実施します。

ビルドパックを追加するには、次のコマンドを実行します。

heroku buildpacks:add -a arcane-gorge-56836 heroku/php

-aオプションは作成時に出力されたアプリケーション名を指定します。

Procfileを追加する

Herokuではいくつかのプロセスを実行することができます。

devcenter.heroku.com

アプリケーションをWEBで公開する際にはwebプロセスを実行する際のコマンドを指定する必要があります。

プロセスを実行する際のコマンドを指定するには、プロジェクトのルートディレクトリ(Laravelであればartisanファイルと同じディレクトリ)に次のようなProcfileを作成します。

web: $(composer config bin-dir)/heroku-php-apache2 public

このようにwebプロセスを指定すると、publicディレクトリをドキュメントルートとしてApacheのプロセスが起動されます。

public/.htaccessに相当するNginxの設定ファイルを追加すれば、Nginxでwebプロセスを起動することもできます。

devcenter.heroku.com

環境変数を設定する

Laravelではデータベースの接続情報やログの出力先などを.envで設定できます。

Herokuの場合.envではなくHerokuの環境変数を利用して設定するのがデファクトスタンダードです。

Herokuで環境変数を設定するには、次のコマンドを実行します。

heroku config:set -a arcane-gorge-56836 \
    APP_NAME=サンプルアプリケーション \
    APP_ENV=production \
    APP_KEY=base64:xxxxxxx \
    APP_DEBUG=false \
    APP_URL=https://arcane-gorge-56836.herokuapp.com/ \
    LOG_CHANNEL=stderr \
    LOG_LEVEL=error

アプリケーションをデプロイする

Herokuにアプリケーションをデプロイするには、GitでアプリケーションコードをHerokuのリポジトリにプッシュします。

git push heroku master

リモートリポジトリがない場合は次のコマンドでリモートリポジトリを追加します。

git remote add heroku https://git.heroku.com/arcane-gorge-56836.git

アプリケーションを確認する

次のコマンドを実行すると、ブラウザでアプリケーションを開きます。

heroku apps:open -a arcane-gorge-56836

以上でHerokuにLaravelのアプリケーションをデプロイできます。

Herokuでファイルシステムを使う場合の注意

Herokuではデプロイするたびに新しいコンテナが作成されるため、サーバ上に書き込んだファイルは永続化されません。

つまり、ユーザーがアップロードした画像等のファイルやアプリケーションログなどをファイルシステムに書き込むと、データが消失します。

Herokuにアプリケーションをデプロイする場合はログ出力先を標準出力に変更したり、S3にファイルをアップロードしたり、RedisやMemcachedなどにキャッシュを保存するなどファイルシステムを使わないように注意する必要があります。

設計と開発の原則

WEBサイト制作・WEBシステム開発で設計をせずにコードを作成してしまうと、仕様の変更に追従できなかったり影響範囲がわからず保守できない、もしくは不具合の多いWEBサイト・WEBシステムになってしまうことがあります。

しかし、設計・開発にもベストプラクティスが存在します。

ベストプラクティスに従うことで、仕様の変更に柔軟に対応できる保守性の高いWEBサイト・WEBシステムをつくることができます。

この記事では、コードを作成する際に意識すべきとよく言われる代表的な原則について紹介します。

SOLID

SOLIDとはオブジェクト指向プログラミングでソフトウェアを設計・開発する際に守るべき原則です。

以下の原則の頭文字を取って、SOLIDと呼ばれています。

  1. Single responsibility principle(単一責任の原則)
  2. Open–closed principle(開放閉鎖の原則)
  3. Liskov substitution principle(リスコフの置換原則)
  4. Interface segregation principle(インターフェイス分離の原則)
  5. Dependency inversion principle(依存性逆転の原則)

それぞれの詳細について説明します。

Single responsibility principle(単一責任の原則)

Single responsibility principle(単一責任の原則)は、ひとつのクラスに複数に責任を負わせてはいけないという原則です。

NGの例

<?php
class Post {
    /**
     * Postの内容をHTMLのtableタグで出力する
     */
    public function outputHtml()
    {
        // 処理...
    }

    /**
     * Postをデータベースに保存する
     */
    public function save()
    {
        // 処理...
    }
}

この例ではPostクラスにHTMLを出力する責任とデータベースを操作する責任があります。

ひとつのクラスに複数の責任を負わせると、コードの複雑性が上がりプログラムを修正する際に影響範囲が読みづらくなります。

OKの例

<?php
class PostHelper {
    /**
     * Postの内容をHTMLのtableタグで出力する
     */
    public function outputHtml(Post $post)
    {
        // 処理...
    }
}

class PostModel {
    /**
     * Postをデータベースに保存する
     */
    public function save()
    {
        // 処理...
    }
}

このように、ひとつのクラスはひとつの責任を持つような設計にすることで、コードの見通しが良くなり影響範囲を少なくできます。

Open–closed principle(開放閉鎖の原則)

あるクラスに対して、機能を追加する度に処理を変更する必要がないような設計にするべきという原則です。

NGの例

<?php
class Notifier {
    /**
     * Slackで通知を送信する
     */
    public function notifyBySlack()
    {
        // 処理...
    }

    /**
     * メールで通知を送信する
     */
    public function notifyByEmail()
    {
        // 処理...
    }

    /**
     * Chatworkで通知を送信する
     */
    public function notifyByChatwork()
    {
        // 処理...
    }
}

function sendNotification ($channel) {
    $notifier = new Notifier();
    switch ($channel) {
        case 'slack':
            $notifier->notifyBySlack();
            break;
        case 'email':
            $notifier->notifyByEmail();
            break;
        case 'chatwork':
            $notifier->notifyByChatwork();
            break;
        default:
            // 想定していないchannelを指定された場合
    }
}

この例ではLINEやDiscordなど通知先を増やしたい場合にswitchcaseを都度追加しなければいけません。

OKの例

<?php
interface NotifierInterface {
    /**
     * 通知を送信する
     */
    public function notify();
}

class SlackNotifier implements NotifierInterface {
    public function notify()
    {
        // Slackに通知を送信する処理
    }
}

class EmailNotifier implements NotifierInterface {
    public function notify()
    {
        // Slackに通知を送信する処理
    }
}

class ChatworkNotifier implements NotifierInterface {
    public function notify()
    {
        // Slackに通知を送信する処理
    }
}

function sendNotification ($notifier) {
    $notifier->notify();
}

sendNotification関数をNotifierInterfaceを実装したクラスのインスタンスを受け取るように変更することで、通知先が増える度にsendNotification関数の処理を修正しなくても良くなります。

Liskov substitution principle(リスコフの置換原則)

同じinterfaceを実装したり、classを継承したりしている場合、各クラスでの振る舞い(処理内容)が同じになっているべきという原則です。

NGの例

<?php
interface NotifierInterface {
    /**
     * 通知を送信する
     */
    public function notify();
}

class SlackNotifier implements NotifierInterface {
    public function notify($message = '')
    {
        $response = Slack::send($message);
        if ($response->status === 'OK') {
            return '1';
        } else {
            return '0';
        }
    }
}

class EmailNotifier implements NotifierInterface {
    public function notify($message = '')
    {
        $response = Email::send($message);
        if ($response->status === 'OK') {
            return true;
        } else {
            return false;
        }
    }
}

function sendNotification ($notifier) {
    $success = $notifier->notify();
    if ($success) {
        Session::message('通知を送信しました');
    } else {
        Session::message('通知を送信できませんでした');
    }
}

この例ではNotifierInterfaceを実装しているSlackNotifierクラスとEmailNotifierで返り値の型が異なっています。

呼び出し元が振る舞いや返り値の違いを考慮する必要があると、クラスを呼び出す際に都度内部の仕様まで確認する必要があるため、効率が悪くバグの発生にもつながります。

OKの例

<?php
interface NotifierInterface {
    /**
     * 通知を送信する
     */
    public function notify(): bool;
}

class SlackNotifier implements NotifierInterface {
    public function notify($message = '')
    {
        $response = Slack::send($message);
        if ($response->status === 'OK') {
            return true;
        } else {
            return false;
        }
    }
}

class EmailNotifier implements NotifierInterface {
    public function notify($message = '')
    {
        $response = Email::send($message);
        if ($response->status === 'OK') {
            return true;
        } else {
            return false;
        }
    }
}

function sendNotification ($notifier) {
    $success = $notifier->notify();
    if ($success) {
        Session::message('通知を送信しました');
    } else {
        Session::message('通知を送信できませんでした');
    }
}

NotifierInterfacenotifyメソッドの返り値を明示的にboolであることを指定すると、実装クラスに返り値を強制できる(異なる型を返却するとエラーになる)ため、sendNotification関数の処理ではnotifyメソッドの返り値をboolである前提で扱えるようになります。

Interface segregation principle(インターフェイス分離の原則)

Interfaceで実装を定義する際に、実装クラス側で必要のないメソッドの定義を強制してはいけないという原則です。

NGの例

<?php
interface NotifierInterface {
    /**
     * 通知を送信する
     */
    public function notify(): bool;
    
    /**
     * SlackのAPIキーを取得する
     */
    protected function getSlackApiKey(): string;
}

class SlackNotifier implements NotifierInterface {
    public function notify($message = '')
    {
        $apiKey = $this->getSlackApiKey();
        // 処理...
    }

    protected function getSlackApiKey()
    {
        // APIキーを取得する
    }
}

class EmailNotifier implements NotifierInterface {
    public function notify($message = '')
    {
        $response = Email::send($message);
        if ($response->status === 'OK') {
            return true;
        } else {
            return false;
        }
    }

    protected function getSlackApiKey()
    {
        // 何もしない
    }
}

function sendNotification ($notifier) {
    $notifier->notify();
}

EmailNotifierクラスではgetSlackApiKeyメソッドは使わないので定義する必要はありませんが、interfaceでメソッドの定義を強制しているため、不要なメソッドを定義しています。

OKの例

<?php
interface NotifierInterface {
    /**
     * 通知を送信する
     */
    public function notify(): bool;
}

class SlackNotifier implements NotifierInterface {
    public function notify($message = '')
    {
        $apiKey = $this->getSlackApiKey();
        // 処理...
    }

    protected function getSlackApiKey()
    {
        // APIキーを取得する
    }
}

class EmailNotifier implements NotifierInterface {
    public function notify($message = '')
    {
        $response = Email::send($message);
        if ($response->status === 'OK') {
            return true;
        } else {
            return false;
        }
    }
}

function sendNotification ($notifier) {
    $notifier->notify();
}

この例ではgetSlackApiKeyメソッドはSlackNotifierクラスの内部でしか利用しない、つまり共通化する必要がないので、SlackNotifierクラスの内部で定義するだけで十分でしょう。

Dependency inversion principle(依存性逆転の原則)

あるクラスにメソッドが定義されていることを、クラス定義ではなくInterfaceで担保するべきという原則です。

NGの例

<?php
class SlackNotifier {
    public function notify()
    {
        // 処理...
    }
}

function sendNotification (SlackNotifier $notifier) {
    $notifier->notify();
}

この例ではsendNotification関数がSlackNotifierクラスのインスタンスに依存しており、別の通知先に送信するにはsendEmailNotificationのような関数を追加しなければいけません。

OKの例

<?php
interface NotifierInterface {
    /**
     * 通知を送信する
     */
    public function notify(): bool;
}

class SlackNotifier implements NotifierInterface {
    public function notify()
    {
        // 処理...
    }
}

function sendNotification (NotifierInterface $notifier) {
    $notifier->notify();
}

SlackNotifierなどのような通知先ごとのクラスにnotifyメソッドがあることをNotifierInterfaceに担保させることで、sendNotification関数はNotifierInterfaceを実装したインスタンスとして$notifierを受け取れるようになり、通知先の違いを意識せずにnotifyメソッドを呼び出すことができます。

KISSの原則

Keep it simple, stupid.

の略です。DeepLで翻訳すると

シンプルにしとけよ、アホ。

になります。

ソフトウェアを設計する際には何事もシンプルにするべきという原則です。

プログラムで例を示しますが、システムアーキテクトなど広い範囲に当てはまる考え方です。

NGの例

<?php
class Post {
    public static function getAll($user = null, $id = null)
    {
        // 処理...
    }
}

$posts = Post::getAll();

この例ではgetAllメソッドにユーザーを指定するとそのユーザーと紐づくPostデータ、さらにIDを指定すると特定のIDを持つPostデータを取得できることを想定しています。

しかし、例えばユーザーは指定せずにIDだけを指定したい、といったユースケースが出てきてしまうと、途端にこの処理は複雑化します。

OKの例

<?php
<?php

class Post {
    public static function getAll()
    {
        // 処理...
    }

    public static function getByUser()
    {
        // 処理...
    }

    public static function getById()
    {
        // 処理...
    }
}

$posts = Post::getAll();

実際にはクエリビルダーなどを利用することで更にシンプルに記述できますが、このようにメソッドを分けることでNGの例よりも各メソッドの処理をシンプルにできます。

YAGNI

「You ain't gonna need it」の略で、(機能などが)必要になるまでは実装すべきでないという原則です。

前述のSOLIDで示した例で言えば、様々な通知チャンネルを作成できるようにNotifierInterfaceを実装したSlackNotifierクラスやEmailNotifierクラスを定義しました。

もし仕様として、様々な通知チャンネルを作成する必要があると明確に決まっている場合は示したような実装をするとSOLID的には良いのですが、80%不要にも関わらず将来的に必要になるかもしれない、といった理由でChatworkNotifierクラスやDiscordNotifierクラスなどを作成してしまうと、使わなかった場合作成にかかった時間は無駄になってしまいます。

また、コードが増えれば増えるほどバグが生まれる可能性も上がります。

拡張性を意識することは重要ですが、過度に拡張性を重視してしまうと必要以上に時間がかかったり、無用のバグを生み出したりします。

本当に拡張性が必要な機能かどうか、検討が必要です。

DRY

「Don't repeat yourself」の略で、同じコードを繰り返し書いてはいけないという原則です。

同じコードを何度も記述すると、例えば仕様に変更が発生した際に多くの修正が発生するかもしれません。

同じ処理であればクラスのメソッドや関数に処理を記述し、メソッド・関数を呼び出すように共通化することで何度も同じ記述をせずに済みます。

ただし、同じ記述であってもSOLIDの原則(特に単一責任の原則)を満たさない形で共通化してはいけません。

無闇に共通化すると、ひとつの修正で思わぬ部分に影響が出ることもあるので、同じ処理でもコンテキストが異なる場合はあえて共通化しない方が保守しやすいプログラムになる場合もあります。

GOF Design Patterns

GOFとは

オブジェクト指向における再利用のためのデザインパターンという書籍を執筆した4人の著者をよく「Gang of Four」と呼びます。

GOF Design Patternsとは

上記の書籍で紹介されている、オブジェクト指向プログラミングの設計パターンのことです。

オブジェクト指向プログラミングでよく採用される設計のパターンが紹介されていて、問題に直面した時にこの書籍で紹介されているパターンを知っていれば時間をかけずに良い設計で解決できるようになります。

domain-driven design(ドメイン駆動設計)

Eric Evans氏のDomain-Driven Design: Tackling Complexity in the Heart of Softwareで紹介されたソフトウェアの設計手法です。よくDDDと略されます。

かなり内容が濃く、人によって理解が若干異なる場合があります。

ドメイン駆動設計 - Wikipediaによれば、次のような要素から表現されるそうです。

ドメイン駆動設計では、ドメインモデルを表現する要素として、下記のものを挙げている。

  • エンティティ (参照オブジェクト): ドメインモデル内のオブジェクトであり、その属性によってではなく、連続性と識別性によって定義される。
  • 値オブジェクト: 事物の特性を記述するオブジェクトである。特に識別する情報はなく、通例、読み出し専用のオブジェクトであり、Flyweight パターンを用いて共有できる。
  • サービス: 操作がオブジェクトに属さない場合に、問題の自然な解決策として、操作をサービスとして実現することができる。サービスの概念は、GRASPにおいて"純粋人工物"と呼ばれるものである。
  • リポジトリ:ドメインオブジェクトを取得するメソッドは、記憶域の実装を簡単に切り替えられるようにするため、専門のリポジトリオブジェクトに処理を委譲するべきである。
  • ファクトリー : ドメインオブジェクトを生成するメソッドは、実装を簡単に切り替えられるようにするため、専門のファクトリーオブジェクトに処理を委譲するべきである。

Test-Driven Development(テスト駆動開発)

プログラムを作成する際に、プログラムよりも先にテストコードを作成し、テストコードが正常に終了するようにプログラムを作成し、その後にプログラムを修正していく開発手法をテスト駆動開発と言います。英語の頭文字を取って、TDDとも呼ばれます。

テスト駆動開発のメリット

テスト駆動開発では実装よりも前にテストコードを書くため、実装前に仕様を設計してテストコードとして具体的に定義できます。テストコードで明確な仕様を定義できるため、実装漏れを防ぐのに役立ちます。また、一般的なテスト駆動開発ではモジュール単位でテストコードを作成するため、疎結合なモジュール設計になりやすいです。

テスト駆動開発のデメリット

プロトタイピングのような開発の場合、機能の開発後に大幅な仕様変更が発生することがあります。仕様が大きく変わる場合作成したテストコードがすぐに使えなくなるため、テスト駆動開発には向いていません。また、テストコードを実行する環境をテストの度にビルドするような設計の場合、規模の大きいモノリシックなシステムではビルドに数時間以上かかることがあり、修正の度に数時間の待ち時間が発生し効率が悪くなる場合もあります。

まとめ

この記事では最低限知っておくべき設計、開発の原則を紹介しました。

これらの原則を意識して設計・開発することで、継続的に改善していくことが可能なWEBサイト・WEBシステムを開発しやすくなります。

【Google Chrome】デベロッパーツールの使い方(基本編)

HTML, CSS, JavaScriptをコーディングする際に、ちょっとしたケアレスミスで意図したように表示されなかったり実行されなかったりすることがあります。

そのような場合にHTML, CSS, JavaScriptだけを読んで問題を解決するのは少し効率が悪いかもしれません。

コーディングした内容が実際にどのようにブラウザで処理されるか確認をするためにデベロッパーツールを利用することで、効率よくコーディングを進めることができます。

この記事ではGoogle Chromeのデベロッパーツールの基本的な使い方について紹介します。

各機能の詳細は量が多いので別の記事で紹介しています。

  1. 【Google Chrome】デベロッパーツールの使い方(デバイスツールバー編)
  2. 【Google Chrome】デベロッパーツールの使い方(Elements編)
  3. 【Google Chrome】デベロッパーツールの使い方(Console編)
  4. 【Google Chrome】デベロッパーツールの使い方(Sources編)
  5. 【Google Chrome】デベロッパーツールの使い方(Network編)
  6. 【Google Chrome】デベロッパーツールの使い方(Performance編)
  7. 【Google Chrome】デベロッパーツールの使い方(Memory編)
  8. 【Google Chrome】デベロッパーツールの使い方(Application編)
  9. 【Google Chrome】デベロッパーツールの使い方(Security編)
  10. 【Google Chrome】デベロッパーツールの使い方(Lighthouse編)
  11. 【Google Chrome】デベロッパーツールの使い方(Settings編)

デベロッパーツールとは

デベロッパーツールはブラウザに標準で付属している、開発者向けのデバッグツールです。

HTML, CSSの確認やDOM構造の確認、JavaScriptのデバッグからWEBページの改善点の提案まで、様々な機能が含まれています。

この記事ではGoogle Chromeのデベロッパーツールを紹介しますが、ほとんどの機能は他のブラウザのデベロッパーツールでも利用できます。

デベロッパーツールを使うには

デベロッパーツールは、ブラウザのメニューから[表示 > 開発 / 管理 > デベロッパーツール]を選択するか、次のショートカットキーで表示できます。

OS ショートカットキー
Windows10 F12
macOS ⌘ + ⌥ + I

デベロッパーツールのレイアウト

f:id:four-winds:20210131203526p:plain

①要素を選択する

Elementsタブでフォーカスする要素を選択できます。

②デバイスツールバーを表示する

後述のデバイスツールバーを表示できます。

③タブ

クリックすると表示するタブを切り替えられます。

④エラーと警告

Consoleに表示されるエラーと警告の件数が表示されます。

クリックするとConsoleタブが表示されます。

⑤設定

デベロッパーツールの設定を変更できます。

⑥デベロッパーツールメニュー

クリックすると次のようなメニューが表示されます。

f:id:four-winds:20210131204447p:plain

Dock side

クリックするとデベロッパーツールの表示位置を変更できます。

左から順に、別ウィンドウ・左側・下・右側に表示されます。

Show console drawer

クリックすると以下のようにコンテンツエリア下部にConsoleドロワーが表示されます。

f:id:four-winds:20210131204831p:plain

機能はConsoleタブと同等です。

Search

読み込んだリソースの中から指定のキーワードで検索を実行できます。

Run command

様々なコマンドを実行できます。

macOSでは[⌘ + ⇧ + P]Windows10では[Ctrl + Shift + P]で実行することもでき、コマンドでChromeの設定などを変更できるので左記のショートカットキーと組み合わせて利用することで操作を効率化できます。

Open file

読み込んだリソースの中から指定のキーワードを含むファイルをSourcesタブに表示できます。

More tools

その他のツールが表示されます。

f:id:four-winds:20210131205813p:plain

⑦デベロッパーツールを閉じる

クリックするとデベロッパーツールを閉じます。

⑧コンテンツエリア

選択したタブの内容が表示されるエリアです。

デバイスツールバー

【Google Chrome】デベロッパーツールの使い方(デバイスツールバー編)で紹介しています。

Elements

【Google Chrome】デベロッパーツールの使い方(Elements編)で紹介しています。

Console

【Google Chrome】デベロッパーツールの使い方(Console編)で紹介しています。

Sources

【Google Chrome】デベロッパーツールの使い方(Sources編)で紹介しています。

Network

【Google Chrome】デベロッパーツールの使い方(Network編)で紹介しています。

Performance

【Google Chrome】デベロッパーツールの使い方(Performance編)で紹介しています。

Memory

【Google Chrome】デベロッパーツールの使い方(Memory編)で紹介しています。

Application

【Google Chrome】デベロッパーツールの使い方(Application編)で紹介しています。

Security

【Google Chrome】デベロッパーツールの使い方(Security編)で紹介しています。

Lighthouse

【Google Chrome】デベロッパーツールの使い方(Lighthouse編)で紹介しています。

Settings

【Google Chrome】デベロッパーツールの使い方(Settings編)で紹介しています。

さいごに

デベロッパーツールは非常に多機能ですべてを使いこなすには時間をかけて学ぶ必要があるかもしれません。

作業内容によって利用する機能は異なりますが、HTM, CSS, JavaScriptのコーディングをする場合次の機能をよく利用します。

  • デバイスツールバー
  • Elements
  • Console
  • Sources
  • Network
  • Lighthouse

こちらの機能だけでも使えるようになると、効率よくコーディングを進めることができる思うのでぜひお試しください。