A Day In The Boy's Life -17ページ目

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

自分たちでシステムを作る場合、何らかのツテがあるベンダーに入ってもらって提案してもらったり、または過去の導入実績からその新しい製品を見積もってもらったりといった感じでこちらが導入に際して主導権を握りますが、中にはそうではない厄介なものがあったりします。


それは、自社と取引のあるお客さんから「そっちの製品/サービスを買ってんだからうちのも買ってよ」という感じで持ちかけられたものたちです。

悪い例では、自分たちで構成を決め、見積もりを取り、設計をしている段階で営業部門とかから商談のネタとするために他の製品の導入を強引に持ち込んできたりもします。



使い道の無いものの使い道


こういった話の面倒なところは、販売元が取引先であるために無下に断れないことや、そもそも話が来た頃には勝手に導入することが決定されているような状態で来ることです。

しかも、自社のサービスのライン側もそういったものが必要で買うわけではないので使い道も無く、システム部門で使ってよということで話が来るわけですけど、当然こちらとしても使い道なんて無いわけですよ。


いや、使い道はあることはあるかもしれませんけど、そもそもシステム部門としても年間の大きなシステム投資計画や施策というものは決まっていて動いているわけですから、例えそれが今あるシステム部門の課題を解決してくれるものだとしても、当初の予定に無いものをやるには体制面や運用面や関連するシステムやユーザーへの影響などを考慮しなくてはならないわけで、言ってしまえば余計な仕事が増えるわけです。


まだ、これが遠い将来でも「それは課題だからいつかやらないとね」という認識のものであれば計画を変更してやりましょうということで落ち着けられるかもしれませんけど、そうではないケースも多々あります。

例えば、


・ その製品と同じ機能を持つものを去年導入したばかり(課題は解決済み)

・ 社内のデファクトスタンダードなもの(標準で使っているソフトウェアとか)を一変させなくてはならない

・ そもそもその製品が解決する課題が社内には見当たらない

・ オーバースペック過ぎる(超巨大なアプライアンス製品とか)

・ 機能がしょぼすぎる(使いものにならない)


といった感じのもの。

こういったものの末路というのは「とりあえず言われたから買うだけ買う」という状態になり、遊休資産として倉庫やサーバールームの奥深くに眠らせることになったりします。

巨大なアプライアンス製品を導入しなくてはならないときは、サーバールームでの耐荷重がオーバーしていたため(ただ単にそこに置くためだけに)床下の補強工事をする羽目になったり、塔が立ったように場所を占有して誰しもが作業に邪魔と思うような結果になったこともあります。

あと、電気代がもったいないから火を入れることすらしないとか、「○○のシステム作るのにサーバーが足りないんだよね」という話が出たときに「あのアプライアンス使えばいいじゃん」と揶揄されるだけの品になったりします。


まぁ、もうひたすら遊休資産として保管しておき誰もが早く償却しないかなとか考えるようになったりするわけです。

置いておくだけでいいなら別にいいのでは?とか思われるかもしれませんけど、現物としてある限りその資産を管理しないといけなかったり、アプライアンスだけでなくついでにその中のソフトウェアやH/Wに関する保守契約とか結ばされたりするので、その契約管理とか更新処理とか結構手間はかかってくるので早く消えて欲しいと願わざるを得なくなります。


また、ソフトウェアなら邪魔にならなくていいというわけでもなく、そういうのって導入のコンサルとセットになってたりして、そうなった場合は何らかの形で導入して使う算段を立てないといけないのでもっと面倒なことになったりします。

使い道が無いものに無理やり口実をつけないといけなくなったり、運用の手間が増えたり、導入までにやる気が全く沸いてこない打ち合わせに何回も付き合わないといけなかったり。

今の環境を変えることなく低コスト・短納期で導入が可能ですとかいわれても、作るときについでに入れろと言われるならまだしも実際には既存のシステムとの連携や組み込みがネックになって色々と構成を捻じ曲げないといけないようなことになったりして、手間だけでなくほかのところの弊害が幾つも出てきたりするわけです。


正直、買った体にしてお金だけ上げるからそっとしておいて見たいな事すら思えるレベルなんですが、政治レイヤーで勝手に決められることで振り回されるのは本当に勘弁して欲しいと思う今日この頃です。





