Azure Devops PipelineでiOSアプリのCIを設定してみた

Azure Devopsが大変優秀だということで、リポジトリ管理からスプリント管理まで全部をこちらにまとめてしまおうという動きがアルバイト先でありました。

それに伴って、今までCircle CI動かしてたパイプラインをAzureのPipelineに移行しました。

その設定の際の知見をまとめたいと思います。

Azure Devopsについて

azure.microsoft.com

Azure Devopsでは、アジャイル計画ツールやGitリポジトリホスティングサービス等、チーム開発に必要なツールがひとつにまとまっていて、それをプロジェクトごとに管理することができます。

チームメンバー5人までなら無料で始めることができるので、最初からお金をかけたくない・少しずつ移行していきたいというチームにもおすすめ。

無料でもプライベートリポジトリは何個でも作ることができますが、Pipelineに関しては並列実行ができない・ビルド時間月1800分までという制限が付きます。

Pipelineの設定

azure-pipelines.ymlをプロジェクトのルートに作成し、その中にパイプラインの処理を書いていきます。

タスクは、画像のようなAzure Devops上のタスク一覧からGUIで追加すると、yamlファイルにコードで起こしてくれます。

f:id:aomathwift:20191111150702p:plain f:id:aomathwift:20191111150716p:plain

ローカルでyamlを編集するのでも良いのですが、Devops上で編集するとインデントのミス等をその場で指摘してもらえるのでとても便利です。

基本的な設定はドキュメントを見てもらうと良いので、私自身が苦戦した所・ややこしいところだけピックアップしてお話します。

躓いたポイント

xcWorkspacePathはオプションだが自分で指定しないといけない

Xcode BuildタスクのxcWorkspacePathという項目は自身で設定しなくても動くオプション項目です。

そのため最初は、こういうのは設定しなくてもよしなにxcworkspaceを見つけてきてくれるだろうと思ってそのまま動かしたら、何やら違うプロジェクトのxcworkspaceを開こうとして、指定されたSchemaがないと怒られる。

