PAK86_codeing20140517_TP_V

突然プログラマになって社内ファイルサーバ検索システムを作った話

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

お疲れ様です。株式会社リスペクト プログラマの山内です。

先輩から「入社してから一年半経ったし今までやってきたことをブログにまとめてみてよ」と言われたので、今回は自分が入社してはじめての社内ツールをつくるまでの話をしてみようかと思います。

どうしてプログラマになったのか

せっかくなので、はじめに自分がどうしてプログラマになったのかをちょっとだけ話してみます。

自分は大学時代バリバリの文系で、おおよそプログラミングとは縁遠い生活をしていました。ついでに言えば大学で始めた演劇では脚本家の真似事までしていて、 就活はそれを活かして文章を書くような仕事に就ければなーくらいのことを考えていたのです。

そこで出会ったのが株式会社リスペクトだったのですが、弊社で新卒ライターを募集していたのに目をつけ、ライター志望で弊社の面接に乗り込みました。一次面接を気合でなんとかやり過ごし、多少気を良くした私でしたがしかし、 最終の代表面接では早々に「ライターには向いてないね」と衝撃的な一言でバッサリ切り捨てられてしまいます。

向いていないと言われてしまってはしょうがないかと諦めかけたところで、 代表から「プログラマやってみない?」とこれまた衝撃的な一言をいただきます。話を聞くと、事前に受けていたSPIの結果を見る限りではライターよりもプログラマに向いているとのこと。

予想だにしない展開ではありましたが、せっかく社会人になるのなら新しいことをやってみるのもいいかも…と思い、晴れて素人プログラマとなったのでした。

ファイルサーバ検索システムを作る前にやったこと

なにしろプログラミング未経験だったため、いきなり実戦投入というわけにもいきません。内定が決まったあたりから入社前課題を出してもらい、ひたすら基礎固めをしていきました。

基礎知識

まずは数多くのプログラマがお世話になったであろうドットインストールです。
具体的に取り組んだのは以下のレッスンでした。

卒論などもあったことからマイペースに進めていいよと言われ、2,3カ月かけてかなりのスローペースで取り組みました。

余談ですが、ローカル開発環境の構築ははじめVagrantを使用する予定で進めていたのですが、当時個人的に使用していたノートPCに「仮想化支援機能」なる機能がなかったためにまったくレッスン動画通りに進まず結構苦戦した覚えがあります。そのときはまだ英語のエラーを読み解くという発想には至りませんでしたし、まさか自分のPCで環境構築ができないとは思わなかったので…。

結局、研修はさくらのVPSを借りて進めました。結果的にVPSにも触ることができたのでいい経験になったんじゃないかと思います。

Googleニューススクレイピングツール

卒論が終わったあたりに次なる課題が出されました。

  • 毎日指定した時間にGoogleのニュース検索から、登録されたキーワードをもとに検索をかけて検索結果をすべてMySQLに保存する
  • 保存する際は、前日までに保存済みのデータと重複しないように注意する
  • すべての登録済みキーワードにおいて、その日に取得できた新着分の情報を指定されたメールアドレスへ通知する
  • メール送信は、登録済みキーワードごとに個別に通知する

いきなりかなり本格的なツールです。
これ以外にも要件や開発のヒントなどがいろいろ提示されましたが、ついこの前まで”Hello World”を表示させて喜んでいた自分にとってはかなりハードルが高かったです。

とはいえ、わからないことがあれば逐一チャットでやり取りしつつ、ある程度形になれば提出をしてフィードバックをもらっていたので「何をしていいのかわからない…!」と途方に暮れることはありませんでした。

せっかくなので、最初に提出したときのフィードバックを一部引用しておきます。

▼コードへの大まかなツッコミ

  1. マークアップとプログラムの処理をなるべく分離する
    ・「どのような処理を行うか」と「どのような表示を行うか」をできるだけ分けて考え、コード上に表現する(関心の分離)
    ・処理を行う部品と表示を行う部品で分けて作っていれば、表示だけ豪華にしたいとき処理の部分を見る必要がないし、逆も同じ
    ・ウチのようにマークアップを行うコーダーと内部処理を行うシステムで分業化されている場合、責任範囲のファイルが明確になるなど、お互い楽になる

  2. DBアクセス部分をなるべく他の部品から分離する
    ・これも関心の分離が目的
    ・SQLが各所に散らばってるとデータ構造の変更時などに沢山の箇所を修正しないといけなくなる
    ・SQLはPHPとは異なる言語なので、混ぜて書く部分は絞りたい
    ・SQLを使ってDBアクセスする関数を提供する層+その関数を利用するアプリケーション層に分け、アプリケーション層からSQLを直接触らないようにする

そういえば関心の分離については初期のころからしっかり指摘されていました。
引用部分にも書かれていますが、特に弊社では今のところマークアップコーディングとシステムが分業されていたりするのでこの辺りは効率化のため重視されます。

  1. ユーザ入力をそのまま使って動的にSQLを組み立てるのにはセキュリティリスクがある
    ・ログイン名やパスワードでSQLインジェクションが可能な作りになっている
    ・信頼できない入力を使うならプリペアードステートメント or エスケープが必要
    ・「SQLインジェクション」でググれば仕組みは分かるハズだけど、必要なら攻撃例も見せます

