読者です 読者をやめる 読者になる 読者になる

Hack The Environment

文系出身エンジニア / Work at Shibuya

go言語を学び始めてみた

go言語を学び始めました。
最近専らクライアントサイドの開発がメインだったので、サーバーサイドやりたくなったので、徐々に浸透してきたgoについてキャッチアップはじめました。

環境構築

環境

エディター

goのインストール

とりあえず自前のPCで動かす環境を簡単に構築します。

$ brew install go
$ go version
go version go1.8.1 darwin/amd64

atomの設定

goを書くにあたってエディターもろもろ調べましたが、どうやらatomでのgoの開発環境構築がイケている感じを受けたので、atomでgoの開発環境を構築します。

Package

go-plusをどうさせるためにgoに依存パッケージをインストールする必要があります。
※ go-plusのドキュメントに記載してあります。

goではrubyのgemのように簡単にgoのパッケージを管理するインターフェースが用意されています。

$ go get ~

コマンドでgoのパッケージをローカルの環境にインストールできます。
普段は、ドキュメントに書いている順序でコマンド打ち込んでいくのですが、めんどくさいのでshellスクリプトを書いて一括でインストールさせます。

#!/bin/sh

#go-delveをbrewで入れる
$ brew install go-delve/delve/delve

$ go get -u golang.org/x/tools/cmd/goimports
$ go get -u golang.org/x/tools/cmd/gorename
$ go get -u github.com/golang/lint/golint
$ go get -u github.com/sqs/goreturns
$ go get -u github.com/nsf/gocode
$ go get -u github.com/alecthomas/gometalinter
$ go get -u github.com/zmb3/gogetdoc
$ go get -u github.com/rogpeppe/godef
$ go get -v github.com/golang/lint/golint

完了したら、atomで上記go-defgo-plus の2つのパーケージを入れます。

GOPATHを設定する

packageをインストール後、atomを再起動すると、 liter-golint のパッケージのところでエラーが発生します。
これはGOPATHを設定していなかったことが問題で、GOPATHを設定し、packageの設定画面のGOPATHに設定したGOPATHのパスを入力します。 GOPATHを設定しないと、goでインストールしたライブラリが正常に動作しません。

GOPATHは適当に決めていいらしいので、今回は ~/.go にGOPATHを設定しました。
設定方法はPATHを通すだけなので、bashrc or zshrc にGOPATHのパスを追加します。

$ emacs .zshrc

# GOPATH を追加
export GOPATH=$HOME/.go

# シェルを再起動
$ source .zshrc

atomの設定画面から「パッケージ」を選択し、go-plusの設定画面のGOPATH項目、 ~/.go を入力します。 これでlinter-golintのエラーは解消され、atomでgoを書く上で最低限の設定は完了しました。

GOPATH設定のところで少しハマりましがが、Goの言語仕様を説明した入門本もさくっと読んだので、コツコツ開発始めていこうと思います。

書評『なぜ、あなたの仕事は終わらないのか スピードが最強の武器である』

『なぜ、あなたの仕事は終わらないのか スピードが最強の武器である』を読んでみての感想。
新卒時代に、当時の上司から口酸っぱく言われていたことが全て書いてあり、当時の上司はこの著者の言っていることを指して指導してしくれていたのだとここに来て気づきました。

書籍そのものは、厚みの割に文字が大きくさっと読み流せるボリューム感です。
著者が伝えたいことは一冊を通して同じで「スピードが最強の武器である」ってことだけです。
それを色んなエピソードや仕事の仕方を交えて解説しています。

多分読む人によっては拍子抜けするかもしれません。
とは言え、同じエンジニアとして、仕事をする上で改めて大事だと思うことも書いてあったのでまとめてみました。

書かれていた内容

  1. 納期を守ること
  2. 時間を守ること

