emahiro/b.log

Drastically Repeat Yourself !!!!

go で簡易HTTPサーバー立てる

http.HandlerFuncを使う場合

package main

import (
  "fmt"
  "net/http"
)

func main () {
  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
    w.Writer([]bytes(`表示内容`))
  }
}

if err := http.ListenAndServe(":8080", nil); err ! = nil{
  fmt.Printf("エラー表示")
}

http.Handleを使う

package main

import (
  "fmt"
  "net/http"
)

type AppHandler struct{
  appName string
}

func (h *AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  fmt.Printf(h.appName)
}

func main () {
  http.Handler("/", &AppHandler{appName: "myApp"})
  if err := http.ListenAndSerce(":8080", nil); err ! = nil {
    fmt.Printf("エラー発生")
  }
}

Linterのエラーが発生する

exported type AppHandler should have comment or be unexported (golint)  というエラーが発生。これはキャメルケースの構造体(外部からアクセス可能)なのにコメントが無いよっていうエラー

// AppHandler
type AppHandler struct{
  appName string
}

とコメントをつける

comment on exported type AppHandler should be of the form "AppHandler ..." (with optional leading article) (golint) というLinterのエラーがまだ発生。これはコメントの形式の警告。 構造体名 (半角スペース) 説明 みたいな書き方が必要になる。

// AppHandler アプリケーションに関わる〜
type AppHandler struct{
  appName string
}

というコメントに説明箇所を半角スペースで追加する。

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の言語仕様を説明した入門本もさくっと読んだので、コツコツ開発始めていこうと思います。

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

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

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

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

書かれていた内容

  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フレームワークだけしか知らないとドメインの隔離とレイヤー化アーキテクチャという大元を見逃してしまう可能性があるということでした。

参考

チーム開発する上での前提に関する備忘録

※ 自戒をこめて

チーム開発する上で認識甘かったことがあって、最近反省することが多かったので、備忘録として残しておきます。

開発する上での前提

「開発の前提知識が整わないと生産性高く開発ってできないよね」っていうお話です。

今回反省したのは、技術レベルや実装レベル云々の話ではなく、開発する上で、同じプロトコルで話せないと生産性が上がらないということに気付かされたことです。

問題だったこと

  1. githubを使った開発フローのベストプラクティスを理解していなかったこと
  2. 言語仕様や開発環境(IDE)を息を吸うが如く使えない

issueを交えたgithubのプラクティス知らなかった

  • オレオレコミットログを書かない
  • rebaseやらsquashを使って開発ログをきれいする
  • refsやらfixesやらを使いながらissueを交えて作業ログを綺麗にする

という基礎的なところから勉強し直し。
慣れればどうってことないんですが、、、

言語仕様やら開発環境を息を吸うように使えない

こればっかりは必至に覚えました。
iOS開発のキャッチアップをしているときも、まともに経験のある言語がphprubyだったので、swiftみたいな書き方(scalaなんかに似てる)、言語仕様が慣れずにとりあえずプロダクションコード触ろうと思ったんですが、そもそもの言語仕様を理解していなかったり、開発に際して、xcodeの使い方を調べたりということを繰り返して中々生産性が上がってこなかったので、とりあえず地に足つけてひたすらどういう言語なのかを理解することに重きを置きました。

設計やら、実装やらを考えるにあたって、そもそもその前に前提条件が揃ってないと、全く生産性が上がってこない、もしくは開発速度が遅いというのが明確に見えてしまい、そういったところをサボってきた(言語仕様等々は作りながら覚えていく派だった)ツケが回ってきたような気がします。

レビューで言語仕様レベルで指摘されてたらリファクタリングとかしてても終わらないレビューとかになりそうなので、前提知識覚えるのってすごく大事だと実感。

開発の生産性とは?

これって、お作法も含めた常識を知っている(同じプロトコルで話ができる)同士のエンジニアが集まると、そもそも話している会話のレイヤーが同じだから開発速度が速いっていうことに直結すると感じました。
言語を知らない、前提が同じでないと、そもそも、何を話されているのかという翻訳が必要になってしまって、そこで脳みそのエネルギーが使われてしまい、そもそも、開発に効率よくエネルギーをかけることができない。

だから、そもそもチームとして生産性高いっていうのは、上記あげたような超初歩的なお作法、バックボーンが同じレベルの人間が集まることで、余計なコミュニケーションが発生することなく、結果として生産性高いっていう状態が生まれるのだなと。

そこに全く行き着いていなかったことを反省しつつ、サボらずに1からちゃんと言語仕様、開発のお作法を直していく日々…

