emahiro/b.log

Drastically Repeat Yourself !!!!

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%提案者のアイデアは汲み取りきれないことを伝えて、コミュニケーションの齟齬をを減らしていきたいものですね。

エンジニアのキャリアとして思うこと

エンジニアとしてのキャリアを今後どうしていくか、どうあるべきかの現時点を記録していこうと思います。

自分なりのエンジニアキャリアの考え方

一般的なエンジニアのキャリアの考え方は3種類あると思っています。
それは

  1. 技術突き詰める
  2. 技術をわかった上でビジネスする
  3. そのハイブリッド

の3つ。

では自分なりにどういうキャリアを歩んで行きたいのかって考えると、ずっと2だと思っていたんですが、最近は3も面白ろそうと感じるようになってきました。

なぜそう感じるようになったのかというと、単純に物作り、サービス作りって楽しいな、もっと大きくした時に、更に大きなフェーズで自分なりにモノづくりを楽しみたいなという思いができてきているからだと考えています。
エンジニアのスキルを持って、ビジネスをするのももちろん楽しそうですが、僕はまだ実感としては、コードを書く現場から離れずにサービスもグロースさせていきたいという思いが強いです。

なにより一つできるより複数のことをできた方が楽しいかなと。

今どうしていきたいか

技術もビジネスもできるハイブリットなキャリアを考える上で、「今」自分がどうしたいのかを考えてみると、今は「技術」に寄っている実感があります。

ビジネスをグロースさせる。
まだ見ぬ勝ちパターンを追求して、サービスが圧倒的に伸び始めている機会を体験したいという欲求はありつつも、伸びた先で待っているであろう課題解決をするためのスキルを今はとにかく身につけたいです。

使える言語やフレームワークへのこだわりはありませんが、少なくとも新しいシステムに触れることで、自分のキャリアの幅は広がり、解決できる課題も増えていくので、今はその課題の解決手段のパイを増やす作業をしていきたいです。

キャリアに課題を感じたときの指針

エンジニアとしてのキャリアを考えるに当たって、何か壁にぶつかったり、想定外の事態が起きて、自分の方向性に迷いが生じることがあります。

そういった時に、自分が提供しているサービス、プログラムが現実の生々しい課題に対して、どう切り込んでいるのかという感覚は捨てずにいきたいと考えています。

理由は、サービスはユーザーがいてこそ成り立つもので、ユーザーの趣味嗜好はこの時代、常に変化していきます。
そうした時に、ふとユーザーの方向や世の中のサービスの方向が変わった瞬間に顕在化するニーズを如何にはやくキャッチアップして、課題を解決するのか、その感覚を忘れずに行きたいなと思います。

サービスは生物であり、それを動かしているコードも生物です。
ニーズが変わればコードはそれに合わせて変わります。

エンジニアリングは課題解決が主たる業務なので、日々刻々と変化する市場とそれに対応するサービス、それを作っているコードが現実の課題に向き合っているのかどうか、そういう指針を持っていきたいと考えています。

今後どうしていきたいか

やはりサービス作りの現場にいたい気持ちがまだまだ強いです。
一方でソフトウェアだけの世界には限界があるように感じてもいます。

これからはオンラインだけでなく、オフラインでもサービスを起点として、ユーザーが繋がって、新しい行動を起こす、新しい価値観が生まれる、そういった世界観を作っていく仕事をエンジニアリングの領域をメインとしつつも関わっていきたい。。

エンジニアリングはどんな課題解決にも適用できると考えていて、サービスを作るだけでなく、そのサービスを支える全てのボトルネックの解消に適用できると考えています。
新しいツール導入したり、単純作業を自動化して、組織のパフォーマンスをあげたり等…

エンジニアリングはあくまで手段で、目標に向かっていく上で、その手段を用いて解決できること全てにエンジニアリングという武器として取り組んでいきたいと思っています。

スキルスタックにとらわれない、もっとメタな枠組みでのエンジニアリングの適用とでも言うのでしょうか。
そういった領域にすごく興味がありますし、良いサービスを作る上ではやっていきたいなと考えています。

iOS開発の学習に際して意識したこと

年明けから業務でiOS開発を担当することになったので、ここ一ヶ月半で何をして何をしなかったのかを書きます。

目標

一ヶ月でiOS開発に必要な知識のベースをつける

キャッチアップしないと行けなかったこと

  • Swift
  • Xcode
  • Cocoaプログラミング
  • Rx (含むリアクティブプログラミング)
  • 1通りObjectice-Cが読める

やったこと (最初の一週間)

ここで課題が発生します。
眠くなります。

ただ、トリセツ読んでるだけでは集中できずにすぐ眠たくなることがわかりました。
そこで手を動かそうと思います。

やったこと(次の一週間)

Appleの公式チュートリアル「Jump Right In」

これがすごく良かったです。
Xcodeの使い方からViewControllerとViewの関係、TableViewControllerまでの実装を学習できるのと、TableViewControllerがわかるとおおよそのアプリがどう作られているのかがわかるようになりました。
あくまで主観ですが。

これを一周完了した後にRxの学習をしました。
そしてつまづきました。

その段階で気づいたこと

  1. swiftを100%理解していない
  2. xcodeの操作で迷うときがある
  3. RxSwiftを理解するにはFRPをなんとなく理解する必要がある
  4. Cocoaプログラミングおろか、まだxcodeの使い方すらおぼつかない。