自分のところではプロジェクト管理としてRedmineを使って、各自担当するタスクや不具合、課題、要望などを管理するようにしているのですが、こうした開発スタイルをとっていく中で当然よい側面と悪い側面が出てきたりします。

簡単に言ってしまえば、タスクが明確化される一方で、与えられたタスクだけをやればよいという風に受け取られてしまうということがあるといった点です。


当然、それぞれのエンジニアの働き方にも大きく依存する問題なのでこうしたツールや開発スタイルというのは良いようにも悪いようにも受け取られたりします。



機械的な形式と機械的な仕事


自分のところではチケット駆動開発と呼ばれるほど厳密なルールを作ってやっているわけではありませんが、タスクや課題、バグからユーザーからの要望などなど雑多なものを拾い上げて適当な開発・改修の粒度に分けてチケットを管理していたりします。

別にこれはRedmineというBTSツールに頼らずとも、規模が小さなチームやプロジェクトであればExcelなんかで管理するというものでも全然かまわないんでしょうけど、要するに何らかのやらないといけない仕事がデータ化され保存されているというわけです。


これにより仕事の見える化が進むわけですけど、それにより最初に書いたような弊害が生まれたりもします。

担当者が決められ割り当てられるというのは、自分がやらないといけないタスクというものがはっきりしますので、いってしまえばそれをこなしていけばよいという機械的な仕事の形式にもなります

これが、そのタスクだけを自分が担当すればよいという思い込みにもつながったりすると最悪で、そっちは担当ではないから関係ないという思い込みとか、関連するタスクの状況を確認していかなかったために後々トラブルが起きたりとかします。


ここで積極的なエンジニアは他のチケットの状況を確認してコメントしたり、担当者が付いていないチケットでも進んで担当者になっていくというようなことが期待できるのですが、まぁこういう自主的に動いてくれるエンジニアは稀ではないでしょうか(仕事が増えるわけですから心理的には当たり前かもしれませんけど)。

エンジニアの中には自分の力量とタスクの難易度を鑑みて打算的に動く人もいますから、このチケットの難易度は高いから止めておこうとか、このモジュールはAさんが過去に対応していたから自分が受け取るのはやめておこう見たいな事にもなって特定のチケットが放置されたり、システムの分野やカテゴリによっては担当者が偏って負担が大きくなったりもします。


これは、その一部のエンジニアしか積極的にチケット管理ツールを使わないということにもなってきて、本来タスクの見える化や権限のフラット化やチームの活性化というものに結びつかなかったりもします。

個人的には、チケットの総量や担当者の動きというものが全て把握できたりもするので、誰が仕事をしていて誰がしていないか(または積極的ではないのか)ということがわかったりするので、結構残酷なツールだなと思ったりもします。



組織における向き不向き


チーム内でやらないといけないタスクというのは、誰がと言うわけではなく各々が見つけて提言していくのが理想的です。

バグにしろ、ユーザーから言われた改修の要望にしろ、それが特定のマネージャーを通らないとあがってこないという状況ではそこがボトルネックになりかねません。


先ほど書いたように積極的なエンジニアがどれだけチーム内にいるかという話にもなりますが、Wikipediaの記事を書く人と読む人のどちらが多いのかを比較すれば明らかですけど、かなり多く見積もって1割のエンジニアが積極的に動いてくれたとしても、100名のチームならそれなりのタスクの流動性を持たせられるでしょうが10名以下の小規模なチームとかになると1名とかになるのでタスクが自主的に動いていく数がかなり低くなってきます。

タスクが活発に動いている状況はチームが活発に動いている状況でもあるので、そのような状況に無い場合はそもそもその開発スタイルがチームにあっていないということにもなります。


別にこれはコミュニケーションスキルに優れたエンジニアがいるかいないかという話ではなく、BTSを使った場合のコミュニケーション手段は基本テキストになるので、バグの報告とかシステムの仕様をWikiにまとめるといったことは、話すのが苦手といったエンジニアの方が返って向いてたりもします。

逆に話し好きなエンジニアの方が打ち合わせで問題点や方針を決めたりして、それがチケットにあがってこないという状況にもなったりするのでこのスタイルに向いてないかもしれません。


また、チケット(タスク)の総量が減ってきたりするとエンジニアが仕事を持て余すようにもなってきたりします。