の2つです。これは著者も色んな言葉で書いていましたが、僕が感じたのは、一冊を通して、ほぼこの内容しか言っていないということです。
多分この2つさえ、ちゃんとできるようになれば、意味不明な飲み会のルールなんか覚えなくてもいいと思います。

この本に書いてあるのは、大事なことは上の2つで、それを常に実践するためにはどうするかのスタンスが書かれているのみです。
中でもしきりに書かれているのは、 仕事全体を2:8に分け、最初の2割の日程で仕事全体の8割を終わらせる ってこと。

このセンテンスは頻出で、それだけ大事なことで、著者である中島さんのキャリアは全て上記のスタンスに集約されているのでしょう。

もちろん、今の立場にあるからこそできる内容(ex 昼寝の仕方 etc…)もあって全てが全て実施できるわけではありませんが、もし、仕事の仕方として自分で納期を切れる、もしくは納期を明確に伝えられている場合は、参考になる内容がかなりあると思います。

とりあえずやってみて、肌感覚掴んでから一旦報告して、納期までに終わりそうか確認する。
とはいえ、これって案外難しくて、やはり任された仕事である以上、1人でやり遂げたいし、周りに相談したり、ましては納期を変更するなんて、自分の無能をさらけ出しているみたいでかっこ悪くてしづらいと思います。
自身にも似たような経験がありますし、それで迷惑かけたこともあります。
でも、結局仕事は自分1人でしているわけではないので、そこはちゃんと伝えるべきなんですよね…(自戒も込めて)

報告が遅くて困ることはありますが、報告が速くて困ることはまずありません。

書籍の内容は平易で、エピソードもなかなかわかりづらいところもありますが、これは社会人歴浅い自分みたいな年代の人にはぜひ知ってほしい内容です。
仕事の仕方は組織や社会のルールに染まる前の方が矯正し易いです。

個人的に印象に残ったこと

約束の納期を常に守り続けていれば、自分より高い能力の人間よりも上に行ける。 と触れられている内容の箇所です。
約束を守ること = 信頼 を勝ち取ることであって、スキル上優秀だから信頼できるわけでなく、セルフマネジメントまでできて、常に予定通りに成果を出してくる、または早いタイミングで予定の変更を依頼してくる方の方が、信頼感がある、なんて当たり前のことのようですが、それが実は仕事の全てではないかと。
仕事は結局、人と人の関わりの中で行われることである以上、スキルセットは優秀でも、人として信頼できるかどうかが最終的な意思決定にもっとも効いてきます。
そして、信頼されて任された仕事 = キャリアなので、信頼される人の方がキャリアアップにつながっていく。

もちろん、有無を言わせない天才的なスキルセットを持っている人間はいるので、そういう人間には勝負しても勝てないかもしれませんが、とは言え、そういう一握りの人間と勝負するよりも、凡人同士の中で勝負する中で、いかに相手より信頼されるか、どう差別化して、少しでも上に行くのか、ってことの方が自分にとっては身近な内容で、再現性が高いです。

どう活かしていくか

とは言え、最初の2割の日程の中で普段の10~20倍の生産性で業務にとりかかるなんて凡人には無理ですよね。
著者の中島さんも凡人みたいな事欠かれますが、僕から見たら十分天才の部類です。

なので、実践で活かすとするならば、プロトタイプを作るってところから始めようかなと。
そして、日程の算出の仕方とスケジュールの組み方。
現在、あまり納期が明示されることはありませんが、その場合、仮納期を設定して、どれくらい終わるのかってところ、仮納期を設定して一気に作業することで、自分が躓いているポイント、時間がかかっているポイントを洗い出して、予め潰す、もしくは、部分的に変わってもらう、アドバイスをもらいやすくするなど、色々方法は考えられると思います。

あくまでゴールは時間、納期を守ることで、少しずつ回していくのはその訓練にすぎません。少しずつやっていけばそのうち慣れて行くと思います。

まとめ

