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

Hack The Environment

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

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

※ 自戒をこめて

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

開発する上での前提

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

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

問題だったこと

  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を使わずに、要素を扱いたい時に使えるかなと言った印象。 積極的に現場で使っていきたい。

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

背景

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