つまりは、受身なエンジニアが多い状況ではそのチームやプロジェクトのマネージャーがチケット(タスク)を作り出して割り当てていくということをしていかないと全然仕事が進んでいかないという状況に陥ります。

このスタイルを割り切ってしまえば、マネージャーの負担が大きくなるにしろ機械的にタスクをこなすことでチームを回す事はできるかもしれませんが、それに慣れてしまった場合に何も考えが及ばないようなエンジニアが育ってしまったりして怖いなとも思うわけです。


何れにせよ、数多ある開発スタイルというものは、マネジメントの観点だけで良し悪しが決まるものでもなく、そもそも組織やチームの文化やそこにいるエンジニアの能力や人柄なんかにも左右されるので、無理に当てはめてもすぐに効果が出るものでもなく、長い時間をかけて特性に合うエンジニアを育てていくということも大事なんだと思います。





標準のLaravelのディレクトリ構成でも特に問題なくアプリケーションの構築は行えるわけですが、このフレームワーク上で多数のシステムを動かすとなった場合、ディレクトリの構成をサブシステムごとに分離できたほうがよい場合があります。

例えば、システム数が多くなるとコントローラの数が増えてくるので(設定ファイルやViewファイルなども同様ですが)どのコントローラが何の処理をしているのかわかりづらくなってきたりで、あるシステムで構成するファイル群がまとまっていた方がターゲットが明確になったり、システムを削除する際にもそれ以下をごっそり消せばいいといったことができたりとかでメリットがあったりもします。


Laravelではディレクトリ構成をある程度自由にカスタマイズできるのでこういったことも簡単にできたりします。

ここでは、Laravel4.2を対象にしています。



アプリケーション用のディレクトリを分離する


今回は、下記のようなディレクトリ構成にしたいと思います。


laravel
  + app
     + Sys
        + Subsys
           + controllers
           + config
           + lang
           + models
           + services
           + views
           + routes.php
  + controllers
  + config
  + lang
  + models
  + views
  + routes.php

Sysディレクトリ以下が新しく作ったディレクトリ構成で、Subsysディレクトリ下はapp直下にあるcontrollersやconfigなどオリジナルのディレクトリ構成と合わせています(サービスプロバイダ用ファイルを登録するservicesディレクトリは追加してます)。

サブシステムを追加したければSubsysディレクトリをさらにコピーしてあげれば幾つでも追加していけます。


$ cd /path/to/laravel/app
$ mkdir -p Sys/Subsys
$ cd Sys/Subsys/
$ mkdir config controllers lang models services views

ここで作ったディレクトリはLaravelの基本セットです。

後述する設定によってどのファイルがどのディレクトリにあるのかを対応付けさせればよいので、名前などは自由に決めれますし例えばライブラリファイルとしてオリジナルのlibディレクトリを追加するといったこともできます。


次に、Laravelでアプリを作る際の基本となるcontollerファイルとviewファイルを作ります。

この作業はLaravelでアプリを作る際の作業と同じです。

コントローラーファイルは、Sys/Subsys/controllersディレクトリに配置します。


<?php

class BarController extends Controller
{
    public function anyIndex()
    {
        // viewを生成
        return View::make('subsys::bar');
    }
}

ビューファイルは、Sys/Subsys/viewsディレクトリに配置します。


<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>hello world</title>
</head>
<body>
hello world
</body>
</html>

次は、ルーティングの設定です。

URLで/barにアクセスしたら先ほどのBarControllerを呼び出すようにしてみます。

routes.phpファイルはSubsysディレクトリ直下に配置します。


<?php

// barシステム用
Route::any('bar', 'BarController@anyIndex');

次は、サービスプロバイダーファイルの作成です。

ここでは新しく追加したディレクトリを定義したり、プレフィックスを定義することでコントローラ内から簡易的な呼び出し方ができるようにセットしておきます。

サービスプロバイダーファイルはservicesディレクトリに配置します。


<?php
namespace Sys\Subsys\services; 

use Illuminate\Support\ServiceProvider;

class BarServiceProvider extends ServiceProvider
{
    public function register()
    {
    // IoCコンテナ登録のみ行うことが推奨されています
    }