書籍はHowToを謳っていますが、書いてあるのは、即実践で使える具体的なHowToではなく、どちらかというと、スタンスや意識、考え方の側面が強いです。

納期と時間は守るもの、そういう風に最初に決めてしまえばいいのだと思います。
そうすれば、「どうすれば納期を守れるのか▷とりあえずやってみて報告しよう」といった具合に仕事のやり方に行き着きます。

こんな時期なので、フレッシャーズの皆さんには一読してほしい本かと思います。

MacOSをアップデートしたらbrew でインストールしたツールが`command not found`になったときの対処

トラブル概要

MacOSX Sierraを2017/04/06時点の最新版にアップデートしたら

$ mysql
mysql not found

になってしまった。

対応した手順

brew list でインストールされているか確認

$ brew list | grep mysql
mysql56
mysql@5.6

入っている…
mysqlの最新版は5.7ですが、現状の業務では5.6を使用していたので、5.6を動作させなければなりません。

※ ちなみにbrew でインストールできるソフトウェアのバージョンは以下で調査できる

$ brew info mysql # インストールできる最新版を表示してくれる。
mysql: stable 5.7.17 (bottled)
Open source relational database management system
https://dev.mysql.com/doc/refman/5.7/en/
Conflicts with: mariadb, mariadb-connector-c, mysql-cluster, mysql-connector-c, percona-server
Not installed

brew doctor で Homebrew の状態を確認

$ brew doctor
Your System is ready to brew

問題ない…

brew uninstall ▷ install で入れ直そう

$ brew uninstall mysql56
Uninstalling /usr/local/Cellar/mysql@5.6/5.6.35... (345 files, 154.7MB)
mysql@5.6 5.6.32, 5.6.34 are still installed.
Remove all versions with `brew uninstall --force mysql@5.6`.
$ brew install mysql56
brew install mysql56
Updating Homebrew...

#中略

Warning: The post-install step did not complete successfully
You can try again using `brew postinstall mysql@5.6`
==> Caveats
A "/etc/my.cnf" from another install may interfere with a Homebrew-built
server starting up correctly.

To connect:
    mysql -uroot

This formula is keg-only, which means it was not symlinked into /usr/local.

This is an alternate version of another formula.

If you need to have this software first in your PATH run:
  echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.zshrc

For compilers to find this software you may need to set:
    LDFLAGS:  -L/usr/local/opt/mysql@5.6/lib
    CPPFLAGS: -I/usr/local/opt/mysql@5.6/include


To have launchd start mysql@5.6 now and restart at login:
  brew services start mysql@5.6
Or, if you don't want/need a background service you can just run:
  /usr/local/opt/mysql@5.6/bin/mysql.server start
==> Summary
🍺  /usr/local/Cellar/mysql@5.6/5.6.35: 345 files, 154.7MB
➜  ~ which mysql
mysql not found

ここで、

To have launchd start mysql@5.6 now and restart at login:
  brew services start mysql@5.6
Or, if you don't want/need a background service you can just run:
  /usr/local/opt/mysql@5.6/bin/mysql.server start

パスが /usr/local/opt/mysql@5.6/bin/ 以下であることに気づく。 Homebrewで入れた場合は自動的に /usr/local/bin 配下に設置されるものだと理解していたけど、ちょっと違う???

とりあえずパスの在り処がわかったので /usr/local/bin 配下にコマンドをコピーする

$ sudo cp /usr/local/opt/mysql@5.6/bin/mysql /usr/local/bin
$ which mysql
/usr/local/bin/mysql

と、ここまで来てコマンドの場所がわかったのなら、PATH通せば終わりじゃね?ってことに気づき、 .zshrcexport PATH=/usr/local/opt/mysql@5.6/bin:$PATH を通し

$ which mysql
/usr/local/opt/mysql@5.6/bin/mysql

と表示されたので完了。

WebViewを使ったHTMLの描画

