とりあえずググれ?もうちょっとコツとかないんですか?(Google検索のコツ)

はじめに

TECHDRIVEの佐藤です。 プログラミングするのに、初学者でも上級者でも安定して必要とするスキルと言えば検索力ではないでしょうか。 ググり力 なんて言ったりもしますね。

ただ、「検索しよう」と言われても実際どういう風にすると望む情報が効果的に取得できるのか、ということはありそうです。 ここではプログラミングにまつわるググりをテーマに何点かポイントをお伝えしたいと思います。

検索ワードをどうするか

とりあえず単語を繋げる

何か方法がわからない時に多いやりかたです。

  • rails ファイルアップロード
  • php7 クラス コンストラクタ
    • 場合によってはバージョンを入れると良い

エラーメッセージを貼る

どうしても解消できなさそうなエラーの時(エラーの英語はちゃんと読んでみた上で)、特徴的な文章を探して貼ります。

Uncaught SyntaxError: Unexpected token =

こういうのをベタッと検索窓に貼ります。ただしこの場合には、Uncaught(捕まえられない=今は処理できないという理解で良いです)、Syntax(文法)、Error(エラー)なので、何か文法を間違えたことはエラーメッセージからはわかります。本来はもう少しよくわからなそうなのを扱います。

英語で文章を作ってみる

carrierwave failed save on validation 全部英語にします。この方法で良いのは、英語版のstack over flow が当たりやすくなることです。英語で解説が出ますが、英語は頑張ります。英語だけは頑張ります。何度もやると慣れるので頑張りましょう。

そのほか

  • 使っている言語、フレームワーク(もちろんそれとは関係ない場合には入れませんが)の名前を入れる。 PHPRails
  • 期間を限定する 1年以内など
  • 対象でない言葉が多い - を頭につけて省く -slack

どれくらい絞るかは言葉次第です。一般名詞の場合には補わないと難しい。 例えば express だと広すぎる。 node.js express とか。

検索結果

結果は膨大な量が引っかかるので、ここから効率的に探していくことが必要です。タイトルと、一部文章の引用を見ます。この時ヒットした言葉は太字になっているので前後の雰囲気を見ていきます。明らかに違いそうなのはこの時点で省けます。 f:id:ms2sato:20180809215257p:plain

以下、サイトごとによく見るべきかどうかをザックリ挙げてみます。私はこんな感じです。

よく読む

課題解決系

  • 本家のGitHub
  • Stackoverflow 英語

上記には劣る場合もありますが、以下も見ます。英語がよく理解できないとか、ちょっと概念が難しいものは日本語でわかる方が楽だったりしますよね。

  • Qiita
  • 個人のブログ

概念、知識系

例えば「トランザクション」とか、そもそも何なのかわからない言葉を調べようとしている場合です。IT系の用語はこういうのが多いので、何かしらの概念の解説が必要になると思います。最近はこの辺少なそうですが、記事形式で中身の丁寧なものが多いです。例えば以下でしょうか。

あまりよく読まない。飛ばすこと多い。

WIkipediaとか何かのまとめ系サイト

おしまいに

検索が上手だとプログラミングの上達もはやいと思うので、ぜひ検索上手になりましょう。

「jQueryで書くとグチャグチャになる」への処方箋、もしくは昔々のJSでのモジュール化について

f:id:ms2sato:20180805232858j:plain

はじめに

TECHDRIVE の佐藤です。

ちょっとあるところで盛り上がったので、ちゃんと書いたらどうなるかなと*1。 「『jQueryで書くとグチャグチャになる』という話を聞くけれど、それってモジュール化をちゃんとしていないからじゃないか」 という話から発しています。

以前からJavaScriptと付き合っている人にとっては、ただの古めかしいイディオムです。ただ、SPAするレベルでなく「ちょっとした動き」をさせたいような場合もソコソコあると思うので、そういう人には参考になるかもしれません。

というわけでこれはレガシーなJavaScriptと付き合う場合のあるあるな方法を今更紹介したものです。特に何か目新しいものがあるわけでもなく、最新のJavaScriptを相手にしていける環境の人には全く関係のないものです(周辺技術が既にこういう部分をカバーして進んでいますし、今後ブラウザにも追加されていくだろうからです)。