セキュリティはやはり重要ですね。
ちなみに「SQLインジェクション」や「XSS」など基本的なものについては部門の研修だけでなく、新卒全体での研修でも取り上げていました。

ソースコード

https://github.com/respectpal/google_news_scrape

当時のコードと研修担当の上司から返ってきたフィードバックをGitHubにあげてみました。
お世辞にもきれいなコードとは言えないのですが、「最初はこんな感じのコードを書くんだ」という参考にしていただければ。

ファイルサーバ検索システムを作ることになった経緯

入社してすぐに、ひとまず教育担当の先輩から研修期間の最初の3カ月で習得してほしい事項のリストをもらいました。

  • コンピュータ / プログラムがなぜ動くのかの理解(ハードウェア/ドライバ/OS/サーバorブラウザといったソフトウェアスタックについての理解)
  • ログの調べ方
  • PHPの基本構文ひと通り
  • ファイルの分割とコードの再利用
  • オブジェクト指向
    • 抽象データ型
    • カプセル化
    • ポリモーフィズム
  • 外部ライブラリの利用
  • 正規表現
  • 文字コードの基礎
  • MySQLのCRUD
  • 正規化とテーブル設計
  • XSS/SQLインジェクション/CSRFの一般的な対処
  • MVCパターン
  • MVCフレームワークの利用
  • Gitの使い方
  • TCP/IPの基礎
  • Linuxのフォルダ構成
  • Linuxのユーザ管理
  • Linuxの権限管理
  • Apacheの設定とhtaccess
  • mod_rewrite
  • バッチファイルとシェルスクリプト
  • サーバセキュリティ基礎(ひたすら穴をふさぐ)
  • FuelPHP(or その他何らかのMVCフレームワーク)の基本
  • HTML/CSS/Javascript基礎
  • jQuery
  • Ajaxの利用
  • 計算量の概念
  • 基礎的なアルゴリズムとデータ構造幾つかの原理
    • ソート/探索/ダイクストラ/確率的アルゴリズム
    • ツリー
      • 二分木
      • バランス木(B木/赤黒木)
    • ハッシュ
  • 幾つかの異なるプログラミングパラダイムについての大まかな理解
    • 手続き型/関数型
    • 命令形/宣言型
    • クラスベース/プロトタイプベース
    • 逐次実行/イベントドリブンなど
  • ひと通り終えたあとの技能試験として、FuelPHPを使ったWebサービスの公開

はじめにこのリストを見たときは「こんなに覚えることがあるのか…」と辟易しましたが、実際にやってみると特に苦ではなかったです。
掲示板やブログといった簡単な課題を、フレームワークを使用しないフルスクラッチで作ってPHPの基礎を身に付けながら、合間合間で座学を受けてリストのひと通りを習得していきました。

そして最後に

  • ひと通り終えたあとの技能試験として、FuelPHPを使ったWebサービスの公開

をすることになったのですが、せっかく作るならちゃんと使えるものを作ろうということに。

ちょうど社内ファイルサーバのデータ量が膨大になってきてどこに何があるかが把握しきれなくなっているという問題が出てきたこともあり、全文検索機能を搭載した、社内ファイルサーバ検索システムを作ることにしました。

方針

FuelPHP

ひとまずPHPを使うのは確定として、はじめて本格的にPHPのフレームワークを使用した開発を進めることになりました。

弊社では主にCakePHPとFuelPHPを使用しているのでそのどちらかで開発をするので好きな方を選んでいい、ということでなんとなく公式ドキュメントが読みやすそうなFuelPHPを使用しています。

とはいえ始めはフレームワークって何?という状態だったため公式ドキュメントを見てもよくわからず、ざっくりFuelPHPの使い方 – Qiitaなど読みやすそうな日本語の記事をひたすら漁りながら手探りで進めていきました。
FuelPHPでもそこそこ日本語の記事は見つかりましたが、今考えるとどちらかといえばCakePHPの方が日本語記事は探しやすかったかもしれません。

MeCab

日本語で全文検索を行う場合はあらかじめ分かち書き(英語のように単語ごとでスペース区切り)をする必要があり、そのために日本語形態素解析エンジンのMeCabを導入しました(形態素解析が不要なN-Gramという方式もありますが、今回はこちらを採用しています)。
MeCabの導入をするにはLinuxでコマンド操作してMeCab本体やPHPのmecab拡張などをインストールしなくてはならず、黒い画面に苦手意識のあった当時の自分にはなかなか辛かったです。

MySQL(InnoDB)

全文検索を実装するということで、今回はInnoDBでFULLTEXT INDEXを使用することにしました。InnoDBでFULLTEXT INDEXが使用できるのはMySQL5.6以降なので導入時のバージョンに気を付けます。