アプリのTableViewから詳細画面に遷移するインターフェースを考えます。
詳細画面に遷移する時に、HTMLをViewに描画するとき、

  1. URLをLoadして直にwebViewを読み込む
  2. HTMLの文字列をHTMLの段組みに合わせてWebViewで表示する。

参考 How to load a HTML string into a WKWebView or UIWebView: loadHTMLString()

URLをLoadして直にwebViewを読み込む

let webView = UIWebView()
let urlRequest: URLRequest = URLRequest(URL: URL(string: "https://sample.com/XXX")!) // 表示したいページのURL(URLRequest型)
webView.loadRequest(urlRequest)

URLを指定して、UIWebViewで表示させるだけなので、簡単ではあるものの、ページの描画に時間がかかってしまう。 そこで、APIのレスポンスでHTMLの文字列が返ってきたような場合、レスポンスで返ってきたHTMLの文字列をHTMLの段組みでWebViewに表示してみます。

HTMLの文字列をHTMLの段組みに合わせてWebViewで表示する。

QiitaのAPIを例にとって試してみます。
qiitaのAPIのレスポンスは

$ curl https://qiita.com/api/v2/items/97819a1910859a6f2ef9 | jq
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 14941    0 14941    0     0  29195      0 --:--:-- --:--:-- --:--:-- 29181
{
  "rendered_body": "HTMLの文字列",
  "coediting": false
  # 略
  
}

という形で rendered_body のプロパティにHTMLの文字列が返ってきます。
この rendered_body プロパティのHTMLの文字列を取り出してUIWebViewの loadHTMLString メソッドに渡します。

var webView: UIWebView!
let html: String = "rendered_bodyの中身"
webView.loadHTMLString(html, baseURL: nil)

これでHTMLの文字列をWebViewに描画することができます。
以下のような感じになります。

f:id:ema_hiro:20170403161835g:plain

【2017年度版】今年度はどんなこと学んでいこうかなってこと

今日から新年度ですね。
渋谷ではおそらく新卒入社と呼ばれるみなさんが飲み会をしてました。
賑やかでこの時期ならではの華やかな空気感が色んなところに感じられるようになりました。

自身も新卒で社会に出てから4年目になってしまい、世間的ににはまだまだ若造の部類ですが、業界的にはもうおっさんの域に差し掛かってきたので、目下焦りしかありません。
こんな時期なので今年度はどういったことに意識して技術を学習していこうかなとということを備忘録として記録しておきます。

目次

  1. 現状の自分のスキルセットと傾向
  2. 今年度学ぼうと思っていること

現状の自分のスキルセットと傾向

Web系の言語を中心に1からサービスを立ち上げた経験はあり。
サービスをグロースさせた経験 はなし

新卒で入社した会社でかなり幅広く経験させてもらいましたが、一つの言語に特化して深く理解したことはなし。
言語仕様を完璧に理解する前に、サービスを作りながら徐々に覚えていくタイプ。

今年度学ぼうと思っていること

年明けからiOSの開発を続けているので、今年はクライアントサイドの開発の知見を深めようと今のところは考えています。

クライアントサイドは、端末の規格が変わったり、プラットフォームの影響をもろに受けるので、実は避けていた分野でした。
ただ、年明けからクライアントサイドの開発に携わる中で、ユーザーに直接触れる領域の良し悪しって露骨にサービスの成長に直結しているなという当たり前のことに気づくようになってきました。
世の中に浸透しているサービスには何か使っている心地よさや、使わないと行けない、使うことが当たり前だよね!といえる感覚があり、また、そういったサービスはアプリだけで完結せず、アプリを中心としたコミュニティというか世界観まで作り上げているものが多く、実装に囚われない、 ソフトウェアだけに収まらないものづくり をしているなという感覚があります。

ユーザーに価値を届けるってソフトウェアだけに留まらない体験を届けることなのではないかと漠然と考えたいことが、ストンと腹落ちしました。

