エンジニアは業務時間外に勉強すべきかの話
他社社長が盛り上がってるみたいなんですが、そこの言説だけが広がっていってもアレだなぁと思ったので、単に自分がやってきた経験値とかを書いてみた。銀の弾丸欲しい。
お前誰よ
- 零細ITシステム会社経営
- 従業員5人、エンジニア数だと6人(私自身が含まれる)
- 会社は設立して4年弱
- 自社サービスを作っているが、今のところの収益構造は受託・SESが100%
- 10年ぐらい名古屋でコミュニティ活動に関わってきている(ただし、ここ2年ぐらいは忙しすぎて、ほぼ勉強会に行けてない)
色々やってきて至った基本的な考え方
会社という組織を前提とするのであれば「雇用契約」による利害関係で考えるのがシンプル。
- 会社は利益を上げたい
- 利益を上げる手段としては、良いエンジニアが必要(それだけではないが、この話題の本筋ではないので割愛)
- 良いエンジニアを育むには学習が必要
目的は利益であって、エンジニアの勉強は手段。エンジニアが勉強すべきかみたいな話をしたら、そりゃあ、「エンジニアである以上は生涯学習すべき。ただし、プライベートに勉強を強制させるの(無償労働)はあかん」という一般論にしか終着しない。
「かくあるべき」という話にせず、人事評価(賃金)の話にするのが分かりやすくなる。
- 業務を遂行する上で必要最低限の教育を、賃金を支払ったうえで行わなくてはならない
- 賃金が発生する以上、学習成果が上がっているかを人事評価に反映させることは正当となる
- エンジニア個人の学習成果が収益に直結するのであれば賃金に反映し、新たな事業展開に繋がるような場合はプロジェクトメンバーに抜擢するとか、人事的な面で評価する
これを前提に、会社としてはこういう技術が欲しいとか、こういう人材が不足しているということを伝えて、賃金に反映させる。賃金に繋がるとなれば、学習意欲に繋がって資本主義ヤッターとなる。
当然ならない場合もあるが、賃金に反映されない理由としてはわかりやすい。賃金を払うための収益が改善されないだから、割増する理由がない(これも単純化しすぎたらあかんところではあるけど、割愛)。
強制される勉強の成果は上がらない
サラリーマンプログラマーの時代には、こういうことをやっていたがうまくいかなかった。
会社を作ってから、ある程度の選別をして採用を行ってきているが、すべてのケースにおいて合格点となることはない。そのため、社員教育はやるしかないという意識で取り組んできている。ただ、正直なところ、期待する成果は上がっていない。
振り返ってみて、
- 本人に興味・素質がある領域や教育を行いやすい領域は伸びるが、そうではないところはほぼ伸びない
- 期待値が高すぎた
という、当たり前だよねという思いに至っている。
「強制される勉強」というのは「本人に興味がない」とか「学習成果が上がってるように感じない」というところから来るものかと思う。
「本人に興味がない」ケースで、人事評価で釣れないのであれば、これ以上は会社からインセンティブを与える手段はない。ただ、本人に聞いても「やる気はあります!」みたいな答えしか当然出てこないので、外部から「やる気」を評価することはできないように思う。
「学習成果が上がってるように感じない」については、学習カリキュラムやゲーミフィケーションなど、改善余地はあると思う。自社に対してだけ考えると、正直私の力不足(時間不足)感が強いので、やり方を見直さないといけないなぁとは考えている領域にはなっている。 ただ、学習成果の面において、「マニュアル化」「自動化」については、成果が見えやすいと思っている。マニュアルには即効性のある内容が書かれている。自動化は厳密には学習ではないのだけど、そもそも覚えなくてもよい状況にすれば、成果はあがる。
まとめる
割と殺伐としたまとめになるが、雇用契約に基づいて、システマティック・資本主義的に考えるのが素直だと思っている。
端的に「エンジニアは業務時間外でも勉強すべきか」という問いに対して、経営者としての立場の回答は「強制は逆効果になるからNG、インセンティブを明示して社の要望を伝えることは必要」となる。
- 期待しすぎない
- ある程度の誘導はできるにしても他人が自分の期待通りに動くわけがないし、銀の弾丸もない
- 高すぎる期待値は精神衛生上良くない結果になりやすい
- マニュアル化、自動化等の属人性が排除できる部分を対処していくことで底上げを図る
- プライベートでの勉強の有無に関係なく、会社の利益につながる人間(端的に業務遂行能力の高い人間)を人事的に評価する
社員のやる気を上げる手段は色々提供することは可能だけど、最終的には、やる気とかいうのは運要素だと考えた方が良い。そういう人が採用できるとも限らないし、興味分野はコロコロ変わるし、ゲームやりたくなったりするし、結婚したりとかで状況は常に変わる、人間だもの。
追記: 「期待しすぎない」は「地に足をつけろ」「着実にやれることをやる」みたいなニュアンス。
おまけ
うちは就業規則をGitHubに公開しているので、エンジニアの勉強に関連する制度の現時点の評価を書く。
EmployeeHandbook/005_福利厚生規程.md at master · DenkiYagi/EmployeeHandbook · GitHub
- 書籍購入補助
- セミナー補助(勉強会参加補助)
- 年に数回程度しか使われていない。これは社員が近場の勉強会に行く頻度が高いので、単に費用が発生しない等の理由と思われる。
- 有償セミナー・トレーニング等については今のところ実績がない。行きたい・行かせたいという具体的なところまで決まりきってないだけ。
その他、社員から機械学習ぶん回したいからサーバーと空調をどうにかしてくれみたいな要望が上がってきたが、マニー・設置スペースの両面で都合がつかなかったので、直近は見送りになっている。
Spring Bootで実装した認証付きWeb APIで異なるAPIのレスポンスが返される問題
発生していた問題
- 未ログイン状態で、認証が必要なWebAPI-1にリクエスト
- HTTP 401が返される
- ログイン
- HTTP 200 ログイン成功
- レスポンスボディなし
- WebAPI-2(1とは異なるAPI)を呼び出す
Spring Bootのバージョン
- Spring Boot 1.4.2
- Spring Security 4.1.3
原因
問題が発生するパターンのSpring Securityの設定は概ねこんな感じ。
public class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter { private static final String URL_PATTERN = "xxx"; @Override protected void configure(final HttpSecurity http) throws Exception { http.regexMatcher(URL_PATTERN) .formLogin() .successHandler((req, res, auth) -> res.setStatus(HttpServletResponse.SC_OK)) .failureHandler((req, res, auth) -> res.setStatus(HttpServletResponse.SC_UNAUTHORIZED)) .permitAll(); http.regexMatcher(URL_PATTERN) .exceptionHandling() .authenticationEntryPoint(new Http401AuthenticationEntryPoint("Bearer error=\"invalid_request\"")); http.regexMatcher(URL_PATTERN).csrf().disable(); } }
また、APIは下記のような実装を行っていた。
- 単一URLにPOST
- HTTP Headerによって処理をルーティング
この環境下で、前述の再現手順を行うと、以下のようなことが発生していた。
対応策
Spring Securityの設定でリクエストキャッシュを無効にする。
public class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter { private static final String URL_PATTERN = "xxx"; @Override protected void configure(final HttpSecurity http) throws Exception { http.regexMatcher(URL_PATTERN) .requestCache().requestCache(new NullRequestCache()); } }
参考URL
http://www.sedooe.com/2016/04/rest-authentication-using-spring-security-and-spring-session/
分散協調サービスのメモ
以前は分散システムの設計をやってたんですが、最近ちょっと離れているので、2017年7月末時点の分散協調サービスについて確認。
- Apache ZooKeeper https://zookeeper.apache.org/
- 相変わらず使われている
- APIが低レベルすぎるので、Apache Curator http://curator.apache.org/ との組み合わせで使う(これも相変わらず)
- Consul https://www.consul.io/
- HashiCorp製
- etcd https://github.com/coreos/etcd
- Goで書かれてるやつ
自分で使うとしたらこの辺りになるかなぁ。あとは用途要件に合わせて、RabbitMQ + Zabbixみたいな組み合わせと比較していく感じ。
DynamoDBがスケールしねーぞの話に関するメモ
You probably shouldn’t use DynamoDB https://t.co/Y8cOEDqgeq 10GB毎にノードが勝手に増えるので分散writeで速度激落ちのDynamoDB,実は全然スケールしないという.巨大データは素直にBigTableを使えと. pic.twitter.com/zh8CRImbz6
— Yuta Kashino (@yutakashino) 2017年7月8日
こういう話が流れてきたので元記事を読んでみたのだけど、そもそもDynamoDBの仕組みを把握してなかったので理解ができなかった。ということで、ざっと調べた結果を、自分(Cassandraをがっつり触ってた経験あり)が後から読んでわかればいいや程度のメモに。
DynamoDBとは
- オートスケールするDB
- データはパーティションに分割されていて、パーティションはパーティションキーを元に特定する
- パーティションとデータ分散 - Amazon DynamoDB
- ストレージ容量ではなくスループットで課金される
- Read Capacity Unit (RCU):1RCUで、1秒あたり最大2回のRead
- Consistent Readオプションを使う場合、2倍のユニットを消費する
- Write Capacity Unit (WCU):1WCUで、1秒あたり最大1回のWrite
- Read Capacity Unit (RCU):1RCUで、1秒あたり最大2回のRead
- パーティションはデータサイズとスループット設定により自動で分割される
- 1パーティションが10GBを超えるか、1パーティションに対し3000RCU/1000WCUを超えるスループット設定がなされた場合に分割
- テーブルのベストプラクティス - Amazon DynamoDB
DynamoDBのスループット設定の考え方の注意点
このスライドを一回読むとよさそう。
端的には、
100,000RCUを持っていたとしても、パーティションが50個あれば、1パーティションあたりのRCUは2,000となる。
で、パーティションキーを元にアクセスするパーティションを特定する性質上、以下ようなアクセスの偏りが生じるケースがある。
元記事の指摘ポイント
言いたいことはわかるけど、DynamoDBの仕組み(課金の仕組み)を考えると、なかなか難しい問題。分散DBは難しい。
IntelliJ IDEAでHiDPI(Per-monitor DPI)対応
Windows 10 Creators Update(1703) + IntelliJ IDEA 2017.1.2 で確認。これで表示がぼやけなくなった。
idea.propertiesで sun.java2d.uiScale.enabled=true
を設定しろということらしい。というか、他にも swing.bufferPerWindow=true
みたいなマルチディスプレイに影響しそうな設定が存在するので、 https://github.com/JetBrains/intellij-community/blob/master/bin/idea.properties をそのまま配置した方が無難な気がする。
idea.properties の設定は、IntelliJ IDEAのメニューの Help > Edit Custom Properties...
から設定する。
ただ、これだけだとディスプレイ毎フォントサイズの微調整が効かないので、エディタフォントサイズを都度変更する方法で対応する。
XPS15 9560を買った
VAIO Z(2015)を使ってきたが、低電圧版CPUのパワーとメモリ16GBでは開発が厳しくなってきたので、XPS15 9560を買った。
買ったのは国内モデルのプラチナ(下位モデル:SSD 256GB, MEM 8GB)だが、
- Core i7 7700HQ以上のCPUで重量・筐体がまともそうな選択肢がこれしかなかった
- 似たようなスペックでさらに安いFRONTER NZシリーズと悩んだが… ノートPC/NZシリーズ(HM175) - BTOパソコン通販のFRONTIER
- SSDとメモリーは換装する前提
- 15インチFull HD
- 上位モデルだと4Kだが、このディスプレイサイズだと確実に持て余す
- どうせメインユースでは外部ディスプレイに接続する
- タッチパネルはあれば便利だが、開発端末にはなくてもいい
- 上位モデルよりバッテリーセルが小さいが、その分は軽い
- Let'snoteも持ってるので、モバイル性を気にする場合はそちらを使う
- そもそもバッテリー容量を気にするユースケース・機種ではない
- VAIO Zのデジタイザ、年に数回しか使わなかった…
- Surface 3とかで十分
といった選定基準でこれにした。
XPS15 9560のクーポン
旧モデルの9550だった頃を含めて3-4か月はクーポンの監視していたが、XPS15の場合では8,000円/15,000円引きクーポンはカス、15%引きはまずまず、それ以上はたまにしか来ないという感じになっている。
ちなみに自分は期末/年初期の17%引きクーポンが来るのを狙って買ったので、約3万円引きの15万弱で購入している。次の高レートクーポンはおそらく夏のボーナス期に出てくると思われる。
換装したSSDとメモリ
Samsung SM961 512GB
同じSamsungの960 ProやPM961の上位と悩んだが、SM961でも実用上は十分爆速で、MTBFの差ぐらいになるので、価格と相談してSM961で十分と判断した。約3万円。
ちなみに、SamsungのSSDの現行モデルについては、 Samsung V-NAND採用NVMe M.2フォームファクタSSDにリテール版 「SSD 960 PRO」と「SSD 960 EVO」が登場 | Ark Tech and Market News Vol.3001037 を参考にした。
PC4-21300 16GB * 2
XPS15 9560標準のメモリモジュールはPC4-19200が搭載されているが、仕様上はPC4-21300まで対応していることがわかったので、これを買った。3万円強。
売り上げランキング: 38,152
コンポーネントの換装
分解の仕方は、この動画を見るのが手っ取り早い。
- コンポーネントの換装を行う前に、USBリカバリメディアを作成する
- 筐体を分解するために、通常のプラス精密ドライバーのほか、星形ドライバー(T-5)が必要になる
- 爪がかみ合っているが結構弱いので、ツールはなくても分解できる。黒いヒンジ側に指がかかるので、動画の通りこちらから引っぺがせば簡単に底面パネルが外せる
ちなみに底面パネルを外すとこんな感じになっていた。画像がぼけているが、中央部にメモリスロット、その左側にM.2スロットがある。
左下には2.5インチ用のマウンタがあり、ここにもドライブを増設できる。ここは97Whrバッテリーセルの場合は埋まっている。
また、左上にはネットワークカードスロットがあり、これも換装可能となっている。
SSDの認識
BIOSでストレージのモードをRAIDからAHCIにしないとSM961は認識してくれなかった。引っかかったのはこれぐらい。
Windows 10 1703(Creators Update)のインストール
ISOイメージをダウンロードしてきて、RufusでUSBブータブルメディアを作成した。パーティション構成をGPTにしないとブート時に認識してくれなかった。
OSをインストールするとWiFiまでは認識してくれたので、あとはWindows Updateから自動でドライバを適用した。 ただ、これではSM961用のNVMe Driverドライバーが不足するので、これだけは自分でインストールした。
Tools & Software | Download | Samsung Memory & Storage
まとめ
分解するため、保障がアレになるが、22万円弱でこんな感じのスペックになった。わーい。
SM961はシステムドライブとして使ってるので、すこしベンチマークが悪くなっているが、それでも爆速には変わりはない。
.NETのORMのことを調べてたメモ
Entity FrameworkとDapper以外にあんまり知らないので、軽く調べてみた。
Dapperのページに他のORMとのベンチマーク比較があった。 github.com
その中で検証してみたいなぁと思ったのは以下の二つ。
そういえばNHibernateとかありましたね。あまりHibernate自体にいい印象を持ってないので存在自体を忘れてましたが、クエリの記述方法の豊富さ・表現力の高さを見て、ちょっと気になった感じ。