2019年1月12日土曜日
「エンジニアのためのマネジメントキャリアパス」を読んで管理職について考えてみた
エンジニアのためのマネジメントキャリアパス ―テックリードからCTOまでマネジメントスキル向上ガイド
を読んでみた。
入社されたばかりの被管理者であるSoftware Engineerから始まり、チームを束ねるTech Lead(TL)、管理職や管理職の管理職、そしてVP of Engineering(VPoE)やCTOなどの役職について、期待される役割や課題などを説明している。ざっくりと昨今のTech界隈の役職を俯瞰するのには最適の一冊であろう。
よくまとまってて読みやすい書籍ではある。ただ、ちょっと身も蓋もない言い方になるのだが、会社の役職なんて同じ名前でも役割が違うので、これを読んでどう活用するかは若干難しい。原著は米国の書籍であるので、当然のこととして、日米の文化的・法律的な差異もあるはずである。技術書のように、これを教科書として絶対視しても意味がないので、著者の界隈ではこういう共通認識で回ってるのだろう、といった参考程度に勉強するのが好ましいのであろう。
一点だけ大きく興味をそそられた箇所があった。
5.1節の「ITスキルの維持」の記述のところである。
管理職に転向した後の技術的知識のアップデートに関する主張であり、これ以上コードを書いても技術力が頭打ちになるラインまでは管理職になってもコードを書き続けよう、ということであった。技術力がしっかりと身につくまでは、管理職としても大成できない。そして上級の管理職になってからも何らかの技術的コミットメントを続けるべきだ、と。この意見はとても正しく思える。
私もソフトウェアエンジニアとしてのキャリアの中で、エンジニアから管理職に転向した方を多く知っている。ほとんどの方は、Mangerに転向したのを機にコーディングを行わなくなる。その結果、例えば20世紀にWindowsアプリの開発を行っていた人が、Windowsアプリのパラダイムのままネットの技術を語ったり、クラウド以前のInternet上でWebアプリを開発していた人が、その価値観のまま、クラウドの技術を捉える、といった状況に多く遭遇した。表面的な知識は間違ってないのだが、「それは根本的に考え方が違うんだよなあ」、と突っ込みたくなる状況である。
もちろん、管理職という立場で時間の許す限りキャッチアップは続けているのだろうが、Webの前後、あるいはクラウドの前後、そしてマイクロサービスの前後といったような大きなパラダイムの変換があるときには、業務を前提に深くコードを書いていない限り自分の中の技術的パラダイムはアップデートできない。プライベートな時間で自分しか見ないレベルのコードを書いたとしても、当然のこととして仕事で向き合うのと理解の度合いは違う。業務外でコミットしているオープンソースがあったり、副業としてエンジニアを続けているのでない限り、どの立場になってもコードを書き続けない限りいずれその人の技術的価値観は時代遅れのものになるのだろう。
ただ、言うのは簡単だが、マネージャ業務をしながら開発業務にもコミットし続けるのはとても厳しい。解決策としては、マネージャとエンジニアを数年おきに、すっぱりとJob Changeするくらいしかないかもしれない。米国ではよく(たまに?)あるとは聞くが、少なくとも日本ではあまり聞いたことがない。もしかしたら今後はこのようなJob Rotationが必要とされるかもしれない。
2018年12月16日日曜日
Golangのfake google searchフレームワークをjavaで書いてみた。その2
その1を投稿したあと、某友人から「CompletableFuture使ったらもっとスッキリできるよ」って情報もらった。なので、それ使って書き換えてみた。
行数もざっくり60行程度まで収まった。
while(true)と終了フラグで乗り切ってた汚い部分がだいぶきれいになった。import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.*; import java.util.function.Supplier; class FakeSearch implements Supplier<String>{ String name = null; public FakeSearch(String name){ this.name = name; } @Override public String get() { try { Thread.sleep((new Random().nextInt(10) * 1000)); }catch (Exception e){ } return name; } } public class CmpGoChannel2 { public static void First(Supplier<String> supplier1,Supplier<String> supplier2) throws Exception{ CompletableFuture<String> future1 = CompletableFuture.supplyAsync(supplier1); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(supplier2); CompletableFuture<Object> future3 = CompletableFuture.anyOf(future1, future2); System.out.println(future3.get()); } public static void main(String... args) throws Exception{ FakeSearch web1 = new FakeSearch("Web1"); FakeSearch web2 = new FakeSearch("Web2"); FakeSearch image1 = new FakeSearch("Image1"); FakeSearch image2 = new FakeSearch("Image2"); FakeSearch video1 = new FakeSearch("Video1"); FakeSearch video2 = new FakeSearch("Video2"); CmpGoChannel2 c = new CmpGoChannel2(); List<Future<String>> list = new ArrayList<>(); First(web1,web2); First(image1,image2); First(video1,video2); } }
public static void First(Supplier<String> supplier1,Supplier<String> supplier2) throws Exception{ CompletableFuture<String> future1 = CompletableFuture.supplyAsync(supplier1); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(supplier2); CompletableFuture<Object> future3 = CompletableFuture.anyOf(future1, future2); System.out.println(future3.get()); }
行数もざっくり60行程度まで収まった。
2018年12月15日土曜日
Golangのfake google searchフレームワークをjavaで書いてみた。その1
Go concurrency patternsで触れられていたGoogle SearchのFake frameworkのコードが非常にすっきり記載されていて感動したので、これをJavaで書いたらどうなるんだろうと好奇心から書いてみた。
まず、Go言語の方のやつを、書き出してみる。
コードの解説はスライドに譲るとして、First関数の中での、return <-c の使い方が素晴らしい。
で、これをJavaで書いてみた。
まず気づいたのが、Javaにchannelに相当する仕組みがなかったこと。JavaのConcurrencyはそんなに人気のあるものではなかったが、そうは言ってもそれなりに使われている実績はあるので、書こうとしてみて「そういや、なかったな」みたいな気付きがあった。
なので、ここは
といった感じで while(true)と終了フラグで乗り切るというちょっと汚いコードで対応した。
このあたりですでに、簡素なコードを書けるというGoの魅了が十分に表れている。
まず、Go言語の方のやつを、書き出してみる。
package main import ( "time" "math/rand" "fmt") var ( Web1 = fakeSearch("web1") Image1 = fakeSearch("image1") Video1 = fakeSearch("video1") Web2 = fakeSearch("web2") Image2 = fakeSearch("image2") Video2 = fakeSearch("video2") ) type Result string type Search func(query string) Result func fakeSearch(kind string) Search { return func(query string) Result { time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) return Result(fmt.Sprintf("%s result for %q\n", kind, query)) } } func First(query string, replicas ...Search) Result { c := make(chan Result) searchReplica := func(i int) { c <- replicas[i](query) } for i := range replicas { go searchReplica(i) } return <-c } func Google(query string) (results []Result) { c := make(chan Result) go func() { c <- First(query, Web1, Web2) } () go func() { c <- First(query, Image1, Image2) } () go func() { c <- First(query, Video1, Video2) } () timeout := time.After(80 * time.Millisecond) for i := 0; i < 3; i++ { select { case result := <-c: results = append(results, result) case <-timeout: fmt.Println("timed out") return } } return} func main() { rand.Seed(time.Now().UnixNano()) start := time.Now() result := First("golang", fakeSearch("replica 1"), fakeSearch("replica 2")) elapsed := time.Since(start) fmt.Println(result) fmt.Println(elapsed) }
コードの解説はスライドに譲るとして、First関数の中での、return <-c の使い方が素晴らしい。
で、これをJavaで書いてみた。
import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; class Web1 implements Callable<String>{ public String call() { try { Thread.sleep(10*1000); }catch (Exception e){ } return "Web1"; } } class Web2 implements Callable<String>{ public String call() { return "Web2"; } } class Image1 implements Callable<String>{ public String call() { try { Thread.sleep(10*1000); }catch (Exception e){ } return "Image1"; } } class Image2 implements Callable<String>{ public String call() { return "Image2"; } } class Video1 implements Callable<String>{ public String call() { try { Thread.sleep(10*1000); }catch (Exception e){ } return "Video1"; } } class Video2 implements Callable<String>{ public String call() { return "Video2"; } } public class CmpGoChannel { public static void First(ExecutorService executor1,Callable<String> callable1, Callable<String> callable2) throws Exception{ List<Future<String>> list = new ArrayList<>(); list.add(executor1.submit(callable1)); list.add(executor1.submit(callable2)); boolean loopDone = false; while(true) { for (Future<String> f : list) { System.out.print("."); if (f.isDone()) { System.out.println(f.get()); loopDone = true; break; } } if(loopDone){ break; } } } public static void main(String... args) throws Exception{ ExecutorService executor1 = Executors.newFixedThreadPool(2); ExecutorService executor2 = Executors.newFixedThreadPool(2); ExecutorService executor3 = Executors.newFixedThreadPool(2); CmpGoChannel c = new CmpGoChannel(); List<Future<String>> list = new ArrayList<>(); Callable<String> web1 = new Web1(); Callable<String> web2 = new Web2(); First(executor1,web1,web2); Callable<String> image1 = new Image1(); Callable<String> image2 = new Image2(); First(executor2,image1,image2); Callable<String> video1 = new Video1(); Callable<String> video2 = new Video2(); First(executor3,video1,video2); executor1.shutdown(); executor2.shutdown(); executor3.shutdown(); } }
まず気づいたのが、Javaにchannelに相当する仕組みがなかったこと。JavaのConcurrencyはそんなに人気のあるものではなかったが、そうは言ってもそれなりに使われている実績はあるので、書こうとしてみて「そういや、なかったな」みたいな気付きがあった。
なので、ここは
while(true) { for (Future<String> f : list) { System.out.print("."); if (f.isDone()) { System.out.println(f.get()); loopDone = true; break; } } if(loopDone){ break; } }
このあたりですでに、簡素なコードを書けるというGoの魅了が十分に表れている。
2018年11月29日木曜日
GraphQLを触ってみた
The better Restとの触れ込みのあるGraphQLを触ってみた。
GraphQLとは何か?
ここ数年、Webではスタンダードとして使われていたRest APIに対する不満から生まれたバックエンドとフロントエンド間の通信規約である。具体的には主に下記のようなものを課題として捉えている。課題1 endpointから返されるデータを全部使わない(Over-fetching)
たとえばユーザのプロフィール画面を作りたくて、/user/profiesのエンドポイントを叩いたとする。大体の場合は、これのレスポンスに含まれるすべてのデータは必要とせずに、一部のデータのみ使うであろう。使われないデータは無駄であり、結果として効率的でない通信のやり取りに繋がる。
課題2 endpointをいくつも叩かなければいけない(Under-fetching)
Over-fetchingと表裏一体ではあるのだが、一つの画面に必要となるデータをやり取りするにも、 user/<id>を叩き、次にuser/<id>/profiles、そして最後にuser/<id>/photosの3つのendpointを叩く必要になることがある。これは一つのendpointから返されるレスポインスでは足りないがために起き、そのため複数のendpointへの通信が過剰に走ることになる。パフォーマンスの観点からは基本的にフロントエンドとバックエンド間の通信は少なければ少ないほど好ましい。
課題3 endpoint作成のコストが高い
endpointを一個作るにはフロントエンド・バックエンド側双方の調整が必要となるため、作成のコストが高い。
Getting started
出だしに書いてあったとおり、本当に10分で雰囲気がつかめる。もしかしたら10分もいらないかも。
実際に作ってみた
GraphQLを推進する会社にApollo社がある。Apollo社が提供するApollo Serverを使うと比較的かんたんにGraphQLを試すことができる。Getting started
出だしに書いてあったとおり、本当に10分で雰囲気がつかめる。もしかしたら10分もいらないかも。
感想
npmで初期化するだけで、playgroundがついてくるのは便利。ただ、ドキュメントが不親切で断片的なコードしか書いてないため、ちょっとした改良をするにも試行錯誤が必要。急がばまわれ的に、まずはapollo serverを使わない素のgraphql.jsなどを触って基礎を先に身につけたほうが良さそう。
2018年10月14日日曜日
Go言語の学習に使った本・サイト
A Tour of Go
定番どころのサイト。一通りのSyntax等は学べるか、サラッと書かれてるので基本を知る以外には情報が足りない感じがある。ブラウザ上でGoの実行環境があるので、スキマ時間に理解を進めるのには役立ちそう
スターティングGo言語 (CodeZine BOOKS) 松尾 愛賀
入門書として良書。C、Java、Pythonなどの経験がある人に向けたGoの入門書。文法を網羅的に説明しつつ、落とし穴となりそうなところをちゃんと解説している。注意点としては全くのプログラミング初心者を対象としてないところ。プログラミング未経験者がいきなり本書を読んでも理解ができる前提で書かれた本ではない。
Go言語によるWebアプリケーション開発
タイトルのまんまGo言語でWebアプリケーション開発をするために必要な知識についてまとめてある本。(読み終わったらまた書く)
Go in Action
Manning者のIn Actionシリーズ。個人的にIn Actionシリーズの大ファンなので、購入したが、これは若干いまいち。In Actionシリーズは、実際的なサンプルを作りながら、その技術セットに付いて学べるのが特徴であるが、本書に関してはGoの理解を進めるのにあまり向いている作りではなかった
2018年9月5日水曜日
メルカリの俺的活用方法
フリマアプリのメルカリ。いろんな使い方があると思うけど、俺が気に入ってる代表的な使い方を紹介してみる。
1. コミック全巻セットを買って、読んで、そしてまた売る。
コミックは場所的に嵩張るので、よっぽど気に入った本以外は家にキープしておく場所がない。解決策としてはTSUTAYAとかで宅配レンタルするとか、漫画喫茶で読むとかあるんだけど、それぞれ微妙な点がある。
フリータイムとか利用すれば、かなりコスパは、個人的にはフリータイム3時間とか6時間とかで集中して漫画を読むのとか楽しめない。一冊読んだあと、ネット見て、またその後、次の巻を読んだり、あいた時間に一冊だけ読んだりと、ダラダラ読むのが好きなので、正直言って満喫に何時間も缶詰するとか若干苦行感ある。家でのんびりと読みたい。
ということで、メルカリとかで漫画全巻セットを買って、自分のペースで読み終わったあとに、またその漫画を売りに出すのが、おすすめとなる。大体の場合、買ったときとほぼ同じくらいの値段で売れるので、手数料+送料がランニングコストとなる。30冊くらいの漫画セットであれば、両方合わせてもせいぜい800-1200円程度である。
2. ゲームを買って、遊んで、また売る
コミックと一緒だけど、ゲームなんかも大体の場合は一度遊ぶと二度とやらないので、遊んだあとサクッと処分できると嬉しい。新作は値段の下落が早いけど、発売後数ヶ月から年単位で時間がたった古いゲームなんかは、コミック全巻セットと同様に大きく値段が下がらないので、だいたい買ったときの値段で売れることになる。ゲームは漫画に比べて小さく、当然送料も安く済むので、ランニングコスト的には更に安く上がる。手数料+送料で400-600円程度で済む。
というふうに、上げてみると、ほとんどシェアリングサービス的な使い方になった。もちろん、店で新品で買ったものをただ売ったり、逆に欲しいものをメルカリで中古で買ったりもしているが、とりわけ個人的には漫画とゲームの使い方が気に入ってる。
1. コミック全巻セットを買って、読んで、そしてまた売る。
コミックは場所的に嵩張るので、よっぽど気に入った本以外は家にキープしておく場所がない。解決策としてはTSUTAYAとかで宅配レンタルするとか、漫画喫茶で読むとかあるんだけど、それぞれ微妙な点がある。
- 宅配レンタル
- 満喫
フリータイムとか利用すれば、かなりコスパは、個人的にはフリータイム3時間とか6時間とかで集中して漫画を読むのとか楽しめない。一冊読んだあと、ネット見て、またその後、次の巻を読んだり、あいた時間に一冊だけ読んだりと、ダラダラ読むのが好きなので、正直言って満喫に何時間も缶詰するとか若干苦行感ある。家でのんびりと読みたい。
ということで、メルカリとかで漫画全巻セットを買って、自分のペースで読み終わったあとに、またその漫画を売りに出すのが、おすすめとなる。大体の場合、買ったときとほぼ同じくらいの値段で売れるので、手数料+送料がランニングコストとなる。30冊くらいの漫画セットであれば、両方合わせてもせいぜい800-1200円程度である。
2. ゲームを買って、遊んで、また売る
コミックと一緒だけど、ゲームなんかも大体の場合は一度遊ぶと二度とやらないので、遊んだあとサクッと処分できると嬉しい。新作は値段の下落が早いけど、発売後数ヶ月から年単位で時間がたった古いゲームなんかは、コミック全巻セットと同様に大きく値段が下がらないので、だいたい買ったときの値段で売れることになる。ゲームは漫画に比べて小さく、当然送料も安く済むので、ランニングコスト的には更に安く上がる。手数料+送料で400-600円程度で済む。
というふうに、上げてみると、ほとんどシェアリングサービス的な使い方になった。もちろん、店で新品で買ったものをただ売ったり、逆に欲しいものをメルカリで中古で買ったりもしているが、とりわけ個人的には漫画とゲームの使い方が気に入ってる。
2018年2月4日日曜日
日経新聞をKindleで読むまでにしたこと
Kindleのフォーマット(mobi)への変換
調べたところ、Calibreというその筋では有名なソフトウェアが存在するようなので、試してみた。
何度か試したのだが、どうやら最近の日経新聞電子版ではエラーが発生するようで、Kindle化するまでに至らなかった。
幸い、Calibreは開発をオープンソースベースで行っているようでgithubにソースが管理されていた。その為、必要な修正をpushし、本家に取り込んでもらうことができた。
Ver 3.15以上であれば日経新聞を無事読み込むことができるので、エラーに悩まされていた人はぜひとも試してほしい
Amazon Web Serviceで自動配信
Calibre本体にタイマー機能がついているので、PCを起動しっぱなしにしておけば、毎日設定した時間に日経新聞を取得し、Kindleまで配信することが可能であるが、現在私はラップトップPCしか使っていないため、毎朝手動で朝刊を取得し、Kindleまでメールで送信する必要があった。毎日のこととなるとこの単純作業も地味に辛い。
はじめはフリー枠を恒久的に用意しているHerokuなどを使いたかったのだが、Calibreの場合は本体をインストールするという作業が必要になるため、Herokuでは技術的にこれを実現できなかった。
AWSならば基本的にはLinuxをそのまま利用できるのでこちらを利用することとした。
まずは一年間のトライアル枠で利用するので料金はかからない。厳密に料金の見積もりを取ってないが、Amazon CouldWatchというこれまたAmazonのサービスを使って朝刊と夕刊の時間を取得する時間だけインスタンスを立ち上げることができたので、トライアル期間を過ぎてもおそらくそれほど多大な料金はかからないだろう。
分かる人にしかわからないレベルの粒度で、AWSの自動配信のためにやったことを書いておく。
1. EC2インスタンスを用意する。Amazon Linux AMIを利用した
2. Amazon Lambdaを利用して、EC2インスタンスを起動するFunction、停止するFunctionを用意する
起動のためのFunction(python2.7)
import boto3
# Enter the region your instances are in. Include only the region without specifying Availability Zone; e.g.; 'us-east-1'
region = 'XX-XXXXX-X'
# Enter your instances here: ex. ['X-XXXXXXXX', 'X-XXXXXXXX']
instances = ['X-XXXXXXXX']
def lambda_handler(event, context):
ec2 = boto3.client('ec2', region_name=region)
ec2.start_instances(InstanceIds=instances)
print 'started your instances: ' + str(instances)
停止のためのFunction
import boto3
# Enter the region your instances are in. Include only the region without specifying Availability Zone; e.g., 'us-east-1'
region = 'XX-XXXXX-X'
# Enter your instances here: ex. ['X-XXXXXXXX', 'X-XXXXXXXX']
instances = ['X-XXXXXXXX']
def lambda_handler(event, context):
ec2 = boto3.client('ec2', region_name=region)
ec2.stop_instances(InstanceIds=instances)
print 'stopped your instances: ' + str(instances)
3. Amazon CloudWatchを利用して、2で作成したそれぞれのFunctionを実行するEventを作成する。
例えば朝刊は午前のJSTのAM2:30に配信されるので、起動をAM2:30、停止をAM3:20にした。
4. 1で用意したEC2にCalibreをインストールする
%>yum update
%>sudo yum install libGL
%>sudo -v && wget -nv -O- https://download.calibre-ebook.com/linux-installer.py | sudo python -c "import sys; main=lambda:sys.stderr.write('Download failed\n'); exec(sys.stdin.read()); main()"
私の場合はcalibreのインストール前に、libGLを手動でインストールする必要があった。
5. 日経新聞をmobi化するためのコマンド、およびそれを自分のKindleに配信するためのコマンドをスクリプト化する。
%>/opt/calibre/ebook-convert '日本経済新聞(朝刊・夕刊).recipe' /tmp/nikkei.mobi --username=<日経のIDとなるメールアドレス> --password=<そのパスワード> %>/opt/calibre/calibre-smtp -r mail.gmx.com --username <送信用のメールアドレス> --password <パスワード> --port 587 -a /tmp/nikkei.mobi <送信用のメールアドレス> <Kindleのドキュメント受付用のメールアドレス> subject
6. 5のスクリプトをcronで実行するよう設定する
35 17 * * * /home/ec2-user/calibre.sh
リファレンス
登録:
投稿 (Atom)