MySQLを使用する機会自体は頻繁にあるのですが、PHPのフレームワークを使用していると生のSQL構文を直接書くことがあまりありません。
特に全文検索の処理はFuelPHPのクエリビルダだけでは再現できないのでDB::query()で直接クエリを書いたりDB::expr()を駆使する必要がありました。
検索機能のひとつとしてAND検索とOR検索を選択できるようにしていたのですが、FuelPHPのクエリビルダを使用してそれを実現するのにだいぶ苦戦しました。最終的にかなり不慣れで不細工なコードになっています。

Twitter Bootstrap

社内ツールなのでフロント部分は特にこだわりません。管理画面の開発などでこれからお世話になるかもしれないということで、Twitter Bootstrapを使用してみることにしました。

mount.cifs

社内ファイルサーバはWindows上にあり、それをどうにかしてLinux上で読み込めるようにしなければなりません。そこでCIFSを使用したマウントを実行し、Linux上でWindowsのファイルを扱えるようにしました。

個人的に一番ハードルが高かったのはここかもしれません。マウントという仕組み自体も理解に手間取ったり、弊社ファイルサーバで使用しているActive Directoryでの設定に苦労したり。
ネット上でも記事が少なく、情報が見つかりにくかったです。

できたもの

totsuzen1

(ファイルサーバ検索システム、通称SimmyのTOP画面。ちょっとだけGoogleリスペクトしています。)

ファイルサーバクローラ

日々更新されるファイルサーバ内のファイルの情報を取得してDBに格納するためには、定期的にクローラを実行しなければなりません。調べてみたところ、一回のクローリングには二日弱かかるようでした。
業務時間中に無闇に実行して社内サーバが重くなるのは避けたいので、土日のうちにクローラが実行されるように設定します。

FuelPHPにはoilコマンドを利用してCLIからPHPスクリプトを実行できるTask機能が提供されているので、クローラはこれを使って呼び出し、cronから定期的に実行できるようにしました。

検索画面

実際に検索を使用するときの検索画面を用意しました。とはいえ、作成したのはTOPページと検索結果画面のみです。
フロント部分に時間をかけすぎるのは課題の本旨ではないかなと思い、わりと簡素に仕上げました。

検索機能についてはできるだけ馴染みのあるものになるよう、スペース区切りのAND検索ができるようにしました。ちなみに、データの多さや全文検索によって検索が一時かなり遅くなったことがあり、その問題の対処にはかなり四苦八苦しました。

管理画面

せっかくなのでちゃんとした管理画面もつくってみました。
FuelPHPのSimpleAuthを利用して管理者のみが入れるようにし、検索対象に含める拡張子や最大ファイルサイズを設定できるようにしました。

totsuzen2

(管理画面のキャプチャ。)

課題とこれから

課題の途中から実案件へのアサインなどが入ってきてかなり期間が空いてしまったのですが、
着手から1年後の今年6月になんとか社内でリリースする運びに。

ただ、実際に運用をしてみるとやっぱりいろいろ問題が出てきました。

ログが不親切

FuelPHPにはLogクラスがあり、それを利用して見よう見まねでログ出力はしていたのですが、実際に問題が起きると「欲しい情報がログに残されていない」「いらない情報が多くて問題を見つけられない」といったことがありました。
ちゃんと問題解決に役立つようなログの出力を考える必要がありそうです。

障害が発生しやすい

先述の通り本システムは週に一度、ファイルサーバの新しい情報を取得するためにクローリング処理を行います。
その処理は本番環境で使用されるデータベースを直接書き換えているのですが、そうなるとクローリング処理の途中でエラーが発生した場合に本番環境のデータが壊れてしまう可能性があります。また、タイミングによってはクローリング中のデータが検索結果に表示されてしまうことになるので、それも改善しなければなりません。

そのほか、課題ではありませんが追加してみたい機能も。

Google Site/Google Groupの検索

弊社では今年のはじめにGoogle Apps(現在はG Suite)への移行を行いました。それにともない、Google Siteで社内Wiki、Google Groupでメーリングリストを運用しています。
これについても同様のシステムで全文検索ができると便利そうです。
ただ、ここまで機能を広げていくとなるとInnoDBによる全文検索では持て余してしまいそうです。

Dockerの導入

対外案件などだとリスクもあり、なかなか新しい技術の導入はできません。しかし、社内ツールなどであればある程度意欲的にトレンドを追いかけることもできそうです。

最近で言えば急激にいろいろなところで名前を聞くようになったDockerなどでしょうか。
本システムをDockerに乗っけて運用をしていくことではやめに流行を押さえていきたいなと思っています。

おわりに

約一年半前、入社してすぐ取り組んだファイルサーバ検索システムですが、いまだにちょこちょこバグ修正や機能追加を加えながら運用を行っています。

社内でしか使わないツールですし、もともと研修課題だったことも手伝って、フランクに新しい技術を導入してみたり、かなり好き勝手やらせてもらえるのでとてもありがたいです。
もちろんクライアントから依頼された案件をこなしていくのも大事ですし、学ぶところも多いのですが、「これやってみたい!」と思う技術をすぐに試せる場があるのはすごくモチベーションになります。

上述したように、本システムにはまだまだ改善していかなければならないところもあるのでこれからもしばらくはファイルサーバ検索システムと付き合っていくことにはなりそうですが、もうしばらくこの課題と一緒に自分も成長していければと思います。

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