少し話はそれますが、個人的に考えていたことが2つあります。

  1. バズっているIoTや人工知能といった分野も結局それらは考え方やツールでしかなく、ユーザーにはアプリというインターフェースを経ないと価値を届けられないこと。
  2. サーバーサイドは技術の選択肢は増加してくる一方、インフラ周りの仕組みは自動化されたり、ブラックボックス化されていて、知見を持っていることの技術的な優位性は徐々に薄れてきているようにも感じること。

この2点から、流行りに乗っかったり、今のスキルセットのままいくには漠然とリスクを感じていました。

もともとあるスキルに加えて、ユーザー体験を考えることは、ユーザーの理解、技術の理解、領域の理解、そしてその先にある世界観の理解まで含めて作っていく必要があると思います。

おそらくエンジニアという職業において今後数十年のうちに実際にプログラムを書くことは、人間がやる範囲のことではなくなっていくと思います。
実際、Googleの作っている人口知能はプログラムを書けるようになっているらしいですし、実際にコードを書くということはもはや人間がやらなくてもいいことになりつつあるのかなと。(コード書くのは楽しいですが。)

そんなときに、エンジニアとして何ができるのか、機械に代替できないことはなんなのか、ってことを考えた時、それは体験を作り出し、提供することではないかと一つの仮説を持ちました。
UXを提供する領域、ユーザーに直に触れる領域の知見は今だからこそ身につけるに最適なタイミングなのではないかと。
自分のスキルセットと照らし合わせても、キャリアの幅を増やせるいい機会になると思っています。

今年こそ、何か作りきった!と言えるものを残せるように。

UIRefreshControlの実装でハマったところ

目次

  1. unrecognized selector sent to instance のエラーが出た時
  2. Cannot override with a stored property refreshControl

unrecognized selector sent to instance のエラーが出た時

RefreshControlを使ってSwipe & Refreshを実装しようとした際に、 unrecognized selector sent to instance というエラーが出ました。

selectorに指定したメソッドがないよ

っていうエラーでコードを確認したら、selectorに指定したメソッドがprivate指定してしまっていました。

Selector で指定できるのは public なメソッドのみ。

またこのエラーはコンパイルチェックではエラーが出なかったので、実機で動作させるまで気づきませんでした。

Cannot override with a stored property refresh control

UIRefreshControl は 親クラスである UITableViewController クラスのメンバ変数ですでに宣言されているため、サブクラスでの宣言もオーバーライドもできない。

親クラスに宣言されているので self.refreshControl で当該ViewContollerでのrefreshControlの実装を編集できる

実装としては以下

