私の転職活動は中学生から始まっていた
SIer脱出を語る Advent Calendar 2019 8日目の記事です。
「アウトプット大事」というHow toの話しかしません。 転職の経緯や転職後については SIerから自社サービス系に転職して半年ちょっと経過した (2019/05/15) をご覧ください。
目次
どんなアウトプットをしてきたか
現存するものを列挙するとこんな感じです。古いものだと、中学生の頃に公開したものもあります。
ソフトウェア
- P2P地震情報
- 窓の杜やスラドに載ったり、Interfaceに記事を書かせてもらったりSBSラジオにちょっと出たりした
- 仮想ステレオミキサー、ニコ生アラート(弱) (kram.nyamikan.net)
- WFログビューア
その他
アウトプットに救われた転職活動
「それ、職務経歴書に書いたほうが良いですよ」
初の転職活動は、右も左も分からず転職エージェントを2社活用しました。印象的だったのはIT特化のエージェントでした。
プログラミングを始めたきっかけから今後どうしたいかまでを洗いざらい話した後、こう言われました。
職務経歴書を1ページ増やしても良いので、業務外の活動やSIerで自主的にやっていたこと(Demo or Die(SI現場でいろいろ作った話))をもっと書いたほうが良いと思います
職務経歴書に業務外の活動、という矛盾するアドバイスでしたが、結論から言えばこれに救われました。
私に求められていたもの
転職先はいわゆるWeb系とか自社サービス企業と呼ばれるところですが、現職のメンバ(ソフトウェアエンジニア)には次の特徴があると感じています。
- とにかく技術が好きで、吸収が早い
- プロダクトやビジネスに興味を持っている
- 当事者意識が強い
裏を返せば、メンバとして加わることになる私にも、これらが求められていました。
SIerのギャップとアウトプットのフィット
振り返ると、所属していたSIerでの「普段の仕事」は、求められていたものと大きなギャップがありました。
- 属人性を排除し、標準化された技術を使う
- 作業を細分化するか、細分化された作業を仕上げるかのどちらか
- プロダクトやビジネスに影響を与えにくい
エージェントの方のアドバイスを受けて、上記の仕事にはほぼ触れず「業務外の活動やSIerで自主的にやっていたこと」を中心に据えてアピールをしたわけですが、それこそが「求められていたもの」に近いものでした。
それが評価されたことで、無事転職に至りました。
中学生の頃から始めていた業務外でのアウトプットが、転職に繋がりました。つまり、私の転職活動は中学生から始まっていたのです。
めでたしめでたし。
おまけ: アウトプットでの心がけ
私がアウトプットで心がけているのは2点です。
やりたいことをやる
「やらなきゃ(義務感」は辛くなるので、やりたいことをやってアウトプットにしています。
ポイントは「如何にやりたいことを増やすか」です。情報を仕入れたほうがやりたいことが増えるケースもあります。SIerの頃はWEB+DB PRESSやSoftware Designを読んだり、Podcastを聞いたり(Rebuild.fm、Misreading Chat、その他)していました。
最近は現職のメンバから刺激を受けることがめちゃくちゃ多いです。
稚拙でも良いので、正しさとリスペクトを意識する
ブログやQiita記事の場合は、次の2点を意識しています。
- 公式ドキュメントなどで正しさを確認する
- 参考にしたものや引用元を明記する
「巨人の肩の上に立つ」という表現がありますが、それです。
かなり時間を使ってしまうことも多いですが、もっと良い方法を見つけたり、間違っていることに気づいたり、デタラメ記事の作成を避けたり出来るので、メリットは多いです。
さあ、アウトプットを増やしていきましょう。
Fargate Spotのお値段比べてみた
Fargate Spotが発表された.
70%ディスカウントは魅力的であるものの,EC2と比べて高いのか安いのかがわからない.ということで表にした.
タイプ | vCPU | Mem | EC2 オンデマンド |
EC2 スポット |
EC2 リザーブド (1年前払い) |
Fargate | Fargate Spot |
---|---|---|---|---|---|---|---|
m5.large | 2 | 8 | 0.124 | 0.035 | 0.081 | 0.145 | 0.044 |
c5.large | 2 | 4 | 0.107 | 0.033 | 0.072 | 0.123 | 0.037 |
r5.large | 2 | 16 | 0.152 | 0.037 | 0.089 | 0.190 | 0.057 |
※ap-northeast-1(アジアパシフィック (東京)),2019年12月5日(木)23時時点,単位は USD/h
厳密には, C5 は M5, R5 とプロセッサのクロック周波数が異なるし,そもそもFargateのプロセッサシリーズは公表されていない点に注意.
見づらい表になってしまったが,Fargateはメモリ単価が少々高いという印象.
気象庁の天気予報文をパースする ☀☁☂
天気予報文
気象庁の天気予報には 予報文 があります。
北東の風 日中 東の風 くもり 昼過ぎ まで 時々 晴れ 所により 夜遅く 雨
気象庁 | 天気予報 : 東京都 (10/20 11:00発表 21日の天気予報文)
やや難解ですが、 気象庁|予報用語 と照らし合わせることで下記であることが分かります。
時間 | 天気 |
---|---|
0〜15時 | くもり 時々 晴れ |
15〜21時 | くもり |
21〜24時 | くもり 所により 雨 |
天気予報文と正規表現
ここからは根拠のない独自研究です。
文法
気象庁が発表する天気予報文には 文法 が存在し、どの予報文もいずれかの文法にマッチします。以下は例です。
文法 | 例 |
---|---|
天候 | 晴れ |
天候 頻度 天候 | 晴れ 時々 くもり |
天候 時間帯 天候 | くもり 昼過ぎ から 夕方 雨 |
天候 時間帯 頻度 天候 | くもり 昼前 まで 時々 晴れ |
天候 頻度 天候 時間帯 天候 | 晴れ 時々 くもり 夜のはじめ頃 から 雨 |
天候 所により 天候 | くもり 所により 雨 |
天候 所により 時間帯 天候 | くもり 所により 明け方 まで 雨 |
天候 所により 修飾 | 雨 所により 雷を伴い 激しく 降る |
天候 所により 時間帯 修飾 | 雨 所により 夕方 から 雷 を伴う |
天候 頻度 天候 時間帯 天候 所により 時間帯 修飾 | 晴れ 時々 くもり 夕方 から 雨 所により 夜遅く 雷を伴い 激しく 降る |
正規表現
文法を正規表現で表すと、次のようになります(雪 後 雪
などのありえない表現もマッチしますが、今回は無視します)。
(晴れ|くもり|雨|雪|雨か雪|雪か雨|雪 で ふぶく|雨 で 雷 を伴う|雨 で 雷を伴い 激しく 降る)( (時々|一時|後) (晴れ|くもり|雨|雪|雨か雪|雪か雨|雪 で ふぶく|雨 で 雷 を伴う|雨 で 雷を伴い 激しく 降る))?( ((朝晩|朝夕|夜)|(未明|明け方|朝|昼前|昼過ぎ|夕方|夜のはじめ頃|夜遅く)( (まで|から( 未明| 明け方| 朝| 昼前| 昼過ぎ| 夕方| 夜のはじめ頃| 夜遅く)?))?)( (時々|一時))? (晴れ|くもり|雨|雪|雨か雪|雪か雨|雪 で ふぶく|雨 で 雷 を伴う|雨 で 雷を伴い 激しく 降る))?( (所により|[^ ]+ では)( ((朝晩|朝夕|夜)|(未明|明け方|朝|昼前|昼過ぎ|夕方|夜のはじめ頃|夜遅く)( (まで|から( 未明| 明け方| 朝| 昼前| 昼過ぎ| 夕方| 夜のはじめ頃| 夜遅く)?))?))? ((晴れ|くもり|雨|雪|雨か雪|雪か雨|雪 で ふぶく|雨 で 雷 を伴う|雨 で 雷を伴い 激しく 降る)|(雷 を伴う|激しく 降る|雷を伴い 激しく 降る|霧)))?
何を言っているんだという感じなので、擬似的に表現をすると次のようになります。
天候( 頻度 天候)?( 時間帯( 頻度)? 天候)?( (所により|地名)( 時間帯)? (天候|修飾))?
項目 | 正規表現 |
---|---|
天候 | (晴れ|くもり|雨|雪|雨か雪|雪か雨|雪 で ふぶく|雨 で 雷 を伴う|雨 で 雷を伴い 激しく 降る) |
頻度 | (時々|一時|後) ※時間帯の後ろは (時々|一時) |
時間帯 | ((朝晩|朝夕|夜)|(未明|明け方|朝|昼前|昼過ぎ|夕方|夜のはじめ頃|夜遅く)( (まで|から( 未明| 明け方| 朝| 昼前| 昼過ぎ| 夕方| 夜のはじめ頃| 夜遅く)?))?) |
地名 | 気象庁 | 気象警報・注意報や天気予報の発表区域 の「市町村等をまとめた地域」に準じる |
修飾 | (雷 を伴う|激しく 降る|雷を伴い 激しく 降る|霧) |
※「雪 で ふぶく」等は修飾が入っていますが、簡単のために天候にまとめています。
※カバー出来ていない天気予報文が存在する可能性があります。
テスト
下記サイトで試してみるとマッチします。
天気予報文とパーサ
正規表現のままパーサを書くのはつらいため、より簡単にして概ね次のルールでパーサを書きますました。
- 入力は予報文、出力は0〜21時の3時間ごとの予報
- 「時間帯」「所により(地名)」「何もない(終端)」が出現した場合に分割
- 「所により」「頻度」が含まれる場合は予報を追記。それ以外は指定時間帯の予報として上書き
動作
$ ruby runner.rb 天気予報を入力: 晴れ 時々 くもり 夕方 から 雨 所により 夜遅く 雷を伴い 激しく 降る 解析結果: {:wind=>nil, :weather=> {0=>"晴れ時々くもり", 3=>"晴れ時々くもり", 6=>"晴れ時々くもり", 9=>"晴れ時々くもり", 12=>"晴れ時々くもり", 15=>"雨", 18=>"雨", 21=>"雨所により雷を伴い激しく降る"}} 天気予報を入力: 北東の風 日中 東の風 くもり 昼過ぎ まで 時々 晴れ 所により 夜遅く 雨 解析結果: {:wind=>"北東の風 日中 東の風", :weather=> {0=>"くもり時々晴れ", 3=>"くもり時々晴れ", 6=>"くもり時々晴れ", 9=>"くもり時々晴れ", 12=>"くもり時々晴れ", 15=>"くもり", 18=>"くもり", 21=>"くもり所により雨"}}
3時間ごとの天気予報がわかるようになりました。めでたしめでたし。
同じ構図で何枚も撮って,最も手ブレしていない 1 枚だけを残す
結論
- ImageMagick の
compare
コマンドで, Perceptual Hash (pHash) により同一構図かチェックする. - ImageMagick の
convert
とidentify
コマンドで, Canny 法によりエッジ検出し同一構図の n 枚から最も鮮明な 1 枚を残す. - ソースはここに置いた: GitHub - typewriter/unblurred-photo-picker
背景
手ブレしたくないが, ISO 感度もあまり上げたくない(綺麗に撮りたい).その場合,ギリギリのシャッタースピードで何枚も撮る,ということをよくやります.しかし,撮影後の写真の選別が極めて面倒なうえ,かなり機械的な作業です.
機械的な作業… ということは機械で出来るのではないでしょうか.やってみました.
同一構図の判定
同一構図の判定は,画像の類似度が高いかどうかで行うこととします.ただし,画像処理はさっぱり分からないため, ImageMagick に全力で甘えます.
ImageMagick には compare
コマンドがあり,お手軽に画像比較を行うことが可能です.
画像比較に使用できるメトリクスの一覧は ImageMagick - Command-line Options#-metric type にありますが,今回は PHASH (Perceptual Hash) を用います.
# ImageMagick 7 系.小さいほど類似度が高い. $ magick compare -metric PHASH P9240031.JPG P9240035.JPG NULL: 13.7601
Perceptual Hash ではハミング距離を取って類似度とする例を見かけましたが, ImageMagick の数値はそうではないようです.まあ気にせずいくつかの画像で試してみます.
画像1 | 画像2 | 備考 | 出力値 |
---|---|---|---|
同じ構図 | 0.501766 | ||
少し下に向けた | 8.26181 | ||
別構図 | 39.5355 |
同一構図では数値が小さく,異なる構図では数値が大きくなりました.使えそうです.
「最も鮮明な」写真の判定
やはり画像処理はさっぱり分からないため,こちらも ImageMagick に頼ります.
当初は「標準偏差 (Standard deviation) が大きければ値のバラつきが大きい→鮮明」と考えていましたが,手ブレした写真のほうが標準偏差が高いケースが複数枚でみられたため不採用です.
$ magick identify -format "{ \"Kurtosis\": %[kurtosis], \"StandardDeviation\": %[standard-deviation], \"Skewness\": %[skewness], \"Entropy\": %[entropy] }" 20171104_PB040552.JPG { "Kurtosis": 3.04856, "StandardDeviation": 11783.4, "Skewness": 1.91352, "Entropy": 0.760502 }
画像(切り抜き) | 標準偏差 |
---|---|
11783.4 | |
11899.3 |
代わりに, Canny Edge Detection でエッジ検出した結果の標準偏差を用いることにします.
$ magick convert 20171104_PB040552.JPG -canny 0x1+10%+30% edge.png $ magick identify -format "{ \"Kurtosis\": %[kurtosis], \"StandardDeviation\": %[standard-deviation], \"Skewness\": %[skewness], \"Entropy\": %[entropy] }" edge.png { "Kurtosis": 13.5456, "StandardDeviation": 14823.4, "Skewness": 3.94279, "Entropy": 0.303514 }
画像(切り抜き) | エッジ検出後(同左) | 標準偏差 |
---|---|---|
14823.4 | ||
11678.3 |
良さげな感じになりました.
スクリプト
Rubyで書きました。裏でImageMagickのコマンドガンガン実行します。
参考
*1:バックアップも兼ねているのでアップロードはしている
日用品のストック管理ツール Stokk を作った
日用品のストックを管理出来るツール「Stokk」を公開しました。
以下はポエムです。
技術選定
- サーバをわざわざ建立するほどの機能はない
- mBaaSと親和性が高そう
- フロントエンドを書きたい
ということで、SPA + mBaaSで作ることにしました。
使ったもの
- ツール
- 言語
- TypeScript
- フレームワーク
- その他ライブラリ
- mBaaS
ツール: Adobe XD
初使用。無料の「スタータープラン」があり、アカウントさえあればシュッと使えます。
プロトタイプは作らず、ちょっと便利な図形描画ツール程度に使いました。事前にデザインや要件を整理でき、その後データやイベントの流れを練り練りするのにも大いに役立ちました。
言語: TypeScript
JavaScriptを操れる自信はなかったのでTypeScriptで書きました。エディタはVisual Studio Code。
ただ、厳格に型付けをするのは諦めました。動く状態で、「thisはVueだからお前が定義したプロパティなぞ存在せんわ!」などと言われていました。「ぐ、Gradual Typingだから…」と意味不明な言い訳をしつつキャストしたりanyにしたりしました。
フレームワーク: Vue.js + Vue Router, Bootstrap + BootstrapVue
ふわっと書きたかったのとReactは仕事で書く機会があるのとでVue.jsにしました。Vue CLIでTypeScriptも含めて一括で初期設定でき、とても楽でよいです。
デザインは安定のBootstrap。BootstrapVueも入れましたが、「BootstrapのListってBootstrapVueでどう書くんだっけ」と毎回マッピングしつつ書いていました。効率的に書けたかは分かりません。
その他ライブラリ: Lodash, Font Awesome
Lodashはdebounceに、Font Awesomeはアイコンに。
mBaaS: Cloud Firestore, Firebase Hosting, Firebase Authentication + FirebaseUI
作るサービスと親和性高そうなので全面的に依存しました。
FirebaseUIについては、 Firebase 6.6.1 と FirebaseUI 4.2.0 でドキュメント通りに書いたつもりで動作せず(firebase.auth()
と書くとfirebase
がないと怒られる)。
メジャーバージョンを1つ落として FirebaseUI 3.6.1 を使用することで落ち着きました。何故なんだ。
そのほか
命名: Stokk
当初「にちまね!(日用品在庫マネージャ)」で けいおん!風にしようと思っていました。が、サブドメインを割り当てるタイミングで nichimane
は無いな… と思って在庫(stock)を意図的に誤字らせました。
アニメーション
「動いているんだけど動いている感がない」という印象を受けたため、「小気味よく動いている」感を演出するべくアニメーションを設定しました。
- アイテム追加、削除、並び替え時
- 読み込み・保存時(スピナー表示)
ソースコード
ページの好き嫌いを学習・分類するChrome拡張を作った
ネタです.
ベイジアンフィルタで,ページの好き嫌いを学習・分類するChrome 拡張機能を作りました.
動作サンプル
ページが自分好みかどうかベイズ推定するやつ、Chrome拡張に昇華させた pic.twitter.com/RIsdR3ReMg
— たいぷらいたー (@no_clock) 2019年6月29日
構成
学習・分類サーバがあり,Chrome拡張はそのクライアントとして機能します.
全文ではなくURLを送っているのは,認証が必要なエリアのコンテンツをうっかり学習させないためです.学習データに個人情報が混ざっているとか怖くて扱えない.
学習・分類サーバ
- 考えるのが面倒だったので GCE (Debian 9), nginx, Ruby, Sinatra, Unicorn
- ベイジアンフィルタとして jekyll/classifier-reborn ,日本語の分かち書きにはMeCabとIPA辞書を使用
ソースファイルと利用方法
Chromeウェブストアから拡張機能を追加するか,上記リポジトリをcloneしてデベロッパーモードで拡張機能を読み込んでください.
URLがサーバに送信されますので,気になる方は自前でサーバを立ててください.
Oracle Code Cardを触ってみる (触っただけ編)
Oracle Code Cardという謎のカードを譲ってもらった.「イベントでもらったけど使わない」「ボタン電池が高い(500円)」という情報も付属していた.
観察
赤い基板に電子ペーパーが載っている.イベントで配布するにしては贅沢だ.いくら掛かっているんだろう.
裏面には「Live for the Code」との記述がある.
ボタン電池のホルダがあるが,LIR2450 3.6V,という珍しい電池のようだ.なんと RECHARGEABLE の記述がある.充電池.
よく見ると,ESP-12Fチップが搭載されている.これはArduino互換のような気がする.調べてみるとどうやら確からしい.
あっちこっちのページを探索していると,USB-シリアル(UART)変換チップも載っていて,シリアル接続で通信出来るとのこと.確かに載っている.
というか,リポジトリがある.
通信
リポジトリの記述に従って接続し,スイッチON/OFFを切り替えたが何も起きない.
Aボタンを押すと,どうやらWi-Fiに接続しようとしている旨のメッセージが流れる.Type 'help' for more info.
と表示されるが,直後にシャットダウンしていて反応はない.
詰んだ,と思った.とりあえず適当にA/Bボタンを同時押ししてみた.
…すると,なんと当たりだったようで,電子ペーパーにORACLEのロゴが現れた後,シャットダウンしなくなった.
そのままhelpと入力すると,期待通りヘルプが出てきた.うまくいったようだ.
さて,どう調理しようかな.つづく.