つまりまずやるべきは

  1. 開発にすぐ入れるレベルでのswiftの理解
  2. xcodeの使い方で迷わない

でした。

僕に限らず初学者にありがちなのが、開発環境構築や開発に必要なツールの理解が甘くて、挫折すること。
僕もその一人ではありますが、業務で行うにあたって挫折は許されないので、まずは開発環境の理解とswiftの理解に重きを置くことにしました。

んでそのタイミングでやることを絞り、

  1. xcodeとswiftの理解をすること

を最重要項目として

  1. Jump Right Inを何も見ずに作りきれるレベルで暗記する
  2. Swift 実践入門を読む
  3. CocoaプログラミングでJump Right Inに出てくるものは暗記する

でした。
優先順位としては

Swift > Cocoa >それ以外

って感じで進めることになります。

やったこと(残りの期間)

残りの期間はとにかく「Jump Right In」をひたすら写経。
わからないAPIAppleの公式リファレンスを読む。
幸いにして、Google翻訳ニューラルネットワークが導入されて翻訳精度が劇的に向上していたので、分からない分をそのまま邦訳かけても大意をつかめるところまでは可能でした。

上記を繰り返しておそらくですが、Jump Right Inは5〜6回くらい、公式リファレンスもわからないところは何度も調べたので、おおよそリファレンスのみかたや、実際にxcode上でAPIのソース読んだりとiOS開発にあたって必要なことを一気に頭に詰め込みました。
何度かやっているとswiftのお作法やappleのお作法も勝手にインプットされるので、いちいち確認することなく、とりあえずコーディング規約や言語仕様は当たり前だよねという感じで理解できるようになり、swiftも読めるようになってきました。

気づき

受験勉強しているときみたいでしたが、未経験のスキルを学ぶ時に、躓く箇所として

  1. ツールの使い方
  2. 開発環境の理解
  3. ググり方

っていうのはおおよそ共通して躓くところではないかと思います。
そこで、言語の仕様の理解と開発環境の使い方の理解に重きをおいて、短期間に一気に詰め込むっていうのは案外自分に向いている学習法であることに気づきました。
1ヶ月という比較的猶予を与えられていたので、スケジュールを微調整しながら学習することはできました。
とは言え、反省点も多く、最初に色々寄り道しなければもっと色んな学習をできたのではないかなと思います。

何か新しく学習することは、この仕事についている以上避けられず、また、いつ何時そのタイミングが訪れるかわかりません。

特に僕はエンジニアとしてのスキルはまだまだなので、多少効率が悪く、また、同じことの繰り返しで不安になることもありますが、そこは我慢して、どうすれば最短で業務に入れるのか、業務に入った後も自走しながらiOS開発をキャッチアップできるのかを考えて、今回のような学習をしました。
今は一通りのコードは読めるようになってきたので、多少なりこの学習方法は自分にあっていたのかなと思います。
学習に必要な期間、スキル、OJTなど、置かれた環境で異なると思いますが、学習方法の一つとして、写経を繰り返すっていうのは有効です。

※今はRxの理解が追いつかずつらい…

UIStackViewの削除に関しての追加学習

以前書いたカスタムUIStackViewクラス内の子要素を削除するの追記

  1. removeArrangedSubview()
  2. (UIView).removeFromSuperView

の動作の違いとなぜ2つのメソッドを使わないと完全に削除できないのかということについて。

removeArrangedSubview
https://developer.apple.com/reference/uikit/uistackview/1616235-removearrangedsubview

removeFromSuperview
https://developer.apple.com/reference/uikit/uiview/1622421-removefromsuperview

removedArrengedSubView addArrangedSubviewで追加したviewのみ削除する。しかし公式リファレンスによると

However, this method does not remove the provided view from the stack’s subviews array; therefore, the view is still displayed as part of the view hierarchy.

stack’s subview arrayは削除できない。 この stack’s subview array が残る。

そもそも stack’s subview array とは何か?

removeArrangedSubview(削除対象UIView)メソッドが動作して削除するとき

stack’s sarrangedSubview → 削除できる。 stack’s subview → 削除できない。

という動作がある。

  1. arrangedSubview → https://developer.apple.com/reference/uikit/uistackview/1616235-removearrangedsubview
  2. subview → https://developer.apple.com/reference/uikit/uiview/1622614-subviews

arrangedSubviews は subview の 配列の 集合体 add した時は stack view が subview としてこの arrangedSubview を追加する
remove した時は stack view が arrangedSubview の配列を削除する。
このとき、もともとの stack view の subview は削除しない。
階層構造として、stackview に紐づくarrangedSubview は削除するけど、stackview に紐づく subview は削除してくれない。

stackview
  subview
    arrangedSubview

という階層構造になっているのだと思う。storyboard上に出てこないのでわからない…
なので、removeArrangedSubviewした時に stackview 直下の subview は残るので、このsubview も removeFromSuperView() メソッドで参照を切り離さないといけない。

removeArrangedSubview(削除対象UIView) の後に (削除対象UIView).removeFromSuperView を使うのは公式リファレンスでも書かれているので、一般的な方法なのだと思う。

To prevent the view from appearing on screen after calling the stack’s removeArrangedSubview: method, explicitly remove the view from the subviews array by calling the view’s removeFromSuperview() method, or set the view’s isHidden property to true.

(削除対象のUIView).removeFromSuperview or (削除対象UIView).isHidden = true で残っているStackview を削除 or 非表示にする必要がある。