override func viewDidLoad() {
    super.viewDidLoad()
    
    // UIRefreshControl
    self.refreshControl = UIRefreshControl()
    refreshControl?.addTarget(self, action: #selector("publicなメソッド"), for: .valueChanged)
    self.tableView.addSubview(self.refreshControl!) // viewにUIRefreshControlを追加
}

WebフレームワークにおいてDDDを適用しようとした時の違和感

概要

エリックエバンズの「ドメイン駆動設計」を読む中で、アプリケーション開発に適用する時に感じてきた違和感をまとめてみました。
まだ前半しか読み終えてないので、後半を読んだ際にはまた別のエントリーでまとめようと思います。

レイヤー化アーキテクチャとWebフレームワーク

レイヤー化アーキテクチャ

  • プレゼンテーションレイヤー
  • アプリケーションレイヤー
  • ドメインレイヤー
  • インフラレイヤー

大まかにまとめるとアプリケーションは上記の4つのレイヤーに分けられる。
これを一般的なMVC構造を持ったWebフレームワークで考えると

  • プレゼンテーションレイヤー (View)
  • アプリケーションレイヤー (Controller)
  • ドメインレイヤー (Model)
  • インフストラクチャ (O/Rマッパー/Queue/ログ etc..)

のように大まかに分けることができると思う。

DDDに則れば、

となり、レイヤーに分けることで、責務を分けて凝集度の高い、柔軟なアプリケーションを開発できる。

Webアプリ開発に置いてレイヤー化が曖昧になってしまうのはなぜか

DDDの古典的名著である本書を読むにあたって、事例等が古く、理解が浅い箇所があったため、精読する中で、一般的に使われているWebFWを念頭に置きながら読み進めていった時にFatControllerやドメインモデル貧血症が発症するのかを考えてました。
理想を言えば全てのエンジニアが本著を読んだ上でアプリケーション開発を進めることができれば、そういった問題も少なくなっていくのではないかとさえ考えていたのですが、開発をしていく中で技術的な負債として溜まっていく課題が生まれる原因を少し考察してみました。

  • 開発の質とビジネススピードとのトレードオフなって、開発を優先させて、少なからずSmartUI的な何かを許容しながら開発を進めていた。
  • webフレームワークを一番最初に覚えてしまってドメインを考えずに開発を進めていってしまう。

上記2点が自分が考えついたことで、特に後者については、僕自身開発手法や設計手法を知らないまま、エンジニアとしてのキャリアを始めており、WebFW(Laravel/Rails)からアプリケーション開発に入ってしまっているので、ORマッパーが便利過ぎて、Controllerにビジネスロジックをべた書きしたりとかアンチパターンをひたすら繰り返していました。

なぜ厳格にレイヤ分けされていない状態になってしまったのか考えると、Webフレームワークがすでにレイヤー分けされていると考えていて、DDDに基づいたドメインの隔離やレイヤー化を考えなくなってしまっているのではないかと思います。

余談ですが、PHPを使って開発していた頃は、Controllerにビジネスロジックを書くことはアンチパターンだと念頭に置きながら、拙いながらも、責務を分けようとしていたのですが、Railsを使い始めた時にControllerにバリバリActiveRecordを使ったビジネスロジックが書いてあるのを見たときには軽く衝撃を受けたのを覚えています。ActiveRecordは便利で簡潔にデータベースとのやり取りを書けるので、コードとして局所的には見通しが効くものの、DDDの最初の方で提唱しているレイヤー化、ドメインの隔離には反します。
ORマッパーの機能性が高い現在のWebフレームワークでは、こういったControllerにビジネスロジックを書いても、コードの見た目上ある程度見通しが効いてしまうこともレイヤー分けが曖昧になってしまう原因のように感じます。

DDDを読んでいて感じたWebフレームワークにDDDを適用しようとした違和感

書籍に戻ると、この書籍が書かれた時期にはまだWebフレームワークそこまでが一般的ではなかったのではないかと思いました。
WebアプリケーションというよりはATMみたいなGUI操作をともなうGUIアプリケーションの開発が念頭におかれているのだと思います。
読み進めていくうちに少なくとも以下の点については書籍を読みながら理解することができました。

  • Webフレームワークを使ったアプリケーションとGUIアプリケーションではレイヤー化アーキテクチャの厳格度合いに差があること
  • GUIの方がレイヤー化アーキテクチャには厳格
  • DDDでもFWに依存せずに、DDD適用時に必要になるレイヤーはスクラッチで実装すべきだと提唱している。

そして、自分の感じていた違和感の正体はWebフレームワークにおけるMVCをレイヤー化されたアーキテクチャとして理解してしまっていたことだと気づきました。
DDDの中でサンプルとしてあげられているGUIアプリケーションを開発する際に説明されているレイヤー化アーキテクチャが本来的なMVCで責務が分けれている状態で、WebフレームワークにおけるMVCはそれ自体では厳格にレイヤー化されていないんですね。
インフラレイヤーはまとまっているものの、ドメインモデルの作成は開発者の設計に依存するところが大きい。
Webフレームワークだけしか知らないとドメインの隔離とレイヤー化アーキテクチャという大元を見逃してしまう可能性があるということでした。

参考