このエントリーをはてなブックマークに追加

esaba(餌場)とは

https://github.com/ttskch/esaba

esa.io上の記事データをホストするためのPHP製のWebアプリケーションです。/post/{記事ID}というURLでesa.io上の任意の記事を公開できます。

社内で必要に迫られて作りましたが、割と一般的にニーズがありそうなツールなので簡単にご紹介したいと思います。

esa上のこの記事が esabaではこう表示される(デフォルトCSSでは)

esa標準の「Share Post」との違い

esaにはShare Postという機能があり、記事ごとに外部公開用のURLを発行することができます。これと比較したesabaのアドバンテージはざっと以下のとおりです。

  • 記事の表示に独自のcss/jsを使うことができる(scss/webpack対応)
  • カテゴリやタグごとに細かく公開/非公開を設定できる
  • 社内のみに公開したい場合などに便利(オンプレなのでWebサーバーレベルでアクセス制限可能)
  • 記事中に他の記事へのリンクがある場合はesabaのURLに変換して出力してくれるので、記事本体のURLと公開用のURLを別々に管理する必要がない

なぜ作ったのか

弊社では開発部という部署でのみesaを使っていて、現状は社内の全員が閲覧できるドキュメント管理ツールがありません。 全社向けのドキュメントらしいドキュメントはそんなに数がなかったこともあり、Googleドライブにpdfを置いておくぐらいの運用で騙し騙しやっていましたが、最近になっていよいよ不便さが顕在化してきたため、何とかしようと思い立ちました。

全社向けのドキュメントを書いたりメンテしたりするのはせいぜい数人なので、閲覧させるためだけに全社員にesaアカウントを発行するのはあまり経済的ではありませんでした。そこで、esaの記事データをAPIで取得してそのままホストするだけのサービスがあれば便利なのではと考えた次第です。

インストール方法

事前にesa上でPersonal access tokenを発行しておく必要があります。

esabaのインストールにはComposer(PHPのパッケージ管理ツール)とnpmが必要になります。 また、PHPのバージョンは5.6以上が必要です。

$ composer create-project ttskch/esaba   # npm installも自動で走ります
$ cd esaba
$ cp config/config.secret.php{.placeholder,}
$ vi config/config.secret.php   # esaのアクセストークンなどgitignoredな設定を書き込んでください

使い方

本番環境

/path/to/esaba/webをDocumentRootとして、PHP5.6以上が動作するWebサーバーでホストしてください。

開発環境

PHPのビルトインサーバーを使ってローカルサーバーを起動するには、以下のようにします。

$ COMPOSER_PROCESS_TIMEOUT=0 composer run

起動したら、ブラウザで http://localhost:8888/index_dev.php/post/:post_number へアクセスすれば記事が見られます。

各種設定

config/config.php で色々な設定が可能です。

カテゴリやタグによるアクセス制限

$app['config.esa.public']$app['config.esa.private'] にそれぞれカテゴリ名やタグ名をセットすることで、柔軟なアクセス制限が可能です。

例えば以下のように設定すると、

// config/config.php

$app['config.esa.public'] = [
    'categories' => [
        '公開用/公開用1',
        '公開用/公開用2',
    ],
    'tags' => [
        '公開',
    ],
];

$app['config.esa.private'] = [
    'categories' => [
        '公開用/公開用1/一旦保留中',
        '公開用/公開用2/一旦保留中',
    ],
    'tags' => [
        '非公開',
    ],
];
  • 公開用/公開用1カテゴリ配下、公開用/公開用2カテゴリ配下が公開対象となる
  • それとは別に公開タグが付いている記事も公開対象となる
  • ただし、公開用/公開用1/一旦保留中カテゴリ配下、公開用/公開用2/一旦保留中カテゴリ配下は非公開となる
  • また、非公開タグが付いている記事は他の全ての設定に優先して非公開となる

という状態になります。

HTMLの置換