    public function boot()
    {
    // Laravel用クラスローダーの登録
    \ClassLoader::addDirectories( array(
    // 独自で設定したフォルダを記載
        __DIR__.'/../controllers',
        __DIR__.'/../models',
    ));

    // ビュー、言語、設定の名前空間(プレフィックス)設定
    // 独自で設定したフォルダを記載
    \View::addNamespace( 'subsys', __DIR__.'/../views' );
    \Lang::addNamespace( 'subsys', __DIR__.'/../lang' );
    \Config::addNamespace( 'subsys', __DIR__.'/../config' );

    // ルート定義の読み込み
    require __DIR__.'/../routes.php';
   }
}

addDirectories()によって、独自のcontollersやmodelsディレクトリを使うように宣言したり、subsysプレフィックスを追加することで、先ほどのBarController.php内での


return View::make('subsys::bar');

という呼び出し方が可能なように定義しています。

subsysプレフィックスを付けるとviews、lang、configディレクトリからファイルを探してくれます。

設定ファイルも


$const = Config::get('subsys::foo.bar');

のような呼び出し方ができたりします。

次にこのサービスプロバイダをLaravel本体に認識させます。

これは、laravel/app/config/app.phpの中にprovidersという設定項目があるのでその中に追加します。


    'providers' => array(
        'Illuminate\Foundation\Providers\ArtisanServiceProvider',
        'Illuminate\Auth\AuthServiceProvider',
        'Illuminate\Cache\CacheServiceProvider',
        'Illuminate\Session\CommandsServiceProvider',
        'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider',
        'Illuminate\Routing\ControllerServiceProvider',
        'Illuminate\Cookie\CookieServiceProvider',
        'Illuminate\Database\DatabaseServiceProvider',
        'Illuminate\Encryption\EncryptionServiceProvider',
        'Illuminate\Filesystem\FilesystemServiceProvider',
        'Illuminate\Hashing\HashServiceProvider',
        'Illuminate\Html\HtmlServiceProvider',
        'Illuminate\Log\LogServiceProvider',
        'Illuminate\Mail\MailServiceProvider',
        'Illuminate\Database\MigrationServiceProvider',
        'Illuminate\Pagination\PaginationServiceProvider',
        'Illuminate\Queue\QueueServiceProvider',
        'Illuminate\Redis\RedisServiceProvider',
        'Illuminate\Remote\RemoteServiceProvider',
        'Illuminate\Auth\Reminders\ReminderServiceProvider',
        'Illuminate\Database\SeedServiceProvider',
        'Illuminate\Session\SessionServiceProvider',
        'Illuminate\Translation\TranslationServiceProvider',
        'Illuminate\Validation\ValidationServiceProvider',
        'Illuminate\View\ViewServiceProvider',
        'Illuminate\Workbench\WorkbenchServiceProvider',
        'Sys\Subsys\services\BarServiceProvider',
    ),

最後に、追加したディレクトリをcomposerに認識させ、オートロードできるようにします。

laravel/composer.jsonに下記のpsr-0の項目を追加します(classmapはLaravelインストール時のデフォルトの設定です)。


    "autoload": {
        "classmap": [
            "app/commands",
            "app/controllers",
            "app/models",
            "app/database/migrations",
            "app/database/seeds",
            "app/tests/TestCase.php"
        ],
        "psr-0": {
            "Sys": "app/"
        }
    },

修正が終わったら


$ composer dump-autoload

を実行します。


初期設定は多少面倒ではありますが、これでサブディレクトリ内で幾つものLaravelのアプリを動かすことができます。

色々な設定をしていますが、app.php内のサービスプロバイダの中からサブシステム用のサービスプロバイダ(BarServiceProvider.php)が呼び出され(呼び出す際にはcomposerによりオートロード)、サービスプロバイダからルーティングファイルやコントローラやビューファイルの場所をLaravelに認識させているといった流れです。

ここで書いたのは例ですのでうまくサービスプロバイダの中身を書き換えればディレクトリ構成はもっと自由に定義できたりします。


新しいサブシステムを追加したい場合は、


・ Sysディレクトリ以下にサブシステム用ディレクトリを新たに作る

・ サービスプロバイダファイルを作成する

・ laravel/app/config/app.phpに追加したサービスプロバイダを追加する


という対応だけでどんどん増やしていくことができます。