おかしいなと思ってxcWorkspacePathのデフォルト値を確認すると、**/*.xcodeproj/project.xcworkspaceになっている。

どうやらCarthageのCheckoutフォルダ配下のいずれかのライブラリのxcworkspaceを開こうとしてしまってたみたいですね。

ここをApp名.xcodeproj/project.xcworkspaceにしてあげることで解決しました。

ちなみに、Cocoapodsを使ってるプロジェクトの場合はApp名.xcworkspaceを指定してあげると良いです。

インストール先のPathを指定するとキャッシュがうまくいかない

bundle installする際はいつも --path vendor/bundle にpath指定でやってたのですが、ここでpathを指定するとキャッシュがうまくいきません。

bundle installすると(Pipeline.Workspace)/.bundle配下に入るので、そこを参照しに行くようになってるみたいです。

ちなみに、現在このキャッシュタスクはベータ版でキャッシュをクリアする機能がありません。

そのため、設定途中でクリアしたいとなったらバージョン名(v0, v1等)をつけたりしてキャッシュのキーを変えることで対応ができます。

ブランチの指定の仕方がややこしい

指定ブランチへのマージ・PRのオープン等を引き金としてテストを発火させることができるのですが指定するブランチがややこしい(主観)ので注意が要るなと感じました。

trigger:で指定したブランチは、そのブランチへのpushとマージで発火します。(ここは普通)

pr:で指定したブランチは、指定したブランチに向けたPRがオープンされたら発火します。(ここがややこしい)

完成形

ざっとiOSアプリのCIに必要な処理を書いた設定ファイルがこちらです。

bundle installはfastlaneを使った処理をあとから追加したくて書いてます。

trigger:
  - develop

pr:
  - develop
  - master

pool:
  vmImage: 'macos-latest'

variables:
  MINT_PATH: $(Pipeline.Workspace)/.mint
  BUNDLE_PATH: $(Pipeline.Workspace)/.bundle

stages:
  - stage: Build
    jobs:
    - job: Build
      steps:
      - task: CacheBeta@0
        inputs:
          key: v0 | gems | $(Agent.OS) | Gemfile.lock
          path: $(BUNDLE_PATH)
        displayName: 'Cache gems'
      - script: bundle install
        displayName: Bundle Install
      - task: CmdLine@2
        inputs:
          script: brew install mint
        displayName: Mint Install
      - task: CacheBeta@1
        inputs:
          key: v0 | mint | $(Agent.OS) | Mintfile
          path: $(MINT_PATH)
        displayName: Cache Mint
      - script: mint bootstrap
        displayName: Tools Install by Mint
      - task: CmdLine@2
        inputs:
          script: 'sudo xcode-select --switch /Applications/Xcode_11.1.app/Contents/Developer'
        displayName: Xcode select
      - task: CmdLine@2
        inputs:
          script: |
            # 秘密テキストの環境変数が指定できるので、そこに事前に取得したGithubのアクセストークンを設定しておく
            export GITHUB_ACCESS_TOKEN=$(GITHUB_ACCESS_TOKEN)
            mint run Carthage carthage bootstrap --no-use-binaries --platform iOS --cache-builds && echo '*** Resolved dependencies:' && cat 'Cartfile.resolved'
        displayName: Carthage Build
      - task: CmdLine@2
        inputs:
          # ライブラリを使ってテスト用のモッククラスを作成するためのスクリプト
          script: mint run SwiftyMocky swiftymocky generate
        displayName: MockFile Generate
      - task: Xcode@5
        inputs:
          actions: 'build'
          configuration: 'Debug'
          sdk: 'iphonesimulator13.1'
          xcWorkspacePath: 'App名.xcodeproj/project.xcworkspace'
          scheme: 'App名'
          xcodeVersion: 'specifyPath'
          xcodeDeveloperDir: '/Applications/Xcode_11.1.app'
          packageApp: false
          destinationPlatformOption: 'iOS'
          destinationSimulators: 'iPhone 8'
        displayName: Xcode Build
      - task: Xcode@5
        inputs:
          actions: 'test'
          configuration: 'Debug'
          sdk: 'iphonesimulator13.1'
          xcWorkspacePath: 'App名.xcodeproj/project.xcworkspace'
          scheme: 'App名'
          xcodeVersion: 'specifyPath'
          xcodeDeveloperDir: '/Applications/Xcode_11.1.app'
          packageApp: false
          destinationPlatformOption: 'iOS'
          destinationSimulators: 'iPhone 8'
        displayName: Xcode Test

なお今回は一旦無料の枠の中でやっているので、並列実行処理はありません。

ビルド→テストの処理はこの前リリースされたマルチステージ機能を活かし、ビルド成功時のみテストを実行するという処理に書き換えても良いかなと思います。

まだまだCI初心者なので、間違ってたりアドバイスなどあればコメントおねがいします!

ZOZOテクノロジーズさんのインターンに参加してきた話と近況報告

9/12~9/27の間、ZOZOテクノロジーズさんのインターンに参加してきました。 今回のブログではその体験記と、近況報告を書きたいと思います。

ZOZOテクノロジーズさんでのインターンについて

私が参加したインターンシップはこちらです。 tech.zozo.com

このインターンに応募した理由は、もちろんiOSコースの募集があったというのもありますが、自分がZOZOTOWNの超ヘビーユーザーであることが大きかったです。

面接でもESでも、聞かれてもないのにZOZOTOWNへの愛をひたすら語ってました。

これは私の憶測ですがこのZOZOTOWNへの愛情表現(?)がインターン合格に一役買ったのではないかという気がしてます。

インターンの内容

私は念願のZOZOTOW iOSチームへの配属になりました。

取り組んだのはZOZOTOWNアプリのレガシーなコードのリファクタリングです。

これはインターンを開始する前に、メンターのばんじゅんさん(@banjun)やチームリーダーのあららさん(@arara_jp)と事前に話をして決めたタスクです。

具体的にはObjCのコードをSwiftに書き換えるという業務だったのですが、さすが私が高校生のときから使ってたくらい歴史の長いZOZOTOWNアプリ、一筋縄でひょいと移行できるようなコードではありません。

そんな癖のあるコードでも、メンターのばんじゅんさんが移行するコードを細分化して安全に移すためのヒントを与えてくださったり、Swiftらしい書き方をすごく意識して厳しくも温かいレビューをしてくださったりしたおかげで、日々楽しく学びながらリファクタリングに取り組むことができました。

PRのレビュアーには技術顧問である岸川さんにも入って頂き、なんかもう光栄すぎてそのPR持ち帰りたいみたいな気持ちでした(語彙力)

会社の雰囲気

インターン中は毎日違うチームの方とランチをセッティングして頂き、ZOZOテクノロジーズさんのメンバーと幅広く交流する機会が得られました。

いろんな方とお話して思ったことは、本当に楽しくて優しい方が多いということです。

それぞれのメンバーとはほんの1,2回のランチをご一緒しただけでしたが、就活の話や技術の話、ファッションの話からアニメ・ゲームの話まで、どんな話題でもみなさん真剣に私の話をきいてくださったし、私が聞いて興味深い話もたくさんして頂きました。

そんなメンバーだからこそだと思いますが、社員さん同士も皆とても仲が良いです。

社内の雰囲気がとても穏やかなのに、仕事はきちっとこなすというのがとても良き風土だと感じました。

インターンを終えて

実は私がインターンで入社した日の朝、世間を騒がせたZOZOグループ買収のニュースがあったので、最初はなかなか複雑な心境でした。

しかしながら、社員の皆さんはそんな大きな変化に気を落とすこともせず、むしろ変化を楽しんでいるという様子。

社名や組織体制が変わっても、やることは変わらない。それが皆さんの信念としてあるようでした。

皆さんが同じ方向を向いているからこそ、メンバー同士の仲の良さも際立つのかなという気がします。

私も、こんな風に強い信念を持って仕事に打ち込みたいと考えさせられた10日間でした。

選考から長くに渡りお世話になったZOZOテクノロジーズの皆さん、ありがとうございました!

最終日に頂いた、インターン中に関わった39名からの嬉しいメッセージ、大切にします。

f:id:aomathwift:20191003002655j:plain

近況報告

私のサマーインターンラッシュは9月いっぱいで終了したので、今後のことを含めここで少し近況報告です。

10月からサマーインターンでお世話になったクックパッドさんで再び長期アルバイトをさせていただいています。

部署はサマーインターンのとき同様モバイル基盤部で、メンターはなんと偉大なるぎぎにゃん先生(@giginet)です。

自分は割とシュッと質問するのが得意じゃなかったりするのですが、せっかくの貴重すぎる機会を無駄にしないように、時間を大事に使って頑張りたいと思います(戒め)

iOSDC Japan 2019 参加記録

iosdc.jp

9/5(木)〜9/7(金)で行われたiOSDC Japan 2019に参加してきました。というわけで、#iwillblogです!

印象に残ったトーク

トークいっぱい聞いたしなるほどわからん状態で止まってるものもあるので、厳選してご紹介します。

簡単なアプリを作れるようになった!からその先に進むために

speakerdeck.com

Swift初級から中級になるためにはどうしたら良いのか?と思ったときに、アプリ開発の世界を広げていく方法を紹介しています。

私自身同様の悩みをもったことがあったので、とても参考になりました。そして、ろくさん(@66nylon_y)の行動力がすごすぎて、自分も見習いたいと思いました、、、!

とりあえず他の方々にも勧められてるSwiftコンパイラの世界を覗いてみたいと思います。

自作して理解するリアクティブプログラミングフレームワーク

fortee.jp

RxSwiftを自作しながらリアクティブプログラミングを完全に理解した状態になりましょうというセッション。

私は半年前くらいにRxSwiftを触り始めたのですが、実際にプロダクトコードに入れていくうちに、一時はダニング=クルーガー効果でまさに「完全に理解した」みたいな状態になってました。

が、そこから一線超えてここ最近は「なんも分からん」状態に陥っていたので、理解のための新しいアプローチの仕方としてとても良いお話が聞けたと思います。

トーク以外について

スポンサーブース

一階のスペースではスポンサーの企業が各々の企画を打ち出してブースを出店していました。アンケートに答えてノベルティー貰えたり、エンジニアの方と直接フランクにお話ができたりします。

サマーインターンでお世話になった企業やこれからお世話になる企業はいずれもスポンサーとしてブース出されていたので、「お久しぶりです」「今度からよろしくお願いします」といった会話で盛り上がることができました。

ランチ・ドリンク

毎日お昼には美味しいランチが出て、LTの前にはお酒を含むドリンク配布され、食事事情はとても充実してました。(なのに写真がなにもない!!)

私はいろいろあって懇親会や茶会は出られませんでしたが、写真でみたところ料理もお酒もとても充実していたので、来年は必ず参加します。

コミュニケーション

今回のカンファレンスの一番の魅力はいろんな方とコミュニケーションが取れたことだったと感じてます。

先述した通りサマーインターンで知り合った方とブースで再会できたり、同じくサマーインターンでお世話になった方がスタッフとして参加しておられて困ったときに気軽に相談できたり、SNS上やQiitaの記事でしか見たことなかった憧れのエンジニアの方とお話できたり、人との繋がりがすごく感じられた3日感でした。

まとめ

iOSの大きなカンファレンスに参加するのは初めてでしたが、学ぶこと・刺激をうけることが本当に多くて、とても充実した時間を過ごすことができました。

自分はまだまだ精進しないと!と思う傍ら、自分もいつかスピーカーとして参加したいなーと思ったり。

最後に、iOSDCのスタッフの皆さん、知見を共有してくださったスピーカーの皆さん、私とお話してくれた皆さん、本当にありがとうございました!来年も是非参加させて頂きたいと思います。

Cookpadのサマーインターンに参加してきました

インターン内容

internship.cookpad.com

前半は現在Cookpadで使われている技術やサービス開発についての講義、後半はOJTコースとPBLコースに分かれてサービス開発の実践を行うという内容です。

前半について

講義については後日資料を公開するとのことだったので、そちらを見ていただけると良いかと思います。

一日コードを一切書かず、Cookpadのサービス開発の手法を学ぶという日があったのがとても印象的でした。自分たちでユーザーストーリーを考え制作したプロトタイプに、超丁寧なフィードバックを貰えたのはとてもありがたかったです。

ペルソナをしっかり設定しないと、出来上がるプロダクトもぼんやりしたものになってしまうということを痛感し、サービスを考えるのって本当に難しいと感じました。

後半について

私はOJTコースの配属になりました。

実際にCookpadの現場に入り、今実際に世の中で使われているサービスの開発に携わります。

私は、モバイル基盤部という部署に配属され、アプリのバグ修正やObjective-CファイルをSwiftに書き換える業務等をやらせていただきました。

メンターの方が本当にすごい方で、私が一つ質問すると付随することを一緒にたくさん教えてくれたので、毎日新しい知見が増えてとても楽しかったです。

また、人為的ミスを防ぎ時間を短縮するためにあらゆるところが自動化されているのを見れたり、Cookpadで採用されているアーキテクチャに触れられたりしたのもとても良い勉強になったと思います。

Cookpadは歴史のあるサービスなのでレガシーな部分もまだ残っていますが、それとモダンなコードを上手に共存させて、サービスのグロースを止めずに少しずつリファクタリングを進めていっているというところに技術力・開発力の高さを感じました。

モバイル基盤部には、fastlaneのコミッターの方がおられたり、カニ大好きな方がおられたり、技術的にもキャラクター的にもすごい人が揃っていて、同じ部署で仕事をさせて頂けたのが本当に光栄でした、、、!

会社の雰囲気

お昼休みや仕事終わりに社員さん同士でご飯を作っていたり、カードゲーム大会開催してたり、和気あいあいみんな仲が良いなという印象でした。

それに対して仕事の場では良い緊張感があって、そういうメリハリを大事にしているみたい。(実際インターン生もそうするように言われた)

また業務中には、部署が違うけど席が近かった方々が「なにか困ってることない?」って気にかけてくださったりして、社内全体のあったかい雰囲気が感じられました。

講義中のランチは手作りのものを用意して頂いて、インターン生同士で夕飯を作る機会も多くて、さすがレシピサービスを提供するCookpad!という感じ。

毎日のご飯が楽しみでしょうがなかったです。

f:id:aomathwift:20190901161434j:plain f:id:aomathwift:20190901161500j:plain

1週目終了後のクッキングバトルではジャスティン(@juschin_)さん率いる私のチームが優勝!週末の疲れた大人の胃袋を掴みました。

f:id:aomathwift:20190901162300j:plain

こうして料理したり一緒にごはん食べたりしているうちに同じインターン生や社員さんと仲良くなれたような気がします。

まとめ

歴史あるCookpadのサービス開発について学び、実際に現場にも入ってその手法に触れたことで、ユーザーが喜ぶサービスを提供し続けることの大変さを感じられました。

それと同時に、将来はそういったサービスの開発に携わりたいという気持ちが強くなりました。これから就活をしていく上での軸にもなるような気がします。

最後に、Cookpadの皆様、素敵な2週間をありがとうございました!!ここでの経験を糧に、これからもたくさんのことを学んでいきたいと思います。

余談

私がリスペクトして止まないお二人からこんなリプを頂いたので、そのうちObjective-C駆逐しに行きます。

Wantedlyのサマーインターンに参加してきました!

8月5日から8月16日までの二週間(実質祝日挟んで9日間)、WantedlyさんのサマーインターンiOSコースに参加してきました!

夏のインターン一発目からとても濃くて貴重な経験ができたので、ここで記録しておきたいと思います。

Wantedlyとは?

Wantedlyさんでは、主に以下の2つのサービスを制作しています。

  • はたらくを面白するための採用SNSWantedly Visit
  • かしこく名刺管理するためのサービスWantedly People

www.wantedly.com

私はVisitを使って今のインターン先を見つけたり、現在はその会社で同サービスのAdmin側を利用したりと、もともとこちらの会社のサービスに非常に馴染みがありました。

また、Wantedlyさんのエンジニアは技術力が高いと予てから話に聞いていたということもあり、今回インターンに応募するに至りました。

インターンの内容

Wantedlyさんのインターンは、完全就業形です。実際のチームにジョインして、タスクを振ってもらってそれに取り組む、というスタイル。

私はVisitのグロースチームに配属され、プロフィール入力欄のUIの改修を主に取り組みました。

初日はまずコードを追うことで一日が終わり、サービスの大きさを痛感。

翌日からは実際にUIButtonのカスタムクラスを作るところから始めましたが、今までデザイナーの考えたデザインに沿ってUIを作ったことが無かったので、色とかマージンとか、細かいところまでこだわってUIを作るということ自体が初めての経験でした。

レイアウトも、曖昧なプロパティが絶対存在してしまうStoryboard上で作った経験しかなかったので、全部コードでレイアウトするというのは最初はなかなかうまく行かなったです。

しかしながら、ここと見た目が似ている他の部分ではどんなふうに実装されているかな、とか、改修前はどんなふうに書かれていたかな、とかを追っていくと段々自力で想像した通りのUIが実装できるようになっていきました。 現在実際に動いてるプロダクトのコードを見れるということの有り難みをすごく実感。

メンターもインターン生1人に付き1人ついていただき、しかもインターン生は常にメンターの隣で仕事ができるという、かなりの安心感のもと仕事をすることができました。

会社の雰囲気

基本的に作業してる間は個人でもくもくって感じですが、MTGとかになると新卒の子でも関係なく積極的に意見を出し合ってたのが印象的でした。

お昼は社内全体のシャッフルランチがあったり、他チームのエンジニアとの交流ランチがあったりと、社内での交流の機会は多かったです。

私はこのタームで女子1人だったので、女性の人事さんが何もない日にランチ誘ってくれたりすごく仲良くしてくれて、とっても嬉しかった、、、!

ちなみにお昼で一番おいしかったのは会社の裏路地にある「馳走 麹屋」というお店の和食ランチ。 f:id:aomathwift:20190818221437j:plain

ただし、白金台周辺のランチは基本的にちょい高めです。

インターン生同士で関わる機会は正直そんなになかったですが、結果として最終日の打ち上げで結構仲良くなれました。

まとめ

就業形のインターンは初めてでしたが、実際にプロダクトとして生きているコードに直に触れられるし、その中に自分のコードを入れていくっていうのはすごくやりがいがありました。

また、インターン生だけの空間で作業しているわけではないので、会社の雰囲気を直接感じられたのも良かったです。ちなみにWantedlyさんのメンバーは根がおもしろい技術オタクって感じの人が多い印象でした笑

最後に、Wantedlyの皆様、2週間貴重な体験を本当にありがとうございました!!

打ち上げで出てきたGopherくんのケーキが可愛かったです。

f:id:aomathwift:20190818222839j:plain

次のインターン

明日から2週間、クックパッドさんの10Techインターンに行ってきます!!

無事ついていけるかは不安だけど、とても楽しみ!!