記事中に他の記事へのリンクがあれば、esabaでその記事を閲覧するためのURLに自動で置き換えられます。

また、それとは別に$app['config.esa.html_replacements']にて任意の置換ルールを設定しておくこともできます。 例えば、すべてのtarget="_blank"を削除したい場合は、以下のように設定します。

// config/config.php

$app['config.esa.html_replacements'] = [
    '/target=(\'|")_blank\1/' => '',
];

置換ルールのパターン部分はPerl互換の正規表現です。詳しくはこちらをご参照いただくか、お近くのPHPerまでお尋ねください。

カテゴリ/タグに応じたcss/jsの切り替え

$app['config.esa.asset']でカテゴリやタグごとに使用したいcss/jsファイルを設定できます。

// config/config.php

$app['config.esa.asset'] = [
    '公開用/Wordっぽい文書' => [
        'css' => 'css/post/word-like.css',
        'js' => 'js/post/word-like.js',
    ],
    '#Wordっぽい文書' => [
        'css' => 'css/post/word-like.css',
        'js' => 'js/post/word-like.js',
    ],
];

上記のように設定した上で、./web/css/post/word-like.cssおよび./web/js/post/word-like.jsを設置すれば、

  • 公開用/Wordっぽい文書カテゴリ配下の記事
  • カテゴリに関わらずWordっぽい文書タグが付いている記事

にはword-like.css word-like.js が適用されます。

注:複数の条件にマッチする記事の扱い

  • ある記事が複数の条件にマッチした場合、「タグベースの条件」が「カテゴリベースの条件」よりも優先されます
  • ある記事が複数の「カテゴリベースの条件」にマッチした場合、より深いカテゴリを指定している条件が優先されます
  • ある記事が複数の「タグベースの条件」にマッチした場合、保証された優先順位はなく、いずれか1つの条件が適用されます

webpackによる独自アセットのビルド

esabaはscss/webpackに対応しています。独自アセットも、設定ファイルの変更なしでwebpackのビルド対象にすることができます。