Computed Property で for を使った構文を map を使った構文へ書き換える

computed property内でforを使った実装をしていた部分をmapを使ったswiftらしい構文へ書き換えました。

変更対象コード

var isSuccess: Bool {       
    for q in questions {
        if !q.isSuccess {
            return false
        }
    }
    return true
}

変換第一段階は以下

var isSuccess: Bool {   
    questions.map { q in
        if !q.isSuccess {
            return false
        }
        return true
    }
}

このままだと Ambiguous reference to member mapxcodeに怒られる

var isSuccess: Bool {
    questions.map { q -> Bool in
        if !q.isSuccess {
            return false
        }
        return true
    }
}

参考: http://stackoverflow.com/questions/34368958/ambiguous-reference-to-member-map-when-attempting-to-append-replace-array-elem

mapはクロージャーの中で返り値の方を指定する必要がある。 しかしこれでも返り値はBoolなので、返り値の型が違うのでおこらえる。 mapでの返り値はCollection型で返ってくるので、返り値はBool指定しないと行けない。

そこでやりたかった意図は questionsの回答状況が全てSuccessであればisSuccessがtrue ということなので、mapで返されたCollectionの中身が全てtrueである、つまりfalseを含まなければいいというロジックになる。

var isSuccess: Bool {
    let status = questions.map { q -> Bool in
        if !q.isSuccess {
            return false
        }
        return true
    }
    return !status.contains(false)
}

プロトコルでのオプショナルなインターフェースを作る。

Protocolの定義

宣言したインターフェースは継承先のクラス、もしくはプロトコル、構造体で、宣言必須。
とはいえ、必要ないインターフェースは継承先で記述省きたいとも思う。
そこでswiftで使えるオプショナルなインターフェースについて調べてみた。

オプショナルなインターフェース

参考 swiftの公式ドキュメント
https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID267

You can define optional requirements for protocols, These requirements do not have to be implemented by types that conform to the protocol. Optional requirements are prefixed by the optional modifier as part of the protocol’s definition. Optional requirements are available so that you can write code that interoperates with Objective-C. Both the protocol and the optional requirement must be marked with the @objc attribute. Note that @objc protocols can be adopted only by classes that inherit from Objective-C classes or other @objc classes. They can’t be adopted by structures or enumerations.

オプショナルなインターフェースの定義方法

protocol SomeProtocol{

  @objc optional func someMethod

}

@objc修飾子とoptional修飾子が必須 特に@objc修飾子がないとオプショナルなインターフェースは定義できない。

使い所

オプショナルなインターフェースにすれば、継承先のオブジェクトでインターフェースの宣言は必須でなくなる。
クラス設計に寄っては、継承先のオブジェクトで不必要なインターフェースも存在するので、設計を厳格にコードに落とし込む上でも有用。

ただし、このこちらのブログにあるように、optionalにすることで厳格性が失われたり、@objc 修飾子をつけることで、swiftの良さがなくなることもあるので、導入には議論が必要になりそう。

既存のコードの書き換え時には使えるなと感じつつも

  1. オプショナルを使わずに厳格にインターフェース定義できるプロトコルを設計段階で実装できることの方が大事
  2. メソッドに対して ?! といった明示的なunwrapを使うのがコードとしては美しくないと感じる

とも感じるので、設計の初手から使うことは考えずにいたい。

swift学習ログ「タプル」

swiftのタプルについて

公式リファレンス呼んだ備忘録
php, rubyと経験してきて、swiftを学習し始めてから「tuple」という概念を知ったのでまとめます。

タプルとは?

タプル(tuple)とは、複数のものからなっている組の構成要素数を表している集合数詞である。2つ組、3つ組などのそれぞれを表す英単語が一般化された言葉から派生し、数学や計算機科学などの分野では、通常順序つけられた対象の並びを表すために用いられる (出典: 日立ソリューションズ IT用語辞典)

タプルとは集合数詞ということで、なんかよくわからないものと捉えてましたが、Collectionというより変数に近い扱いをするものだと理解して続けます。

タプルの定義と使い方

参考 : Swift Gideline

// 定義の仕方
let httpStatus404 = (404, "Not Found")

// タプルごと定数定義もでき、アクセスもできる
let (statusCode, statusMessage) = httpStatus404
print(statusCode) // => 404
print(statusMessage) // => Not Found

// ワイルドカードもつかえる
let (statusCode, _) = httpStatus404
print(statusCode) // => 404

