求職活動におけるジョブホッパーの3つのデメリット
転職活動をしていたところ、先日次のようなツイートをしてしまいました。
苦渋の選択をし、泣く泣く辞退した内定を後悔しているアカウントがこちらになります。
— ナガモト@Glideエンジニア (@ngmt83) 2019年7月23日
普通こんなことないけど、弱っているな自分。
少し時間をおき、頭を冷やして考えました。すると、何か上手くいっていない、もっと言えば防げたはずのミスを重ねてしまったと気付き、自分への戒めや反省を兼ねてこの記事を書き始めました。
私は職務経歴上ジョブホッパーであることは間違いありません。考えなしに職を変えているわけではないですが、それを他者に理解してもらうことはあまり容易ではありません。 こういった転職を重ねることによる求職活動でのデメリットをまとめます。
前提
- 平均在職期間が1年前後で3社以上の経験があるジョブホッパーに限る
- 社外にまで名の知れた一流エンジニアではない
- エンジニアの採用は明らかに売り手市場
- エンジニアの待遇は年々良くなっている
- 実務経験3年程度までは、転職したほうが簡単に年収が上がってしまう*1
エンジニアとして3〜5年程度経験を積み、シニアエンジニアやリードエンジニアクラスになるべく挑戦していくような状態のエンジニアを想定しています。
求職活動における3つのデメリット
- 求職活動への慣れ・甘えが出る
- 面接が少しマイナスからのスタートになる
- 選考におけるフィードバックサイクルの質が落ちる
求職活動への慣れ・甘えが出る
ジョブホッパーは求職活動の経験が豊富です。それにより上手くなることもありますが、エンジニア採用が売り手市場であることと合わせて悪い慣れ・甘えがでることもあります。 あからさまに出ることはほぼなく、適度な緊張感を欠いて面接に臨んだり、リラックスしすぎて話が冗長になってしまったり、細かいところで悪い影響が出ます。
面接が少しマイナスからのスタートになる
ジョブホッパーに理解があり、面接してくれる企業はあります。しかしスタートは若干マイナスな場合が多いです。ジョブホッパーだから先入観や第一印象が多少悪いという当たり前で言及するほどのことではありません。 面接という貴重な時間を「なぜ短期間で転職を繰り返したのか?」という質問でほぼ確実に消費してしまうがことこそがマイナスです。
この質問は非常にデリケートでネガティブに言いすぎても、いいように表現しすぎて嘘っぽくなってもいい印象はないでしょう。しかも大抵の場合、この質問への回答は減点法で評価されます。*2
良い結果に直結しにくい質疑応答に自己アピールや企業をさらに知るための時間を失ってしまうのはデメリットです。
選考におけるフィードバックサイクルの質が落ちる
選考で落ちた際にはフィードバックを参考にすべきだと思います。しかし、ジョブホッパーへのフィードバックは「自身で環境を変えていく力が不足している」「他責傾向が強い」などといった短期間で転職を繰り返している事実に端を発する内容がほとんどになり、参考にしにくいです。*3
私も採用担当経験がありますが、人に合否を出す行為は非常に難しいです。そのため、判断の理由を言語化する際に純然たる事実である経歴を根拠にしてしまう気持ちは私もわかります。
また、「社風にマッチしない」など具体性のないフィードバックのみの場合、自身で振り返ることがさらに重要になります。しかしジョブホッパーでは「経歴が汚いから落ちたのだろう」という思考停止に陥りがちです。 落選したことを思い詰めすぎても問題ですが、このような思考停止は危険です。
戒めも込めて以下に私の失敗例を列挙します。
私の失敗具体例
- 単なる売り手市場を自分の実力と錯覚し、謙虚さを忘れる
- 大企業とベンチャー企業でほぼ同じレジュメを使い回す
- スカウトを受けた企業と自分からコンタクトをとった企業とを混同する
- 自分からコンタクトをとっておきながら下調べが甘い or 面接当日に情報を忘れる
- 面接可能な日程が少ないため疲弊していてもリスケせず、面接時に集中力を欠く
- 志望度と選考の日程調整が甘く、希望度が近い企業を最初に受けてしまう(内定への回答期日までに他社の選考が終わらない)
- 正直に答えているつもりで不要なことまでぺらぺらと喋っている
- 面接官の話しやすさにかまけてカジュアルに話しすぎる(馴れ馴れしい)
- 同じ質問に対する回答が大きく異なることがある
- 「自分で組織を変えようとは思わなかったのか?」という質問を真に受けすぎる
- 「他責傾向が強い」というフィードバックを受け止めすぎて激しい自己嫌悪に陥る
まとめてしまうと、慣れや甘えがでていたことに、フィードバックから気づくのが遅れ、経歴のマイナスをうまく挽回できていないといったところです。
対策
対策は大きく2つです。
- よくある質問をスムーズに答えられるようにしておく
- 謙虚さを忘れない
当たり前なことですが、転職活動を複数回こなしたからこそ、当たり前がおろそかになってしまいがちです。気を引き締めましょう。
「短期間で転職を繰り返した理由」「自分で組織を変えようとした経験・挫折した理由」くらいは整理してある程度スムーズに答えられるようにしておきましょう。正直に答えることと、事前に整理して決まり文句的に覚えてしまうことは矛盾しません。
また、精神論ではありますが、こまめに「今自分は傲慢になっていないか?」と自身に問いかけましょう。面接では質問にこたえる前に一呼吸置いて「謙虚に…謙虚に…」と心の中で唱えてもいいでしょう。謙虚であれば無理な日程を組んだり、自分からコンタクトをとった企業の下調べが甘くなったりはしないでしょう。
最後に
私の今回の転職活動はひとまず落ち着いてきましたが、今回得た教訓は心に刻んで同じような失敗をしないようにしたいです。
*1: エンジニアの新卒は適正不明で当たり外れが大きいので、雇う側が350~400スタートの気持ちはわかるんだけど、使えるとわかった2年目, 3年目は転職市場で500万〜 600万〜の値段がつくのに短期間で昇給するシステムを持つ会社がないので、転職すると市場価値で是正されるのが転職すると150万上がるの話
*2:「そういう事情があったのなら短期間の転職も仕方ないかもね」「しっかり目的をもった転職であればマイナスな評価にはなりませんよ」といった言葉をかけられることが多い
*3:自身で変える力が足りないのではないか?他責にしすぎなのではないか?などという疑問は何度となく自分から考えているため、他者に抽象的に指摘されてもあまり参考にはならない
Ruby on Rails でDB構造を扱うRidgepole gemにコントリビュートしました
業務でよくお世話になっているRidgepoleというgemにPRを出してマージされたので、その経緯を書き残しておきます。
コントリビュータの証
Distinguish same foreign key constraint on multiple columns by nagamoto · Pull Request #278 · winebarrel/ridgepole · GitHub Contributors to winebarrel/ridgepole · GitHub
どや!(なおdiffはたった1行)
Ridgepoleとは?
複数人・チームで並列して開発を行うとデータ変更が競合したり、内容は競合していなくともschema.rbのversion部分(後述)でやたらとコンフリクトが発生します。そういった問題を解消してくれます。
ActiveRecord::Schema.define(version: 2019_07_18_0000000)
詳しくはこちらのクッ社開発ブログをご覧ください。
コントリビュートに至る経緯
現職で扱うRailsアプリが巨大になり、並列する開発でDB周りのコンフリクト発生が増えてきたため、私が利用経験のあるRidgepole導入を試しはじめました。
最初に次のコマンドでDBからSchemafile作成を行いました。
bundle exec ridgepole -c config/database.yml --export --output db/Schemafile
そして作成されたSchemafileを次のコマンドでapplyしました。
bundle exec ridgepole -c config/database.yml --apply -f db/Schemafile
すると次のようなエラーが発生しました。
[ERROR] Foreign Key `xxx(["xxx", "yyy"])` already defined
このエラーを解消するために調査した結果、コントリビュートするのがシンプルで良い解決方法だと判断し、PRを作成しました。
(Schemafileに外部キー制約が重複して宣言されているというエラーだったため、デフォルト外部キー制約名を付与するオプション--dump-with-default-fk-nameを利用してもエラーが発生しました。)
エラーの再現
わかりやすくエラーを再現したほうがPRの有効性を説明しやすいと考え、シンプルなRailsアプリでエラーとなるケースを再現しました。
ユーザ間でダイレクトメッセージを送信できるアプリケーションを想定します。ERDは次の次の通り。
再現から分析
詳細はPRに書いてありますが、いずれもusersテーブルからdirect_messagesテーブルへの複数の外部キー制約を正しく区別できずに、重複した定義だとしてエラーになっていました。
外部キー制約が重複していないかチェックしている箇所はこちらです。
idx = options[:name] || [from_table, to_table] raise "Foreign Key `#{from_table}(#{idx})` already defined" if @__definition[from_table][:foreign_keys][idx]
見た限りでは外部キー制約はその名前、もしくは制約を設ける2つテーブル名によってユニークであるか否かを判定しているようです。実際の動かしてもそのように挙動であることが確認できました。
変更を加える
コードリーディングとエラーの再現から、ほぼ間違いないレベルで改修する箇所を特定できたため、変更を加えて次のようにしました。
idx = options[:name] || [from_table, to_table, options[:column]] raise "Foreign Key `#{from_table}(#{idx})` already defined" if @__definition[from_table][:foreign_keys][idx]
[from_table, to_table, options[:column]]
により、同じ2テーブル間に複数の制約があってもカラムが指定されていればそれらが異なる制約だと区別できるようになりました。
PRを作る
英語で作成しました。正直この英文にかなり時間がかかりました。
失礼のないように、わかりやすいようにと丁寧に書いたおかげかスムーズにマージしてもらえたので非常に嬉しかったです。winebarrelさんありがとうございます。
最後に
自分には難しいと思っているかもしれませんが、やってみたらOSSのオーナーは優しいし、サクサクことが進むこともあります。 ぜひみなさんもOSSにコントリビュートしましょう!
起業家本田圭佑氏の求人noteから使用技術を想像する
IT業界でも動向を注目されている本田圭佑氏がエンジニアを募集する記事を投稿しました。
彼のイメージを良い意味で裏切られるとても王道な良い記事だと思いました。(語彙が豊富ではないためエモいとしか言えません。)
- 親近感が湧くような失敗を含めたエピソード
- いたずらな横文字を使わず、わかりやすいビジョン・バリューの説明
- 強力なボードメンバー*1
- 成長中毒者というキャッチーな表現
これらは求人noteを書くことがあれば参考にしたいですね。
本題
noteの最下部にエントリー用google formがあったため、使用技術*2を想像してみたいと思います。
※全編想像・妄想の域をでませんのでその前提で読んでください。
最も特徴的なのは Dart
Dartの記載からFlutterを使用する可能性がまずまず高いと思います。 そうでもなければ絞り込まれた言語(技術)の欄にDartは入らないと思います。
スマホアプリがネイティブでない可能性
iOS, Androidと記載されていますが、Swift、Kotlinとは書かれていません。 これが意図的なものだとすると、FlutterによるiOS, Android両対応アプリの可能性もあるでしょう。
採用人数の記載はありませんでしたが、少数であればFlutterの可能性は高まりそうです。 (iOS, Kotlinそれぞれの優秀なエンジニアを揃えるのは簡単ではないため)
早い開発速度実現のためのスクリプト言語
PHP, Rubyの記載があるあたりに開発速度を重視していそうです。実際に採用する言語は集まったメンバー次第で選ぶくらいではないかと想像しています。
スポーツマッチングサービスNow Doを考えた時にパフォーマンスを要求される場面はリリース初期にはあまりなさそうに感じるため、スクリプト言語をサーバーサイドに採用する可能性は高そうです。*3 sportsbull.jp
汎用的なJava
エンジニアの母数が多く、パフォーマンスや堅牢さを考慮するとJavaが記載されるのは自然です。Androidネイティブな側面も含めるとJava経験者に求める能力は多岐に渡りそうです。
しかし実際に最初期のサーバーサイドにJavaを使うのかどうかは疑問です。パフォーマンス・堅牢さを優先するならJava以外にも選択肢がある上、開発速度を優先するスクリプト言語採用の可能性のほうが高いためです。*4
機械学習系の記載なし
最初期であるため記載がないだけかもしれませんが、サーバーサイドにも使用できるPythonの記載がないのは少し驚きでした。 Now Doや他のサービスをリリースしてから、成長してからでもよいと考えているのでしょうか。
総合的にみて
集まったメンバーのスキルセットに依存するとは思いますが、最初期は次のような構成になるのではないでしょうか。
- サーバー: Rails(Laravel)製APIサーバー
- スマホアプリ: Flutter or Swift or Kotlin or PWA (iOSのみ先行リリースもありそう)
- WEB: Flutter Web or ReactなどのSPA
そりゃそうだろという感じの月並みな予想ですみません。 個人的な希望ですが、FlutterとFlutter Webの両採用という攻めた構成を少し見たい気がしています。
フォーム全体の所感
使用技術以外については、有名どころのエージェントやサービスでよく求められる内容でした。 奇をてらうことなく王道をいくのは本田圭佑氏にしては手堅いとは思いましたが、その方がいいよなとも思います。
最後に
起業家本田圭佑氏がどう動くか、どんなサービスができるのか楽しみです。
2019年4~6月振り返り
2019年ももう半分ですよ、新元号令和も2ヶ月が経ちましたよ。時の流れは残酷ですが、振り返っていきます。▓▓▓▓▓▓▓░░░░░░░░ 49%
— Year Progress (@year_progress) June 28, 2019
振り返りの手法はびば(森のフレンズ) (@viva_tweet_x) | Twitterさんが行なっているYWTを参考にしています。*1
3月分までは振り返り記事を書いていたので4~6月分の振り返りです。(振り返りサボんな) ngmt83.hatenablog.com
Y: やったこと
- 習慣化完了
- 週1記事ブログ投稿
- 毎日運動
- write-blog-every-weekに参加
- Glide appsによるアプリ作成*2*3
- アプリ開発進行中
- 現職で大きなプロジェクトほぼ終わり
- 転職活動本格化
- 健康診断結果大幅改善
ブログは2019年皆勤賞、運動は体調不良時の嫁ストップ時のみのさぼりです。習慣化が完了したと言っていいでしょう。ブログはwrite-blog-every-weekに入れてもらってより続けやすい体制が整い、身内みたいなものですがブログを見てくれる人が増えたのは嬉しいことです。アプリ開発も粛々と進めています。
仕事では育休から復帰後初の繁忙期(大きなプロジェクトが佳境)を迎え、真に仕事・ブログ・子育てすべて同時期にコミットできるかを試されました。その時期に転職活動まで被せてしまったため想像以上の多忙さですが、なんとかやれています。とはいえ慢性的な寝不足は感じているため、てきぱきやって睡眠時間を確保することが課題です。
ダイエットの結果がでたことも非常に嬉しいです。健康診断前の絶食(勘違いして20時間ほど食事を抜いてしまった)も手伝って64kg台を記録しました。2018年の最大体重は74kgだったのでとてもいい感じです。
W: わかったこと
- 「ブログを書く時間はある」*4を経験として実感
- 意識を強く持たなければ記事の質が上がらない
- 多忙な時期の転職活動は判断を誤る可能性が高い
- 繁忙期は容易にリバウンドする
ブログを書くことはできていますが、質は上がらないままです。書評は特に全然進みません。
また、先ほどダイエットうまくいってると書きましたが、6月はリバウンドしました。ストレスは食べて解消するタイプなので繁忙期に最大68kgまでまで戻ってしまいました。食事以外の気軽なストレス解消方法か、ローカロリーなストレス解消食を見つける必要がありそうです。
T: つぎにやること(7~9月)
- 習慣の再構築
- アプリリリース
- ダイエット再開
挑戦することを減らし、習慣の再構築とアプリ開発により集中する予定です。習慣アプリで体重計測・運動・ブログは計測しやすく続いていますが、継続できていないものもあるため、以下の通りに見直します。
- 体重計測(毎日)
- 運動(毎日)
- 学習(読書1ページ or アプリ開発1コミット。毎日)
- 早寝(25:00までに就寝。毎日)
- 健康的な食事(高カロリーな間食・おかわりを避ける。週5日以上)
- ブログ(7日に1回以上)
早寝というには遅すぎるとか、健康的な食事というよりは太らないように心がける程度だとかまあ甘い習慣ではありますが、続けることが大事なので最初のハードルは低くいきます。
習慣に関する参考記事
細かいこと考えたりしてますが、要はやるんだよ!やっていき!という感じです。
*3: #write-blog-every-week に入れてもらったのでGlideアプリを作りました。
An app I made with @glideapps from a Google Sheet, without writing any code. https://t.co/sxp20FjLEs
*4:https://speakerdeck.com/kakakakakku/passion-for-blog-mentoring?slide=43
Railsアプリのマスターデータ管理 Seed Fu ベタープラクティス
Railsアプリ開発におけるマスターデータの扱い方は大きく次の3つです。
- 標準機能のseedを利用する
- migrationを利用する
- その他
選択肢で言うとその他になりますが、私は複数の現場で導入してきたのSeed FuというGemをおすすめしています。この記事ではSeed Fuを利用する際のベタープラクティスを紹介します。
おすすめの記法
シンタックスシュガーとして用意されている下記の記法を用いましょう。マスターデータは基本的に静的な値を取り扱うもので、テーブルにレコードとして挿入されることがわかりやすいこの記法がおすすめです。Seed Fuを全く知らない人もすぐ理解してくれます。*1
都道府県のマスターデータを定義する例
Prefecture.seed(:id, { id: 1, name: "北海道" }, { id: 2, name: "青森県" }, { id: 3, name: "岩手県" }, # ~中略~ { id: 47, name: "沖縄県" } )
開発環境用に大量のデータをループで挿入したいときなど、向かないと判断した時は他の記法を利用しましょう。ここでは説明しません。素直にREADMEを読みましょう。 github.com どうしても日本語情報がいい人は以下の記事を参照ください。 qiita.com
変更頻度に合わせた書き方
ほぼ確実に変更がありえず、誤って変更されることを防ぎたい場合はseed_once
で書きましょう。
Prefecture.seed_once(:id, { id: 1, name: "北海道" }, { id: 2, name: "青森県" }, { id: 3, name: "岩手県" }, # ~中略~ { id: 47, name: "沖縄県" } )
こうするとid 1~47で存在しないものにのみinsertが行われるようになります。 (seedの場合は内容が異なるレコードは更新してくれます)
そもそもDBに保存するということは永続化したいけど変更もしたいマスターデータではないのか?という話もあります。プログラム内に定数で持つことも可能ですが、RDBに入れておくとBIツールでデータのみを参照する際にもわかりやすいといった利点もあります。 結局はケースバイケースです。その場に応じた判断をしましょう。
依存関係にあるマスターデータ挿入順序対策
マスターデータで外部キーを持つような依存関係になるものもあるでしょう。例えば都道府県と地方のような関係です。 Seed Fuはファイル名のアルファベット順で実行します*2*3。それを利用して、ファイルのプリフィックスに数字をつけましょう。一番最初に実行する必要があるファイルのプリフィックスは0です。私は同時実行で問題ないファイルも同じ数字を設定します。
地方のマスターデータを定義ファイル(00_areas.rb)
Area.seed_once(:id, { id: 1, name: "北海道地方" }, { id: 2, name: "東北地方" }, # ~中略~ { id: 8, name: "九州地方" } )
都道府県のマスターデータ定義ファイル(01_prefectures.rb)
Prefecture.seed_once(:id, { id: 1, name: "北海道", area_id: 1 }, { id: 2, name: "青森県", area_id: 2 }, { id: 3, name: "岩手県", area_id: 2 }, # ~中略~ { id: 47, name: "沖縄県", area_id: 8 } )
※二桁数字を採用しているのは開発用テストデータと合わせてファイル数が多くなることがあるためです。*4
同一ファイル内に書くことでより直感的に順序を制御する方法もあります。とはいえ、データが増えた時に見通しが悪くなったり、検索性が下がったりするため、私は1modelに対して1seedファイルを作成しています。
Seed Fu Gemを意識せずに実行させる
通常のrails db:seed
コマンド実行時にSeed Fuが呼び出されるように設定しましょう。
db/seeds/seeds.rb
SeedFu.seed
標準的な方法ではrails db:seed_fu
という簡単ですが独自コマンドが必要です。しかし、前述のように標準のseed実行時に呼び出す設定をすることで開発メンバー全員がGem特有のコマンドを覚えずにすみます。
また、この設定をすると標準のseedで管理していたものをSeed Fuに切り替えるときにも、CIやDeployの設定変更が不要になります。 (もともとseedを実行する設定になっているはずのため)
自動テスト実行前に一度だけマスターデータを挿入する
自動テストは副作用をなくす意味でもDBがクリーンな状態で実行されます。*5しかし、マスターデータについては存在することを前提に自動テストを実行したいはずです。 RSpecによる自動テストの場合、実行前に一度だけSeedFu.seedを実行するように次の記述をします。
spec/spec_helper.rb (rails_helper.rbの場合もある)
RSpec.configure do |config| config.before(:suite) do SeedFu.seed end end
自動テストにおいて副作用をより厳密になくすため、Database Cleanerを合わせて利用する場合はこちらの記事がとても参考になります。 blog.inouetakuya.info
Seed Fuを用いたマスターデータ管理ベタープラクティスまとめ
Classi Angular Night #3 参加レポート
先日参加したこちらの勉強会のレポートです。 classi-angular-night.connpass.com ハッシュタグのTLからツイートを抜粋しながらざっくり振り返ります。
イベント概要
本イベントでは、Angularのプラクティス活用事例、Tipsなどを共有できればと思っています。
日本国内ではReactやVueほど活発ではないので、少し貴重なAngularの勉強会です。 (私はAngularが好き)
会場提供はビズリーチさんでした。遅れてきてもスムーズに入館できて助かりました。
遅れたけどスムーズに入れた。運営の人ありがとうございます。#classi_angular_night
— ナガモト@Glideエンジニア (@ngmt83) 2019年6月13日
発表内容
HRMOSにおけるAngularのエラーハンドリングについて
発表者: 杉原 碧志さん (株式会社ビズリーチ)
ご静聴ありがとうございました!
— あおし (@deepblue_will) 2019年6月13日
先程の発表資料です!https://t.co/uQdDUH8Ivm
#classi_angular_night
私は途中参加であまり理解できていませんでしたが、タイトルの通りAngularにおけるエラーハンドリングのプラクティスが詰まった発表だったようです。
会場の声(TLから抜粋)
具体的にハンドリングをするわけじゃなく、ライブラリのエラーをアプリケーション固有のエラーに翻訳するのインターセプター、きれいですね #classi_angular_night
— lacolaco / Suguru Inatomi (@laco2net) 2019年6月13日
Deep dive into Component
発表者: 笠原 渉さん (Classi株式会社)
初〜中級者向けの内容だと感じました。なんとなくで使ってしまいがちなライフサイクルフックについて分かりやすく説明されていました。 また、アプリが大きくなったときに困り始めるであろうパフォーマンスに優しい書き方も、具体的な対策込みで説明されていて理解がはかどりました。
会場の声(TLから抜粋)
ngDoCheck は使ったことあるけど、下手するとパフォーマンスめちゃ劣化するので神経質になる。 #classi_angular_night
— 奥野賢太郎 Crescware (@okunokentaro) 2019年6月13日
constructorはクラスの初期化であって、コンポーネントの初期化(OnInit)ではない、という説明がわかるようになるのは、Angular中級者チェックリスト(なにそれ)のひとつです #classi_angular_night
— lacolaco / Suguru Inatomi (@laco2net) 2019年6月13日
ChangeDetectionStratecyを OnPushにすると、Inputが変わらない限り変更検知がされない #classi_angular_night
— Satoshi Watanabe (@sassy_watson) 2019年6月13日
Upgrade Angular to v8.0
発表者: lacolaco さん
今日の発表資料です!
— lacolaco / Suguru Inatomi (@laco2net) 2019年6月13日
"Upgrade Angular to v8.0"https://t.co/raPAXROXNw #classi_angular_night
先日リリースされたAngular v8での差分をメインに、Angularのリリーススケジュール・アップグレード方法・deprecatedから削除までの流れなど、Angularのアップグレードについてまとめられた発表でした。 まだアップグレード経験が浅い私には非常にありがたかったです。
会場の声(TLから抜粋)
非推奨から削除になるまでは2回って決まっているのか。それだったら非推奨は割とゆっくり対応できるんだ。
— Yoshihiro Kaneko (@tronperidot) 2019年6月13日
#classi_angular_night
dynamic import、loadChildrenのマイグレーションは、v6=>v8だとコードコンバートしてくれなかった
— akihiko.KIgure (@ic_lifewood) 2019年6月13日
v7=>v8だとコンバートしてくれる#classi_angular_night
tsconfig.jsonのcompilerOptionsにstrict: trueを追加した話
発表者: しみきょん さん
今日の資料です!https://t.co/owBeOorvOb
— しみきょん (@shimikyonkyon) 2019年6月13日
#classi_angular_night
具体的な取り組み方も説明されていて、型宣言をおろそかにしがちな私のモチベーションをあげてくれる素晴らしい発表でした。
型安全な世界への導き手だ、いい資料だ!#classi_angular_night
— ナガモト@Glideエンジニア (@ngmt83) 2019年6月13日
会場の声(TLから抜粋)
strict true対応経験者だけど、エラー傾向を精査してログの上から直したりしないのは、めちゃくちゃ賢明ですね。 #classi_angular_night
— 奥野賢太郎 Crescware (@okunokentaro) 2019年6月13日
今日のこの初期値哲学、資料としてかなり貴重。 #classi_angular_night
— 奥野賢太郎 Crescware (@okunokentaro) 2019年6月13日
strict: trueは知らんかった。
— やまひろん@低音エンジニア (@akkiengtw) 2019年6月13日
使うとより型安全になりそうなので使ってみたい。#classi_angular_night
はじめて業務でAngularを使って苦労したこと
発表者: 川上 和義さん
資料は見つけられませんでした。*1
「ng-japanスタッフだけど業務でAngular使ったことなかった」という川上さんが実際に0からアプリを作る中で得た知見が詰まった発表でした。 要領よく要所を解説し、Angular"は"業務"では"使ってなかっただけで、フロントエンドには多くの知見を持っている方ということがひしひしと伝わってきました。
会場の声(TLから抜粋)
quagga(クアッガ)はシマウマっぽい動物の名前っぽい #classi_angular_night
— lacolaco / Suguru Inatomi (@laco2net) 2019年6月13日
Reactive FormはDDDと相性悪くてやってないんですよねぇ。 #classi_angular_night
— 奥野賢太郎 Crescware (@okunokentaro) 2019年6月13日
angularfire2はほんと便利だったな〜
— Yoshihiro Kaneko (@tronperidot) 2019年6月13日
AngularFirestoreをsubscribeすると何も意識せずリアルタイムで更新されるの感激だった。
#classi_angular_night
ちゃんとng-japanを宣伝するスタッフの鑑。 #classi_angular_night
— 奥野賢太郎 Crescware (@okunokentaro) 2019年6月13日
LT枠① Angularチュートリアル2週目を一瞬でやる (筆者のうろ覚えです)
発表者: almirajさん
資料はありませんでしたが、ライブチュートリアルを通してlacolacoさんの言っていたチュートリアルの重要さを体現してくれました。
20190327 - Classi Angular Night #2 - Google スライド
会場の声(TLから抜粋)
Angularかわいいの方だ #classi_angular_night
— shira (@9v9Shira) 2019年6月13日
初心者はチュートリアル2回やらないといけないのかー
— すみや (@sumi0043) 2019年6月13日
まだ一回しかやってないわ
ngrxとngxsでやっぱり作ろうかな。#classi_angular_night
LT枠② Our Track to Modern Angular #2
www.slideshare.net
AngularJS時代からのアプリとどう付き合うか、Angular7.2とのハイブリッドまでどうやって行き着いたかという発表でした。 Angular4以降の整備されたぬるま湯にだけ浸かってきた私は難しさを想像することもできませんでした。
会場の声(TLから抜粋)
AngularJSとAngular8のハイブリッドで無事動いている#classi_angular_night
— shinyanagatac (@shinyanagatac) 2019年6月13日
非常にLT然としたスピーディで内容の濃い面白い話でした #classi_angular_night
— lacolaco / Suguru Inatomi (@laco2net) 2019年6月13日
感想
初参加ですがみんなAngular好き感が伝わってきたし、敷居が高すぎることもなかったし、学びが多かったです。
— ナガモト@Glideエンジニア (@ngmt83) 2019年6月13日
ありがとうございました😄#classi_angular_night
また、次のツイートから察するに毎回神回でおすすめということのようです。
いつもほんと「初心者→中級者」 向けの発表が充実してる品行方正Classi Angular Night 。#classi_angular_night
— 奥野賢太郎 Crescware (@okunokentaro) 2019年6月13日
そういえば
公式にイベントレポートがありました。こっちも見ましょう! www.wantedly.com
*1:上がってたら追記するので@ngmt83に教えてください
AngularアプリにJsBarcodeでバーコードを表示する
↓先日投稿した記事↓の続きです。 ngmt83.hatenablog.com
AngularでJsBarcodeというモジュールを使う方法を紹介します。
AngularからJsBarcodeを使用する方法(基本)
ここに書いてある通りで非常に簡単ですが、Angularに組み込むための手順があるので軽く説明します。
- npm install (yarn add)
- 使用するcomponentでimport
- バーコードを表示するためのhtml要素を用意
- html要素にJsBarcodeを設定
これだけです。簡単ですね。(なのにちょっとハマりました)
サンプルをこちらにデプロイしています。各手順も公開しているコードを添えておきます。
npm install (yarn add)
npm install jsbarcode
説明するまでもなく、モジュールを使うときはたいていこれですね。yarnの人はyarn addです。
使用するcomponentでimport
import * as JsBarcode from 'jsbarcode';
https://github.com/nagamoto/demo/blob/master/src/app/barcode/barcode.component.ts#L3
Generate barcode on Angular2 project · Issue #134 · lindell/JsBarcode · GitHubを参考にimportしました。
バーコードを表示するためのhtml要素を用意
<svg id=fixedBarcode></svg>
https://github.com/nagamoto/demo/blob/master/src/app/barcode/barcode.component.html#L3
今回はsvg形式で表示するため、svgタグを定義しました。また、バーコードを設定する際にセレクタが必要なのでidを指定しています。
html要素にJsBarcodeを設定
JsBarcode('#fixedBarcode', 'fixedBarcode', {});
https://github.com/nagamoto/demo/blob/master/src/app/barcode/barcode.component.ts#L20
第1引数にバーコードを表示する要素を特定するためのセレクタを指定し、第2引数にバーコード化する値を指定します。 componentが初期化される際にバーコードが表示されて欲しいので、ngOnInitフックに記述しています。
軽くハマったポイント
- 動的ページ構築(*ngIfなど)でのNoElementException
- id属性の先頭が数字
動的ページ構築(*ngIfなど)でのNoElementException
アプリを作っていれば、必要なときだけ表示したりしなかったりするのは日常茶飯事です。Angularでは動的にページ要素を構築する場合に ngIf, ngFor, ngSwitchCase などを使います。こういった実装を行うと、タイミングによっては条件判定と要素の描画がなされていないためにJsBarcode('#fixedBarcode', 'fixedBarcode', {});
実行時にセレクタに該当する要素がないという主旨の次のエラーが発生します。
NoElementException: No element to render on.
対策として、前述のエラーを避けるためにライフサイクル・フック*1を適切に使い分けました。安易によく使用するngOnInitを利用せず*2、適切なタイミングに設定しましょう。*3今回は*ngIfの判定が終わり、要素が描画されたタイミングです。そのためngAfterViewInitでバーコード描画処理を実行しています。
https://github.com/nagamoto/demo/blob/master/src/app/barcode/barcode.component.ts#L25
id属性の先頭が数字
id属性の先頭が数字だと、正常に動作しません。そもそも先頭が数字のid属性は認められていないので当然です。List構造で複数のUUID(のような値)をバーコードで表示する際に、バーコードを表示するhtml要素のid属性をユニークにするため次のようにUUIDを流用し、この問題に遭遇しました。
html例
<svg [id]="uuid" class="barcode"></svg>
ts例
JsBarcode(`#${this.uuid}`, this.uuid, {});
UUIDは数字を含むため、たまに数字が先頭の文字列になります。そのときのみエラーが発生します。先頭が数字のid属性は認められていないというのは初歩的な話ですがうっかりしていました。対策として適当なプリフィックスをつけて解決しました。当たり前ですがidは先頭が数字になる可能性がないか確認しましょう。
最後に
Angularはv8もリリースされ、とても便利なのでぜひ使ってみてください。私はv9でIvyが正式リリースされるのが楽しみです。
*1:https://angular.jp/guide/lifecycle-hooks
*2:自分に言い聞かせています
*3:Angularライフサイクル・フックの参考資料: https://qiita.com/tomonari-t/items/3fd6d3c30b6b007b0f14