./assets/post/*.(scss|js)が自動でビルド対象になり、以下のように./web/(css|js)/post/*.(css|js)として配置されます。

$ vi assets/scss/post/word-like.scss   # scssで書く
$ npm run build
  :
$ tree web/css/post
web/css/post
├── default.css
└── word-like.css   # cssがビルドされてる

0 directories, 2 files

Webhookを使ったキャッシュの自動更新

esabaはesaから取得した記事データをキャッシュしますが、esa Generic Webhookを使うことで、esa上で記事が作成/更新されたときに、esaba側のキャッシュを自動で更新させることができます。(ただし、WIP→WIPの更新についてはWebhookが飛ばないため自動更新されません)

// config/config.secret.php

$app['config.esa.webhook_secret'] = 'Secret here';

/webhook/へのアクセスの解放

もしWebサーバーレベルでのアクセス制限を設定している場合、/webhook/へのアクセスはesa.ioからのwebhookリクエストを受け取るために解放しておく必要があります。

例えば、Apache 2.4の場合は以下のような設定が必要になります。

<Location />
    Require ip xxx.xxx.xxx.xxx
</Location>

<LocationMatch ^/(index.php|webhook/?)$>
    Require all granted
</LocationMatch>

おわりに

弊社ではすでに社内でesabaを運用しており、散らかっていたドキュメントをesaに集約することに成功してハッピーな感じになっています :sparkles:

応用的な用途も色々と考えられそうなので、ぜひ気軽にIssueやPRをいただけると嬉しいです!

https://github.com/ttskch/esaba


このエントリーをはてなブックマークに追加

カルテットの開発部には、10月から新メンバーが加わりました。新メンバーには、将来メインのプロダクト開発にガッツリと参加してもらうことを期待しており、それに向けた教育の一環として、設計力を伸ばしていくための土台づくりを行っています。この記事では、私が現在行っている新人プログラマー向けの教育を、どのような考え方で行っているのかを紹介します。

前提

今回対象としている新人プログラマーのスキルは以下のようなレベルです。

- Webサイト制作的な案件を一人でこなせる
- オブジェクト指向プログラミングについて、書籍などを読み一定以上の知識を持ってはいるが、実務において深く活用したり、他人と意見交換した経験はない

この記事で扱っている「設計」は、プログラマーが行うコードの設計、およびコード群の組み合わせ方の設計といったあたりまでを指しています。

また、この記事では、設計の中身(どのような設計が良いのか等)の教育についてはほとんど触れていません。

設計は学びづらい

設計というのは、プログラマーのスキルの中でも学びづらいものの筆頭です。多くの方が、設計について学ぶのに、何かと苦労されているかと思います。そのような苦労からか、いつしか「設計力を身につけるには、とにかく現場での場数が必要」と考えるようになってしまっていないでしょうか。私も過去に、そんな考えにとらわれていた時期がありました。ところがある時、見習いプログラマーから次のように質問され、ハッとします。

「現場で場数を踏みさえすれば、必ず一人前の設計者になれるのでしょうか?」

あなたがこの見習いプログラマーの教育担当だったら、どう答えますか? 「バカヤロー! そんな事を聞くのは10年早いわっ!」などと怒鳴りつけるわけにはいきません。一人前の設計者らしい鋭い洞察力が滲み出る回答をしたいところです。もちろん、質問への回答は「NO」です。ただ場数を踏めばよいだけなら、それはそれで大変ではありますが、学ぶこと自体に苦労はしません。つまり、単に「場数を踏む」ということ以外に、必要なことがあるのです。それは、1回1回の場数を踏んでいく際の「場数の踏み方」なのです。場数の上手な踏み方を身につけていないと、どれだけ場数を踏んでも全く成長しません。成長したとしても、とてもゆっくりとしたものになってしまうでしょう。しかし、場数の踏み方が上手な人は、少ない場数でも確実に成長していけます。

プログラマーの日々のコーディングの中で、変数やクラスの命名、きれいなロジックへの修正といった、小さな設計行為は多数行っているものです。しかし、判断に数日迷うような設計、様々なことを調査して比較しなければいけないような設計、一見太刀打ちできなさそうな複雑な問題に対する設計といった大きなものもあります。このような設計こそ設計力が試されるので、設計力を伸ばすチャンスでもあります。しかし、大きな設計問題は頻繁に出てくるわけではありません。したがって、そのような問題から学んで成長するには、少ない場数で確実に学びとる力が大切なのです。

また、プログラムの設計という活動では、フィードバックまでのタイムラグが長くなりがちです。このことも設計の学びづらさに関係していると私は考えています。何かを学んで身につけ磨きをかけていくには、自分の行為がどのような結果をもたらしたのかというフィードバックを受けて、次の自分の行為に改善を加えていくというサイクルが欠かせません。しかしプログラムの開発では、何か設計を行っても開発しただけで終わってしまったり、または、数ヶ月後の機能追加や仕様変更などといったタイミングで、ようやく過去の設計と向き合うことになるといった形が普通です。自分の設計に対して評価するのは、設計を行ってから随分と時間が経った後のことになってしまうのです。このようなチャンスが幸運にも巡ってきた時に、確実に学びを得る力が必要です。

では、少ない場数でも確実に学びを得るための、土台となるスキルは、具体的には何なのでしょうか。

設計力を伸ばすための土台となるスキル

設計力を伸ばすための土台となるスキルは、「論理的思考力」です。これは、たとえば以下のような力のことです。

  • 物事を、何らかの観点で分類・整理する力
  • 論理的に筋道を整えて主張を述べる力(論証力)
  • とりうる立場を複数検討し、それぞれの立場から見る力(批判的思考力)

論理的思考力は、プログラマーの仕事において、与えられた問題に対する分析や解決方法の構成に役立つのはもちろんです。しかし、今回注目したいのは、それとは少し異なる側面です。論理的思考力があると、問題の分析や解決方法の構成に至る道筋が、とてもはっきりとしたものになります。そうすると、時を経てその分析や解決方法の結果に対するフィードバックを得た際、最初に立てた道筋のどのポイントが結果に影響を及ぼしていたのかを把握することができます。その結果、フィードバックを的確に改善につなげることができるのと同時に、フィードバックから確実に学びを得ることもできるのです。

ただし、論理的思考力だけでは車の片輪でしかなく、プログラムの設計力の土台として有効に活用するためには、もう片方の車輪が必要です。それは、技術面の知識です。なぜでしょうか。どれだけ論理的思考力が鋭くても、技術面の知識が乏しければ、精緻な技術的検討・論証が行なえないのです。プログラム設計一般に関する知識、利用するプログラミング言語の言語機能に関する知識が伴うことで初めて、眼の前にあるプログラムコードの設計の機微が語りうるものとなるからです。

したがって、プログラムのコードを題材として、論理的思考力を養うようなトレーニング というのが、私が新人向けの設計力の土台作りとして行っていることになります。例をいくつか紹介します。

トレーニング内容の例

以下のトレーニングは、実際の業務のプロジェクトではなく、練習用のプログラミング問題を解くことを通して実施しています。そこでは、形式的なゴールは「問題を解くコードを作成する」ことですが、ゴールへ向う過程で、論理的思考力を養うトレーニングを同時並行で行います。そのために、問題を解くコードを一気に完成させることはせず、TDDのようなスタイルで、問題をいくつかの部分に分割(これも新人プログラマー側が考える)し、Issueやプルリクエストで事細かにやり取りをしながら、少しずつ進めていきます。

名前付けの理由を説明するトレーニング

このトレーニングでは、設計案や実際にプルリクエストで出されたコードに登場するクラス名、変数名、メソッド名、テストケースの名前といったすべての要素に対して、なぜそれを選んだのかという理由を求めます。また、プログラムにおいて重要な役割を担うクラスやメソッドについては、他の候補がなかったか、他の候補と比較して良いと考える理由も求めます。

また、コードに使ったクラス名や変数名を使って「何をやっているのかを説明する」ということも行います。

このトレーニングを通じて、「問題を捉えて、それをコードに表現する」というプログラマーが自然に行っている活動に自覚的になり、「頭で認識した問題の構造」と「表現されたコード」との間のギャップに敏感になるよう促していきます。

仕様変更対応トレーニング

このトレーニングでは、新人向けに出しているプログラミング問題を、段階的に仕様変更していきます。例えば次のような仕様変更を行います。

  • 入力値の与えられ方の別仕様
  • 結果の表示の仕方の別仕様
  • 問題の解き方における別ルール
  • 大きなデータ量への対応

ポイントは、仕様変更によって、最初に実装したコードの設計に対して強制的にフィードバックが入ることです。フィードバックを頼りに、最初の設計のどの部分が良い働きをしているのか、逆にどの部分が良くない働きをしているのかを考えます。といっても、新人プログラマーにいきなりそのような事を見抜くことはできません。この段階の場合は、教育担当者が新設計の案の作成を誘導しながら行っていき、上手くいく形の設計に仕上げて行きます。それが出来上がった後で、変更の前後を見比べて、仕様変更のどの部分が、コード変更のどの部分と対応しているのか、ということを後追いで検討します。

このトレーニングを通じて、自分のコード設計に対する批判的な態度を養います。

おわりに

いかがでしたでしょうか。

論理的思考力のような基礎スキルを養うトレーニングは、即効性のあるものではありません。しかし、年単位のような長い時間軸に目を移した時、人の学びを加速する起爆剤といってもよいほどの効果があると思います。この記事に書いた活動は、実際にはまだ始めたばかりで、どのように実を結ぶのかは分かりませんが、新人の成長などを通してフィードバックを得て、この土台作りのコンセプト自体も磨きをかけていきたいところです。

設計について学んでいきたい若手エンジニアの方、そして新人プログラマー向けの教育に関わっている方の参考になれば幸いです。


カルテット開発部では、設計力を土台から鍛えたい仲間を募集しています!


このエントリーをはてなブックマークに追加

はじめに

カルテットの開発部内でなんとなく「シェルに詳しいおじさん」というイメージを持たれている永井です。(本当は特に詳しくないです)
最近ふと思い立ってGNU Makeコマンド(以下Makeコマンド)を使い始めたんですが、思いのほか使い心地が良いので紹介したいと思います。

Makeコマンドとは

何かソースコードをダウンロードしてきて、インストールする時に入力する

make && make install

みたいなコマンドのことです。

皆さんも一度は入力した覚えがあるんじゃないでしょうか?
最近はソースコードからmakeコマンドを実行してアプリケーションをコンパイルするということは少なくなりましたが、最新のソースコードを利用したい時や自分でパッチを当てて再コンパイルしたい時など、まだまだ使う場面はあるかと思います。

タスクランナーとしてのMakeコマンド

makeコマンドを使ったことはあっても、Makefileを自分で作成したことがある人となると極端に少ないと思います。
自分も「なんだかMakeコマンド周辺のテクノロジーは古臭くて小難しいなあ」というイメージを持っていました。

タスクランナーとしてよく使われているツールと言えば、GruntGulpといったところが頭に浮かびますでしょうか。
またnpm-scriptsComposerscriptsなど、新たにツールをインストールしなくてもパッケージ管理ツールに付随する機能で済んでしまうことも少なくありません。

が、実際に使い始めてみると結構使いところがあるなと感じています。
個人的に良いなと感じたところを挙げていきたいと思います。

ポータビリティが高い

ここではとても狭義な意味でのポータビリティを指していまして、macOSやUnix系のOSならば、余程珍しいものでなければ動作するという意味でのポータビリティです。
一応Windowsでも動作するような記事を見かけましたが、実用に耐えられるかは不明です・・・。

またnpm-scriptsはNode環境が必要ですし、ComposerはPHP環境が必要です。
それぞれの環境にはバージョンがありますし、開発しているアプリケーションが特定バージョンに依存していて干渉してしまうということも少なからずあるのではないでしょうか?
インフラ部門と開発部門が分かれていたりすると、この辺りのレギュレーションがシビアだったりすることもあるかと思います。(弊社はこの限りではありません)

また特にシェルを指定しなければ、Makefileの中身はBource Shellで書くことになるかと思います。
もしそのままBource Shellを利用することになればポータビリティを高めることに一役買うことになるかと思います。

個人的に開発環境で行いたいタスクを書く場所としての利用

私が「 普段開発しているプロジェクトがMakefileを利用していなかった」というのも大きいのですが、複数人で開発している場合にcomposer.jsonpackage.jsonに書くべきかどうか悩むようなタスクが存在します。
「ローカルである程度運用してみて、有用だと思われた場合プロジェクト全体に影響するファイルへ追加する」ということは良くやっているので、そういったお試しタスクを書く場所として重宝しています。

従うべきルールがある

make <ターゲット>

という感じでコマンドを実行するのですが、このターゲットの部分は任意に作成することが出来ます。
マニュアルには、以下のターゲットを持つようにしましょうというルールが明記されています。

  • all
  • install
  • install-html
  • install-dvi
  • install-pdf
  • install-ps
  • uninstall
  • install-strip
  • clean
  • distclean
  • mostlyclean
  • maintainer-clean
  • TAGS
  • info
  • dvi
  • html
  • pdf
  • ps
  • dist
  • check
  • installcheck
  • installdirs

ターゲット名だけでなんとなく意味のわかるものから、使ったことがなかったりピンとこないものまで幾つかあるかもしれません。
個人で利用する時にこれらのルールに従うとなるとかなり窮屈に感じますし、不特定多数に配布するものでなければ特に従う必要はないかなと思っています。
しかし、こういったルールがあることでターゲット名を決める時の参考にすることが出来るので、個人的には非常に助かります。
もしMakefileを他人に配布することになったとしても、これらのルールに従っているターゲット名であれば、タスク内容を推測しやすくなるのではないでしょうか。

ファイルが一つにまとめられる

Makeコマンドを利用する前までは、細かいタスク毎にシェルスクリプトを作成していました。
今でも入り組んだことをやろうとする時はシェルスクリプトを別途用意しますが、数行で済むような簡単なコマンドの羅列であればMakefileで事足ります。

また、コメントも書くことが出来るので、簡易的なドキュメントとしてもファイルが一つなのは助かります。

実際にどんなところで使っているか

まだ使い始めて1ヶ月程度ですが、こんなところで使い始めています。

  • git-pull後のSymfonyプロジェクトのビルド
  • リモートホストに保存されている圧縮されたDBデータのダンプファイルのローカルPCへのリストア
  • dotfilesのファイル配置とファイル削除

dotfilesのMakeifileサンプル

実際に利用しているdotfilesのMakefileを晒してみます。

TARGETS := \
"gitconfig" \
"gitignore" \
"git-template" \
"git-commit-message" \
"tmux" \
"tmux.conf" \
"vim" \
"vimrc" \
"zshrc"

.PHONY: all
all: ## submodule update init
	git submodule update --init --recursive

.PHONY: install
install: ## create target's symlink in home directory
	@for TARGET in $(TARGETS); do \
		if [ -e "$(HOME)/.$$TARGET" ]; then \
			echo "already exists $$TARGET"; \
		else \
			ln -s $(CURDIR)/$$TARGET $(HOME)/.$$TARGET; \
			echo "created $$TARGET"; \
		fi \
	done

.PHONY: uninstall
uninstall: ## delete created symlink
	@for TARGET in $(TARGETS); do \
		if [ -h "$(HOME)/.$$TARGET" ]; then \
			rm $(HOME)/.$$TARGET; \
			echo "deleted .$$TARGET"; \
		elif [ -e "$(HOME)/.$$TARGET" ]; then \
			echo "no symlink $$TARGET"; \
		else \
			echo "no exists $$TARGET"; \
		fi \
	done

.PHONY: help
help:
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

make allでgit-submoduleのアップデートを行っています。
ちなみにgit-submoduleは主にvimのPluginの管理に利用しています。
make installでホームディレクトリ直下にシンボリックリンクを作成し、make uninstallで作成したシンボリックリンクを削除します。
make helpで各ターゲットのコメント表示するようにしています。
実行するとこんな感じになります。

$ make help
all                            submodule update init
install                        create target's symlink in home directory
uninstall                      delete created symlink

以下のサイトを参考にさせて頂きました。
参考: Makefileを自己文書化する | プログラミング | POSTD

必要な情報が一つのMakefileに簡潔にまとめられ、ターゲット名も基本ルールにある程度沿ったもので作成できたので、個人的には見通しが良くなったなと感じています。

おわりに

Makeコマンドをタスクランナーとして利用する的な記事は、以前から存在することは知っていました。
いくつかの記事を見ても、その時はGruntGulpを覚えるのを面倒に感じる人達が

「それMakeで出来るよ」

って言っているだけかと思っていました。
しかし実際に使ってみるとこれはこれで良いものだなと感じると共に、根強いファンがいるのも頷けます。

また、今回は説明を省きましたが、

のような、本来のコンパイルツールとしての強力な機能も多数持ち合わせています。
自分はまだまだそれらを有効活用するところまで出来てませんが、Makeコマンドは今後も長く使い続けられるんじゃないかと思いますので、徐々に覚えていけたらなと思います。