// tapleで宣言された変数へのアクセス方法
let firstElement = httpStatus404.0 // 404
let SecondElement = httpStatus404.1 // Not Found

// 要素に名前をつけることもできる
let httpStatus200 = (statusCode: 200, statusMessage: 'OK')
let statusCode = httpStatus200.statusCode // 200
let statusMessage = httpStatus200.statusMessage // OK

使い所

イマイチ最初tupleの使い所がわからなかったのですが、座標とかまさにこの形だなと思ったり、要素でまとめられる場合、配列やディクショナリといったCollectionを使わずに、要素を扱いたい時に使えるかなと言った印象。 積極的に現場で使っていきたい。

読書 Note -「人工知能は人間を超えるか」~ディープラーニングの先にあるもの~

背景

今年は間違いなくAIだったり深層学習だったりがバズワードになり、色んな製品にそういった技術が使われてくる世の中になるだろうと思います。
そんな中、結局「AI」とか「人工知能」とか「深層学習」ってそもそも何?っていうことの背景だったり歴史だったりを知ろうと思って読みました。

書評

  • 深層学習
  • AI

といったバズワードの実態を知るには最適の書籍でした。
エンジニアとして、そもそもそういう技術が何なのか?ということを全く理解していなかったことがわかり、これから自分がどういった姿勢でこれらの技術に対峙していくべきなのかを学ぶことができたと思います。

そもそもAIって?

結局、僕が知りたかった、というか疑問に思っていた箇所はこの一点でした。
何でもかんでも「AI」とか「人工知能」って言う言葉が軽々しく使われていて、一体何が人工知能なのかを理解していなかったのですが、

  • 現時点においても、AI(artificial intelligence)といえるものは存在していないこと。
  • 深層学習とAIは厳密は異なること
  • 特徴を理解する / 差異を区別すること を機械が自律的にできるようになることが今で言うところの人工知能的な何かであること

ということを知ることができただけでも、最近の動向なり、流行りを大分整理できました。

AIにどういう姿勢で望んでいけばいいか

僕の立場としては「ふーん」程度にまずは時代の流れをしっかり観察していこうと思います。
理由ですが、そもそも深層学習や人工知能と言っても、そのベースとなる特徴を理解させるには、大量かつ自分たちの意図するデータが返ってくるような特徴的なデータが必要で、これを学習させるのには大変なコストが掛かるので、おいそれと手を出せないと考えています。
そして

  • 意図するデータを返すための特徴的なデータ

は自分たちで用意する必要があり、学習させる際もパラメータをチューニングしていく必要があって、それは現状、初期段階では人力が必要になりそう。

そのため、一口に人工知能とか言っても、じゃあそもそも何に使って、そのためにどういうデータが必要なのかということがわからないと「人工知能なんで使うんだっけ?」っていうことになりかねないと考えています。

では、一般的なデータについてはおそらくですが、Googleだったり、Facebookだったり、Amazonだったり、すでに大量のデータを持っている企業にはそもそも量的な意味で勝負できないので、となると彼らが開発したAIを使うことのできるAPIを使って何ができるのか、それはビジネスに対してどういうインパクトがあるのか、そういことを考えることができる方が大事。

そういったことを考える機会になった本でした。

仕組みを理解したり、実際に作れることも大事ですが、こういう非連続的にポッと出てくる技術って世界を変える可能性がある反面、それに対して自分はどういう態度で望むべきなのか、ということを考えさせられます。
背景も含めて正確に理解することで、今後何が来て、どうなっていくのか、その時自分はどういうレベルにいればいいのか。
文系出身でニューラルネットワークについて全く理解していない自分でも、なんとなく概要を理解できたので、機械学習やAIについて漠然とした不安を持っているのであれば一度通読してみるといいかと思います。

ソースコードの検索の仕方

先に注意事項を書いておきます。

  1. コピペの仕方を書いているわけではありません。
  2. ソースコードの検索は実装の手助けをするものです。
  3. その前段階で設計や実装の準備はしっかり行っておく必要があります。

上記3つをこの記事では意識しています。

ソースコードを探すユースケース

ある特定の実装を想定する時に、どうやって実装するのかを考えます。
また、同時に、同じようなことをしているツール、ライブラリがないかを調べます。

誰かが似たような実装をしていたり、似たようなツールがあるので、あれば、そちらを使った方が実装工数は少なくて済むので楽です。

しかし、例えば、特定のライブラリを実装したい時に、ドキュメントだけでは実装方法がわからない場合があります。