解決したい問題

  • RailsなどでAssetsCompileしていると、そもそも全てのJSが動いてしまって「どれが動くのか」わからない。「他の画面の為の内容が影響してバグる」
  • 外部ライブラリ等と名前が被ってしまう問題を回避したい。
  • 動作するものの単位がわかりやすいようにしたい。

どうやるの?

サンプルプロジェクトがあった方が解りやすそうだったのでババっと書いてみました。 github.com 今回のイメージは下記です。

  • index.html(画面)
  • views/index.js (index.htmlで呼ばれるエントリポイントとしてのJavaScript)
  • components/*.js (画面から呼ばれる部品達)

モジュール化

この一言でほぼ答えになるのですが、ちゃんとモジュール化をしましょうという話です。モジュール化と名前空間の適用がこの課題へのコスパの高い対応ではないでしょうか。自分の場合には昔々に名前空間を作れるライブラリを書いているので、これをよく使います。このサンプルでは、viewscomponents配下のJS達がモジュール化されています。

// ネームスペースを指定して、外に露出させない。
// 以下のように書くと、 MYAPP.COMPONENTS.Popupper が使えるようになる。
LIMO.namespace('MYAPP.COMPONENTS')(function(ns){

  function Popupper(el){
    this.$el = $(el)
  }

  Popupper.prototype.setup = function() {
    // 簡単のためalertだけにしているが、ボタンを押したら起きる動作を
    // ここでまとめるようなイメージ。
    this.$el.on('click', function(){
      alert('test');
      return false;
    });
  }

  // ns に付けたものはネームスペースに結合されて公開される
  ns.Popupper = Popupper;
});

エントリポイントを1つにする

一つの画面についてイベントハンドラを付けたりするような、最初の「仕掛け」をするコードの入り口を一つにします*2。index.htmlには下記の1行が書かれています。入り口は必ずこのような簡単な関数一つです。名前空間はプロジェクトで適切に決めれば良いと思いますが、Railsだと、 MYAPP.VIEWS.[Controller名].initShow() などのようにして、 initNew()initEdit() を同じ内容にすると便利だったりするかもしれません。

<script>MYAPP.VIEWS.INDEX.init()</script>

エントリポイントから各コンポーネントを呼ぶ

基本的には上記のエントリポイントの関数内には $.ready が書かれるイメージです。そして、その関数の中から各コンポーネントが呼ばれます。GitHubに載せたサンプルではもう少し複雑な内容も書いてみました。下記だと簡単すぎて恩恵がよく見えないかもしれませんので。

イメージとして複雑な処理はコンポーネントの中に封じ込めて、エントリポイントはなるべくそれを使うだけにするような形です。また、コンポーネントがDOMツリーへの情報を必要とする場合には、ルートのCSSセレクタを設定するなどします(動きが複雑だと複数のセレクタを設定するかもしれませんね)。

LIMO.namespace('MYAPP.VIEWS.INDEX')(function(ns){
  ns.init = function(){
    $(function(){
      // クラスっぽくしているが、簡単ならもちろん関数でも良い。
      // 大抵はコンポーネントのルートになるCSSセレクタを指定する。
      var popupper = new MYAPP.COMPONENTS.Popupper('.mytrigger');
      popupper.setup();
    });
  }
});

おしまいに

「各画面にちょっとした演出のJS書きたいんだけどなぁ」くらいならこの程度がわかっていると簡単ですよってことで。ガッツリやりこむのが見えている場合には今は色々便利な道具があると思うのでちゃんとやってくだされ。

*1:Rails使っている人ばかりだったので、ちょいちょいRailsの話ありますけど興味ない人は読み飛ばしてくだされ

*2:実は概念化されていれば一つの関数にまとめたりする必要も無いですが、簡単に強制するなら一つの関数ですね

Cloud9がAWSの一部になってしまったので利用方法を動画にしてみました

Cloud9はとても便利なWEB上の開発環境です。
元々はOSSのプロジェクトで基本料金無料で環境を提供してくださっていたのですが、Amazonに買収されて現在はAWSの一部として提供されています。買収後はAWSのアカウントを作ってから利用する形になったのですが、ちょっと億劫になってしまった人もいるかもしれません。

利用方法を動画にしてみましたので参考にしてください。

新しくAWSアカウントを作れば無料枠のおかげでリーズナブルに学べる仕組みができていると思いますが、用法・用量を守って正しくお使いください。AWSがどういう仕組みで課金されるかなどは知ってから進められることをオススメします(この辺りの課金についてのトラブルが起きた場合でも責任は持てませんのでご注意くださいませ)。

AWSのアカウント
Cloud9の環境構築

JavaScriptデバッグ作業の効率があがる!? 〜 ブレークポイントを使ってみよう 〜

こんにちわ。最近寒くなりましたね。 皆様はいかがお過ごしでしょうか?

本記事は、7歳のクリスマスイブにお母さんとサンタさんがキスをしている現場に遭遇して以来、何かが欠けてしまったTECH DRIVEの小笠原がお送りいたします。

今回はJavaScriptのデバッグ方法についてご紹介します。 ※ Google Chromeの開発者ツールを使用したデバッグ方法
以降はブレークポイントを使用したデバッグ方法の紹介がメインとなります。
↓のような感じでお悩みの方が対象となりますので、ご了承くださいませ。

1. JavaScriptのデバッグ方法がわからない
2. console.log以外のデバッグ方法がわからない

また、サンプルコードに関する前提条件は以下の通りです。
実行環境: Google Chrome
使用ライブラリ: jQuery

JavaScriptのデバッグ

JavaScriptが期待通りに動作しなかった時、皆さんはどこをみるでしょうか?

そうですね。開発者ツールのConsoleですね。

基本的にJavaScriptのコードにバグがあると、以下のようにConsoleにエラーメッセージとその原因となっているファイルの情報が出力されます。

f:id:kabaneshi:20171215163355p:plain

エラーの内容にもよりますが、上記のようなケースは該当箇所の確認やエラーメッセージでの検索等、解決のためのファーストアクションは取りやすいかと思います。
しかし、バグの中にはエラーが発生しないケースも存在します。

どういった場合でしょうか?
実際のコードを見ながら解説していきます。
以下のコードは ボタンをクリックするとテキストが表示される(pタグにテキストが挿入される)という処理になります。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <title>sample</title>
</head>
<body>
<button class="btn">テキストを表示</button>
<p class="text"></p>

<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script src="./script.js"></script>
</body>
</html>

script.js

$(function(){
    var $btn = $('.btn'),
        $text = $('.txt');

    $btn.on('click', function(){
        $text.text('ボタンがクリックされたよ');
    });
});

上記のコードは期待通りに動きませんが、エラーが発生しません。
ボタンをクリックしても何も起こらない状態です。

このバグを解決しようと思った時にまずは何をするでしょうか?
console.log で怪しい箇所を出力!と思った方、それも一つの解決方法であることは間違いありません。
しかし、もう少しだけ効率良くデバッグを行える方法があります。

ブレークポイントを使用したデバッグ

ブレークポイントというものをご存知でしょうか?
wikipediaを見ると以下のように書いてあります。

ブレークポイント(英: breakpoint)は、ソフトウェア開発のデバッグ作業において実行中のプログラムを意図的に一時停止させる箇所である。

なにやら難しそうですが、 実行中のコードを一時停止させる際に使われるものらしいです。
はて、実行中のコードが停止できると何がうれしいのでしょうか?

それでは、このバグをブレークポイントを使って潰してみたいと思います。
まず問題のページを実際にブラウザで開いてみます。

f:id:kabaneshi:20171215175922p:plain

テキストを表示というボタンをクリックしても何も起こりません。
開発者ツールからConsole(キャプチャ内の右側)を見てもエラーメッセージも表示されていません。

ではこのコードのどこに問題があるのか、調査していきたいと思います。

まずはConsoleの並びにあるSourcesというメニューを選択してみましょう。
選択後、以下のように現在表示中のページに関連するソースファイルの一覧が表示されるはずです。

f:id:kabaneshi:20171215164945p:plain

JavaScriptのコードを確認したいので、ソースファイルの一覧からコードが記載されているscript.jsを選択します。
すると、以下のように開発者ツール右側に表示されているソースがscript.jsの内容に変わります。

f:id:kabaneshi:20171215172342p:plain

次にこのJavaScriptコードを途中で停止させるためのブレークポイントを入れます。
ブレークポイントの挿入は簡単で、以下のようにコードの行数が記載された箇所をクリックするだけです。
まずは、変数の定義をしている2行目で処理を停止したいと思います。

f:id:kabaneshi:20171215172221p:plain

↑のように停止したい行数をクリックしブレークポイントが入ると青くハイライトされるた状態になります。
それでは、この状態で画面をリフレッシュしてみましょう。

リフレッシュ後に画面が↓のキャプチャと同じ状態になっていれば、ブレークポイントでコードが停止していることになります。

f:id:kabaneshi:20171215172752p:plain

先程script.jsの2行目にブレークポイントを挿入したので、JavaScriptの実行はそこで止まっています。
次に開発者ツール右下のScopeという項目をみてみましょう。
するとLocalと書かれた情報にネストしていくつかの情報が表示されていることがわかります。

f:id:kabaneshi:20171215173052p:plain

このLocalの解説を厳密にすると、それだけで1記事余裕で書けてしまうので、今回は割愛します。
Local中の情報で着目すべきは、script.jsの中で定義した変数の情報になります。
↑のキャプチャ内の枠で囲われた箇所から現在変数に入っている情報を確認することができます。

今は2行目で処理が停止しているので、まだ変数に値は代入されておらず、undefined(変数を宣言した際に入る初期値)が入っていることがわかります。

次に開発ツール上でscript.jsの2行目を実行してみましょう。
開発ツール左下のメニューバーにあるアーチ状の矢印をクリックしてください。

f:id:kabaneshi:20171215174817p:plain

矢印をクリックするとscript.jsの2行目が実行され再び3行目で止まります。
この状態で再度右側のLocalの中を確認してみましょう。
2行目が実行されたことにより、変数$btnに値が入っているのが確認できます。

f:id:kabaneshi:20171215174937p:plain

この容量でデバッグを進めていくと、わざわざconsole.logで出力しなくとも変数の値が確認できるので、デバッグが捗りそうです。
また、このアーチ状の矢印はステップ実行と呼ばれ、クリックするとブレークポイント挿入箇所から1行ずつコードを実行してくれます。
それでは、再度ステップ実行を行いLocalの中を見てみましょう。

f:id:kabaneshi:20171215175227p:plain

次は3行目の処理を実行されました。
再度Localを確認すると、先程までundefinedだった$textの中にも値が入っていることが確認できます。
しかし、$textの中に要素の情報が入っていません。。。
ここが怪しそうですね。

このデバッグ方法の素晴らしいところは、現在の停止した状態でConsoleからJavaScriptが実行できる点です。
それでは、なぜ$textに期待した値が入っていないのか、開発者ツール下部のConsoleから$('.txt')を実行してみましょう。 ※ 開発者ツールの下部にConsoleが表示されていない場合はEscキーを押してみてください。

f:id:kabaneshi:20171215175631p:plain

Consoleから$('.txt')を実行するとLocal->$textの結果と同様に要素の情報が取得できていないことがわかります。
もうお気づきとは思いますが、今回はタイポがバグの原因となっていました。
script.jsの3行目で.textとすべきところが.txtとなっていました。
.txtというクラス名を持った要素は存在しないため、要素が取得できていなかったんですね。

それでは、ブレークポイントを解除し、該当箇所を修正した上でもう一度動作を確認してみましょう。
先程ブレークポイントを挿入した際に青くハイライトされた行数の箇所を再度クリックすると解除が行えます。

ページのリフレッシュ後、ブラウザ上のボタンをクリックしてみましょう。
以下のように「ボタンがクリックされたよ」というテキストが表示されれば、デバッグ成功です。

f:id:kabaneshi:20171215175819p:plain

まとめ

今回は解説のため、かなり極端なバグを例にデバッグ方法をご紹介しました。
しかし、ブレークポイントを活用することで効率よくデバッグが行えることは、お分かりいただけたかと思います。
また、今回エラーの発生しないバグを例に記事を書きましたが、ブレークポイントを活用すると以下のようなこともできます。

  1. エラー発生時、その前後で実行されている処理の動作確認
  2. 複数の変数に代入されている値の確認

この他にもデバック時の様々なシーンで役立ちますので、本記事でブレークポイントを知ったという方は、是非今後も活用してみてください!

Mastodonを2週間ほどHeroku運用した日報まとめ

https://top-techdrive-mastodon-assets.s3-ap-northeast-1.amazonaws.com/media_attachments/files/000/002/757/original/f13ba52f77560603.png?1493429954

はじめに

流行りそうって言うより、面白そうだったのでやり始めたら結構続けているのでまとめてみます。Herokuさんとはなんの関係もございません。

経緯

4/15 〜 おっかなびっくりの初期

4/15 くらいから興味を持ってとりあえず運用してみたくてちょっと調べたら「ユーザ名とパスワードを抜かれるから野良インスタンスはウンタラカンタラ」というような運営者の信用の話があったので、OAuthで解決するのが妥当かと考えました。そして私や私の周囲の人で楽しめる形にするにはGitHubでのOAuthが最善で、その後の個人的な改造にも楽しみが増えると思っていました。もともとこういうサービスを自分で作りたかったことも動機の一つです。

GitHubでのログインを対応させて下記を4/16に書いていますね。とりあえずぼっちだったんですね。 www.facebook.com

HerokuのFreeDynoは早々に見切りを付けて1Dyno使い出しました。FreeDynoはSwapが実装されていないので、少しアクセスが増えるとメモリ不足のエラーが出てしまうのですね。そのままだと利用に支障をきたすと考えて課金生活を始めました。周囲の情報からメモリの使用が尋常ではないと知ったので、そのままでは難しいと思いました。

mstdn.techdrive.top

最初に日報を書いたのが 4/17らしいです。このころは「じゃじゃ馬馴らし」的な気持ちでやっていたと思います。設定できそうなのが下記です。

  • WEB_CONCURRENCY
  • MAX_THERADS
  • Sidekiq concurrency

WEB_CONCURRENCY × MAX_THERADS の分だけスレッドが利用されるはず(その分並行処理が増えるのでメモリも使うはず。Puma環境詳しくないですが https://github.com/puma/puma#clustered-mode あたりを見るとその様子です)で、それとは別にSidekiq concurrency も並行処理分メモリを使うだろうということらしいです。

なので、やばそうになるとこの辺りの数値を調整してメモリ利用をし過ぎないように調整していました。かなり絞りまくっていたのがこの時期です。

mstdn.techdrive.top

mstdn.techdrive.top

ちなみにこの時点でほとんどお一人様インスタンスなので、通常のWEBサービスと求められることがだいぶ違うと感じていました。全然利用者がいなくてもリソースを食いまくり、課金までさせられるので、あまり得したような気がしません。

4/18 〜 workerを作成して安定

結局、一台での安定は難しいと判断して(常時9割近くメモリを消費する状態では安心できません)、workerを立ててみたところだいぶ安定してきました。worker自体の負荷が高かったわけではなく、webの方なのかと感じたのもこのあたりです。また、DBへの負荷が高いとよく言われていますが、Heroku Postgresを利用しているので私が関知するところではなくなっているのは幸運でした(Herokuさんごめんなさい)。Rollbarなども入れてエラーがわかるようになったのはこの頃です(あまりに多くて若干引きました。Slackに流すとかしなくて良かったです)。

mstdn.techdrive.top mstdn.techdrive.top mstdn.techdrive.top mstdn.techdrive.top

理屈では、WEB_CONCURRENCY × MAX_THERADS + Sidekiq concurrencyでDB接続をすると思うので、DB_POOLの値はそれを超えて少し余裕をつけるようにしています。この辺り最初の頃は乱暴に設定していたのでDBに接続できないエラーがRollbarに通知されていました。

ちなみにストリーミングサーバーの構築に全く触れていませんが、Herokuのアプリケーション一つでは難しそうです。みなさん工夫されている様子です。 qiita.com

4/22 初めてのVerup

最初どこかのmasterをforkして持ってきてしまったので自分が運用しているバージョンすら知らなかったのですが、ver1.2.2が出たとのことでバージョンアップ。怖かったのでstagingを用意して、これでうまくいくか確認してから行いました。Herokuには特定のGitHubのブランチを監視して変更があれば自動デプロイする仕組みがあるので、今はこれを生かしてマージ=デプロイの運用をしています(本当はCircleCIなどで環境作りたいですがちょっと時間が足らずできていません)。

mstdn.techdrive.top mstdn.techdrive.top mstdn.techdrive.top

ここではmastodon:dailyを仕掛けないとやばいという話が伝え聞こえていたので、それだけは忘れずにやろうと決意して臨みました。

4/23 〜 安定期

この辺りでやっと諸々落ち着いてきた感があり、淡々としています。日報の変化少ないので巻末に入れます。気付いたり思ったこととしては下記です。

  • 無差別フォローBotはサーバーの負荷になるのでブロックすること(フォローされると、トゥートの度にこちらのサーバーがアクションしなければならなくなるのでリソースを食います)。
  • テキストばかりのインスタンスでローカルTLに2〜3人のせいか、ポツポツ人が増えてもそれほど大きな負荷にはなっていません。
  • Herokuはこれくらいならひょっとすると人数捌けるのかもしれません。人数増えないのでGitHubのアカウントお持ちの方は https://mstdn.techdrive.top/ へ遊びに来てくださいー。
  • チューンするならWebからやりたいです。
  • 改造は少しずつが良いです。GitHubログインだけできれば良いと思ってガサッと機能を削ってみたのですが、アプリにログインするのにOAuthだと邪魔になるケースなどがあり、結局かなり戻しています。
  • サインアップを1秒ごとに狙ってくる輩がいます。これをブロックしておかないとメアドログインのインスタンスは荒らされそうな気がします(OAuthログインなのでエラーログに出てきます)。

これまでの人数の増減などは下記で見ると良いかもしれません。 https://dashboards.mnm.social/dashboard/db/instance-detail?var-instance=mstdn.techdrive.top&refresh=30m&orgId=1

お礼など

Herokuでの工夫はzunda氏のトゥートやGitHubを大変参考にさせていただきました。まだまだ私の知らない工夫をされているので、追いついていきたいです。

mastodon.zunda.ninja github.com

付録

23日以降の日報

mstdn.techdrive.top mstdn.techdrive.top mstdn.techdrive.top

mstdn.techdrive.top mstdn.techdrive.top mstdn.techdrive.top

「HTML+CSS入門ハンズオン!ゆるーくWebサイトを作ってみる会」好評でした!

f:id:ms2sato:20170420192349j:plain

TECH DRIVE佐藤です。TECH DRIVE ではブログだけではなくて、勉強会やセミナーも開催しています!
4/18に行われた「HTML+CSS入門ハンズオン!ゆるーくWebサイトを作ってみる会」もその活動の一つです。メンバーの小笠原氏によるハンズオンで、これまでにも何度か開催された実績のある会です。

最初はライブコーディングを交えたデモンストレーションと共にGoogleChromeのデベロッパー・ツールの扱い方をお伝えしました。
その後、会場のみなさんは資料を参考にしながらHTML/CSSを作り込んで行きます。途中でわからないことがあっても、講師が傍まできて一緒に考え、理解が深まるように丁寧にレクチャーをしてくれます。

f:id:ms2sato:20170420194940p:plain

ご参加いただいた方からは
「作り込まれている資料だったので凄いと思った」
「丁寧に説明受けられてわかりやすかった」
などの声をいただけました。

また、こういったセミナーでは「セミナー当日はわかったと思ったんだけど、いざやってみたらよく理解できていなかった」ということはよくあると思います。TECH DRIVEではそういった困りごとにお答えするために「【初心者歓迎】プログラミング相談所【もくもく作業でもOK】」を開いています。わからないことは再度講師に対面で質問できるので、フォローアップも万全です!
次回は 4/25、場所は同じ高田馬場 CASE Shinjukuさんにお借りして開催します。参加されて疑問点のある方も、参加できなかったけれども相談事のある方も奮ってご参加ください。
techdrive.connpass.com

初心者向けにできるだけ噛み砕いてみるオブジェクト指向 vol.3 コードの変更に対応する

はじめに

これまで、vol.0vol.1vol.2とたとえ話が続いているので「で、実際にコードではどうなるの?」と気になってくるのではないかと思います。これから複数回に分けて、実際にコードを書いていきながら確かめていきましょう。今回はコードに起こる変更のイメージを感じていただけたらと思っています。オブジェクトっぽいコードはまだ出てきませんので「こんなの楽勝!」という方は読み飛ばせるかもしれません。

シチュエーション

私は先輩プログラマに依頼されて、システムの一部の処理を書いています。まだ仕様は確定していないそうで、サンプルのコードを書いておき、そこから都合のいい部分を本当のシステムに移植するらしいです。先輩は「移植しやすいように作れよ」と言っていました。

ある規則に則って文字列を加工するのが私の担当箇所です。

ストーリー

お題0: カンマ区切り

「カンマで区切られている文字列を、標準出力に出す」 とりあえずこれを言われたので、下記のようなコードを書いてみました。

# 準備された入力の文字列をカンマ区切りで区切って一行ずつ出力する
str = "りんご,みかん,バナナ,いちご"

# ここの処理を作る
puts str.split(',')

どうやらこれはこれで良さそうです。初歩的な内容で書ける処理でしたね。

お題1: 数字と一緒に出力する

どうやら出力のフォーマットが決まってきた様子で、見やすいように行の先頭にインデクスを付けて出すようです。 というわけで、コードを変えてみました。

# 準備された入力の文字列をカンマ区切りで区切って
# 一行ずつインデクスと一緒に出力する
str = "りんご,みかん,バナナ,いちご"

# ここの処理を作る
str.split(',').each_with_index do |fruit, index|
  puts "#{index}:#{fruit}"
end

each_with_indexがわかれば大丈夫でした。

お題2: カンマとコロンに対応する

今度は入力の文字列のフォーマットも変わる様子です。カンマだけではなくて、コロンで区切られることもあるらしいです。 splitは正規表現にも対応している様子なので、一箇所の変更で済みました。

# 準備された入力の文字列をカンマまたはコロン区切りで区切って
# 一行ずつインデクスと一緒に出力する
str = "りんご:みかん,バナナ:いちご"

# ここの処理を作る
str.split(/[,:]/).each_with_index do |fruit, index|
  puts "#{index}:#{fruit}"
end

先輩によると、入力の文字列のフォーマットと、出力のフォーマットはまだ変更されるかもしれないとのことです。

お題3: HTMLタグとして出力する

出力をHTMLで出せないかと依頼があったので、次はこんなコードを書きました。ちょっとした改変でulタグにできて良かったです。

# 準備された入力の文字列をカンマまたはコロン区切りで区切って
# HTMLのULタグとして出力する
str = "りんご:みかん,バナナ:いちご"

# ここの処理を作る
puts '<ul>'
str.split(/[,:]/).each do |fruit|
  puts "<li>#{fruit}</li>"
end
puts '</ul>'

お題4: 状況によって出し分ける

先のお題はちょっと勘違いをしてしまいました。「HTMLでも出せるように」ということで、出し分けが必要だったんですね。条件分岐をするのだろうと思い、下記のようなコードを書きました。

# 準備された入力の文字列をカンマまたはコロン区切りで区切って
# HTMLのULタグとして出力する
str = "りんご:みかん,バナナ:いちご"
output_type = :ul
# output_type = :indexed # インデクス付きならこちら

fruits = str.split(/[,:]/)

if output_type == :ul
  puts '<ul>'
  fruits.each do |fruit|
    puts "<li>#{fruit}</li>"
  end
  puts '</ul>'
elsif output_type == :indexed
  fruits.each_with_index do |fruit, index|
    puts "#{index}:#{fruit}"
  end
end

先輩はあんまりいい反応ではなくて「これはこれで良いけれど、今後、出力の方法が増えるとif文がずっと続くの?ブツブツ…」みたいな感じなんですね。うーん、どうしたら良いんでしょう。

おしまいに

説明しやすいようにお題の内容はかなり簡単な処理です。本来はもっと複雑な処理の方が恩恵はあるのですが、最初は理解しやすいコードで感覚をつかんでいただければと思い、上記のような内容にしています。 実際の現場でお題4のコードでダメ出しされるのは、出力方法が余程変化するシステムでなければ無いと思います。長くなったので次回から上記のコードをより良い形に変えていきます。

一連のコードは下記から取得できます。

github.com

TECH DRIVEについて

TECH DRIVEは「技術者の成長を加速させる」をキーワードに都内で活動をしているコミュニティです。
TwitterやFacebookにて技術ネタやイベント情報の発信を行っていますので、ご興味があれば、いいねやフォローをお願いいたします。