ドキュメントに常に実装方法が記載されていれば言うことはありませんが、そうではなかったり、メジャーバージョンアップしたてのライブラリなどは、そもそも実装方法自体が世の中に出回ってなかったりすることが多々あります。

ドキュメント読んでもわからず、ぐぐっても求めているような実装コードが出てこなかったりするような場合を想定しています。

Githubソースコード検索

そういう場合に役に立つのが、Githubソースコード検索です。

Githubには上部にリポジトリやら、ユーザーを検索できる検索バーがありますが、実はこれ、ソースコードも検索できます。
※ 当然ですが、検索対象になっているのは、publicになっているリポジトリソースコードのみです。

「Swift ◯◯(ライブラリ名とか、メソッド名とか、名前空間とか) 」を入れて検索して、左のナビゲーションのところに、書かれている言語一覧が出てくると思いますが、この言語一覧をクリックすると、その言語で書かれたソースコードが表示されます。

どういった時に役に立つか。

ライブラリのマイナーな機能を使ったり、出たばかりのツールのコードを調べたりっていうのに僕は使っています。

そもそも実装方法が世の中に出回っていなくとも、世界の誰かが実装していたりするので、その誰かの知恵を拝借したり、参考にしたりするために使っています。

しかし、冒頭にも述べたように、それはあくまで、設計が完了して、どういったコードを書けばいいのか頭に浮かんでいるという前提があります。
そもそも、検索対象のコードの該当箇所しか検索結果にはヒットしませんので、一部分を切り出したところでなんの約にも立ちません。

しかし、どういったコードを書けばいいのかわかっていたり、実際にライブラリのソースコードを眺めて、どこでどういうメソッドを使えばいいのか頭に浮かんでいる人には、どこかの誰かが書いたコードは非常に有用です。

ライブラリの使い方で悩んで時間をかけるくらいなら、検索手段の一つとしてGithubソースコード検索を使ってみるのも一つのアイデアだと思います。

拡散思考と実装前提思考

ビジネスサイドや企画サイドと新機能や要望のやり取りをするときに、最近否定的な態度を取ってしまうことが多く、良くない傾向だとおもったので、そもそもなぜ否定的に考えてしまうのかということの理由を考えてみました。

拡散思考と実装前提思考

1. 拡散思考とは?

機能やアイデアを考える時に、納期や機能の実装を前提とせず、思いつくままにアイデアを拡散させていくこと。
実装前提ではないので、今のスキルレベルや実装の詳細を考えずに、自由な発想でサービスに向き合うことができます。

2.実装前提思考

機能の実装に納期が決まっており、実装、検証、改善のサイクルを回すことを前提とし、詳細を決めるために収縮していくこと。
実装される機能には、恒久的な機能とアドホック的な機能の2パターンがあるものの、どちらにせよ、開発が必要になるので、やることやらないことを明確に定義し、仕様に落とし込むことが必要になる。

コミュニケーションの前提を整える

新機能やアイデアに対して否定的になることが多く、コミュニケーションに齟齬が生まれていると感じるときは、この拡散的思考なのか、実装前提思考なのかのコンセンサスが取れていないことが多いのではないかと考えるようになりました。
エンジニアである以上、何か発案をもらったら、実装前提で考えることが多く、そのために、機能の詳細や、いつまでに、何を、どこまで実装するのかを正確に知ろうとしてしまいます。
この過程で、今やるべきなのか、代替案はないのか、そもそも必要なのかをしつこく確認することになり、それが、発案側としてはアイデアを否定されてしまっているように感じてしまうことがあると思います。

しかし、実装前提の立場に立った場合、大雑把な仕様だけでは、出戻りが発生する可能性が高く、どうしても、最速で実装するための最低のシステム要件は確認したくなってしまいます。
特に相手の実装を否定しているという意図はなく、それぞれに抱えているタスク、コミットするべきスケジュールがあるはずなので、それを優先するべきで、差し込みで入ってくる業務等にはどうしてもネガティブにならざる得ません。

拡散思考であれば、上がっているアイデアに対して、エンジニア目線で色んなフィードバックができるようになります。

つまり、大事なのはコミュニケーションを取る前段階で、実装前提なのか、拡散思考なのかはしっかり確認しておくことなのかなと

自分もコミュニケーションを取る際には、拡散思考なのか実装前提なのかを確認し、拡散思考であれば提案者のアイデアに寄り添うこと、実装前提であれば、スケジュールや詳細な仕様も加味しながらになるので、100%提案者のアイデアは汲み取りきれないことを伝えて、コミュニケーションの齟齬をを減らしていきたいものですね。