Studyplus Engineering Blog

スタディプラスの開発者が発信するブログ

便利に使えるAnsibleのAWSモジュール11選

こんにちは、インフラエンジニアの菅原です。

皆さんはAWSをどのように管理されてますか?
Ansibleでしょうか?ChefやTerraform、CloudFormationでしょうか?  

弊社ではAnsibleのAWSモジュールを使って、構成をコード化し、管理しております。
そのため最近関わったプロジェクトでも一人で手早く対応することができました。

今回は便利に使い回せるAWSモジュールを厳選して紹介したいと思います。  

AnsibleでAWSを管理する理由

弊社では以下の理由でAnsibleをメインに構成管理を行っています。

  • 構成変更の影響範囲をできるだけ小さくしたい(破壊的変更を避けたい)
  • エージェントレスで導入コストが少なく、手元で設定を完結したい
  • 使うツールは最小限にしたい(新規メンバー参画時の学習コストを減らしたい)
  • 前任者の好み

Infrastructure as Codeを挫折してしまう理由が「ちょっと変更したいけどコード化に時間がかかる」や「ここだけ変更したいけど影響範囲が大きい」という要望に簡単に答えられないときだと個人的に思ってます。「手でやった方が早い」という気持ちになってしまうと再現性のない環境が次々とできてしまいかねません。
その点Ansibleであれば、変更箇所を変えて実行するだけですし、変更したい箇所以外はskipされるため影響範囲も最小限に抑えられます。

この記事の前提

この記事の前提は以下となります。

  • Ansible2.7系で利用することを前提に記載してます。
  • モジュールは順不同になります。
  • 以下の図のような構成を目的としたAWSモジュールの紹介になります。

f:id:ksugahara08:20190416080142p:plain
AWSモジュールでのsample構成

便利AWSモジュール

iam_role

- name: Create IAM roles
  iam_role:
    state: present
    name: "sample-iamrole"
    assume_role_policy_document: "{{ lookup('file', 'sample-role.json') }}"

iam_roleはIAMロールを作成、変更することができます。
初回実行時にAWS環境にJSONファイルで用意した内容でIAMロールを作成してくれます。
JSONファイルは以下のようにfilesディレクトリ配下に配置します。

├── files
│   ├── sample-policy.json
│   └── sample-role.json
└── tasks
    └── main.yml

IAMロールの設定内容を変更したい場合はJSONファイルを書き換えて実行すれば上書き変更できます。
一つ作ってしまえば使い回しが効くのですごく便利です。

iam_policy

- name: Set policy
  iam_policy:
    iam_type: role
    iam_name: "sample-iamrole"
    policy_name: "sample-policy"
    policy_json: "{{ lookup('file', 'sample-policy.json') }}"
    state: present

iam_policyはIAMのポリシーを作成、変更することができます。
弊社ではtrusted entitiesをiam_roleで設定し、policyをiam_policyで付与しています。

route53

- name: Set Route53
  route53:
    command: create
    zone: "sample.com"
    record: "new.sample.com"
    type: "A"
    ttl: "7200"
    value: "dualstack.sample-1111111111.ap-northeast-1.elb.amazonaws.com."
    overwrite: "{{ DNS_OVERWRITE | default(false) }}"
    alias: "True"
    alias_hosted_zone_id: "ZXXXXXXXXXXXXX"

route53はRoute53にDNS設定を追加、変更することができます。
上記はロードバランサー(ELB)に設定する例です。ホスト名の変更を簡単に行うことができるため重宝してます。
既存のレコードを変更する場合はoverwritetrueにします。その際は変数を実行時に渡してあげるとroles配下のファイルを書き直さなくても良くなります。

ansible-playbook main.yml -e DNS_OVERWRITE=true

ec2_vpc_net

ec2_vpc_net, ec2_vpc_igw, ec2_vpc_subnetは基本的に新規プロジェクトや環境追加するときにしか実行しませんが、手間が省けたり、環境設定をコードで管理することができるため利用しています。

- name: Create vpc
  ec2_vpc_net:
    state: present
    name: "sample-vpc"
    cidr_block: "10.10.0.0/16"
    dns_hostnames: yes
    dns_support: yes
  register: vpc_net

ec2_vpc_netはCIDRブロックを指定してVPCを作成、変更することができます。
変更する対象はcidr_blocknameで一意に決まります。

ec2_vpc_igw

- name: Create igw
  ec2_vpc_igw:
    state: present
    vpc_id: "{{ vpc_net.vpc.id }}"

ec2_vpc_igwはInternet Gatewayを設定できるモジュールです。
vpc_idec2_vpc_netで作成したidを渡すことで設定することができます。
例のようにregistervpc_idを渡してあげるとスムーズです。

ec2_vpc_subnet

- name: Create subnets
  ec2_vpc_subnet:
    state: present
    vpc_id: "{{ vpc_net.vpc.id }}"
    cidr: "{{ item.cidr }}"
    az: "{{ item.az }}"
    tags: { "Name": "{{ item.name }}" }
  with_items:
    - { cidr: "10.10.0.0/20", az: "ap-northeast-1a", name: "sample-vpc-subnet1" }

ec2_vpc_subnetはサブネットを設定するモジュールです。
例ではCIDRブロック、Availability Zone、nameタグをwith_itemsに変数として入れて実行しています。
サブネットを複数設定する場合はwith_items構文でループ実行します。

ec2_group

- name: Create security group
  ec2_group:
    name: "sample-sg"
    description: "sample security group"
    vpc_id: "{{ vpc_id }}"
    rules:
      - proto: tcp
        from_port: 22
        to_port: 22
        cidr_ip: "10.10.0.0/20"
      - proto: tcp
        from_port: 80
        to_port: 80
        cidr_ip: "0.0.0.0/20"

ec2_groupはセキュリティグループを作成し、対象のVPCに設定することができます。
2回目以降の実行ではセキュリティグループの変更(上書き)を行うことができます。
ただし、AWSのマネジメントコンソールから直接入れた設定があるとロールバックさせてしまうので、実行する前は--checkを付けて変更箇所を確認した方が良いです。

elb_target_group

- name: Create Target Group
  elb_target_group:
    state: present
    name: "sample-alb-target-group"
    protocol: http
    port: 80
    vpc_id: "{{ vpc_id }}"
    health_check_protocol: http
    health_check_path: /health_check
    health_check_interval: 10
    health_check_timeout: 5
    healthy_threshold_count: 2
    unhealthy_threshold_count: 2
    deregistration_delay_timeout: 0
    successful_response_codes: 200

elb_target_groupはロードバランサーのターゲットグループを作成、変更できます。
例ではリクエストをhttpで80番ポートに受け渡すように設定しています。
ヘルスチェックは要件に合わせて設定値を変えてください。
ターゲットグループにAWSのマネジメントコンソールから追加したインスタンスがあると実行時にターゲットから外れるので注意してください。

elb_application_lb

- name: Create ALB
  elb_application_lb:
    state: present
    name: "sample-alb"
    scheme: internet-facing
    subnets: "sample-vpc-subnet1"
    security_groups:
      - "sample-sg"
    listeners:
      - Protocol: HTTP
        Port: 80
        DefaultActions:
          - Type: forward
            TargetGroupName: "sample-alb-target-group"
      - Protocol: HTTPS
        Port: 443
        DefaultActions:
          - Type: forward
            TargetGroupName: "sample-alb-target-group"
        Certificates:
          - CertificateArn: "arn:aws:acm:ap-northeast-1:123456789:certificate/aaaa-bbbb-cccc-dddd-eeee"
        SslPolicy: ELBSecurityPolicy-2016-08

elb_application_lbはアプリケーションロードバランサーを作成、変更できます。
今まで作成してきたサブネットやセキュリティグループを指定して作成します。
例ではロードバランサーに証明書を設定しています。Certificatesにarnを記述すれば証明書を設定する事ができます。
ALBとして利用するのであればlistenersタグの中にRulesタグを設ければパスで振り分けることができます。(詳しくは公式ドキュメントを確認してください。)

ec2_lc

- name: Create launch configuration
  ec2_lc:
    state: present
    name: "sample-lc"
    image_id: "ami-123456789"
    key_name: galaxy
    security_groups: "sample-sg"
    instance_profile_name: "sample-iamrole"
    instance_type: "t3.small"
    assign_public_ip: yes
    volumes:
      - device_name: /dev/sda1
        volume_size: 32
        volume_type: gp2
        delete_on_termination: true
  register: lc

ec2_lcはAuto Scalingの起動設定を作成、変更をすることができます。
AMIを用意してあればimage_idで指定することで任意のイメージを利用することができます。
弊社ではAMIをAnsibleとPackerで作成しています。
また、EC2のインスタンスサイズやボリームはここで管理する形にしています。

ec2_asg

- name: Set Auto-scaling group
  ec2_asg:
    state: present
    name: "sample-asg"
    launch_config_name: "{{ lc.name }}"
    health_check_period: 500
    health_check_type: EC2
    replace_all_instances: yes
    min_size: "1"
    max_size: "3"
    desired_capacity: "2"
    vpc_zone_identifier: "sample-vpc-subnet1"
    tags:
      - Name: "sample-web"
      - role: "web"
      - env: "cage"

ec2_asgはAuto Scaling グループの作成、変更をすることができます。
ec2_lcregister: lcを指定しておけばlc.nameを受け渡せます。
弊社ではEC2の起動/停止はec2_asgを使って管理しています。

最後に

今回は弊社でもよく使っているAnsibleのAWSモジュールを紹介しました。
AWSモジュールを利用することでインフラの自動化を進めていますが、Ansibleでは対応していない設定項目やAWSの最新の変更に追従できないこともあります。しかし、うまく使うことで運用をかなり楽にできるができます。

Rails Developers Meetup 2019に参加してきた

こんにちは!
For School事業部でサーバーサイドエンジニアをしているatomiyama(id:atomiyama)です.
今回3/22, 3/23に開催されたRails Developers Meetup 2019 Day2参加してきました!
弊社はDay2でビールスポンサーとして参加させて頂いたのですが,こういったカンファレンスに参加させてくれて感謝です🙇
railsdm.github.io

Railsの生みの親であるDHHをはじめとしたそうそうたる面々の発表が聞けて学び多くあったので,
中でも印象に残った発表の感想などレポートしたいと思います.

印象にのこった発表

今回Day2のみ参加だったので2日目の発表の中からの選出ですが特に下の2つの発表はRailsを書いているすべての人に読んでもらいたい程に有益な発表でした.

Clean Test Code, Revised @willnetさん

f:id:atomiyama:20190415161400j:plain 可読性の高いコードを書くためのコツというお話でした.
describe以下に大量に並ぶletやDRYで書かれスコープを飛び出したlet, FactoryBotにおける初期値の話など,脳への負担が少ない可読性の高いテストコードを書くTipsを アンチパターンを交えつつ発表されていました.ついついやってしまうような覚えのある話もあり胸に刺さる話が多かったです.

twitter.com

Ruby on Railsの正体と向き合い方 @yasaichiさん

f:id:atomiyama:20190415161550j:plain そして会場から人がはみ出す程に大盛況だったこちらの発表です.
DHHがRailsを生み出す上でした妥協の背景,内容をHanami(クリーンアーキテクチャ)との比較を通して認識した後,その妥協(Railsの強みでもある)からくる限界をどう倒して行くかをコードレベル(ApplicationModelやForm, Serviceなどの導入)と,アーキテクチャレベル(BFF, MicroServiceなど)で発表されていた100点満点中300点の発表でした.
特に前半のRuby on Railsの正体に迫る部分の話は他のフレームワークのコードまで出しての説明だったので大変わかりやすく感動しました!

twitter.com

まとめ

今回弊社はビールスポンサーとして参加しましたが,参加者の方々と様々なお話をできて大変楽しい1日を過ごすことができました!
弊社はRailsをサービスの中で積極的に使用しており今後もこのような機会があれば是非参加したいと思いつつ,こういった場で発表できるようにより精進しなければと思わせられる貴重な機会でした.
今回でrailsdmは完結となり次回からはrails kaigiとして開催されるようです.
このような貴重な会を開催してくださった運営メンバーの方々への感謝とともに今回のrailsdm2019のレポートとします!

f:id:atomiyama:20190415161926j:plain
懇親会の様子

RubyKaigi2019でお待ちしております!

スタディプラスCTOの島田です。

いよいよ今週RubyKaigi2019が開催されます。

今回、スタディプラスではスポンサーブースを出展させていただきます。 ブーススポンサーはRubyWorld Conference 2018(以下RWC)に続き2回目となります。

ブースでは学習管理サービスStudyplusとRubyにちなんで、「推しRuby本投票」を実施いたします。
多くのRubyistが集うRubyKaigiで、Rubyを学習するにあたって、どのRuby本を薦めたい(推したい)かの投票していただこうという企画です。
(著者の皆様サインお待ちしてます 🙇🏻‍♂️)

f:id:yo-shimada:20190415154627p:plain

RWCで実施した企画の続編で、候補のRuby本を変えての実施となります。

投票していただいた方には、スタディプラスの缶バッジとサコッシュをプレゼントさせていただきます。
※ サコッシュの数には限りがありますので、なくなり次第終了となりますのでご了承下さい。

f:id:yo-shimada:20190415154822j:plain

その他にもスタディプラスではノベルティをご用意しておりますので、是非スタディプラスのブースまでお立ち寄り下さい。

f:id:yo-shimada:20190415154843j:plain

当日の状況については随時、スタディプラスの公式Twitterにてお知らせさせていただきます。

Flutterもくもく自習室 in スタディプラス #2 を開催しました。

スタディプラスでiOSと新規事業を兼務している須藤(id:kurotyann)です。

今回のブログでは、4月6日(土)に開催した「Flutterもくもく自習室 in スタディプラス #2」の結果についてまとめます。

Flutterもくもく自習室 in スタディプラス #2 - connpass

Flutterもくもく自習室とは?

第1回のブログを参照してください。

Flutterもくもく自習室をはじめました - Studyplus Engineering Blog

運営スタッフから見た第2回の様子

今回も運営スタッフは、弊社の社員の2名で行いました。

参加者の様子は当日のTwitterのハッシュタグ #flutter_studyplus で見れます。

須藤(id:kurotyann)

4月初旬はイベントの多い時期です。

connpass.comで調べると都内では、もくもく学習会の当日に48件のイベントが開催されていました。

この状況だと、参加者ゼロ人もありえると覚悟していましたが、3名の方が参加してくれました。

当日は、前回と同様にもくもくと開発できる良い学習環境が維持できました。

私は、新規事業のアプリをFlutterで開発しており、主にListViewをつかった画面を実装してました。

素晴らしい学習環境の維持に貢献してくれた参加者の皆さま、本当にありがとうございました!

若宮(id:D_R_1009)

"Flutterもくもく自習室"はFlutterではない好きな言語の好きなものをもくもくする場として設定しています。 そこで今回はAndroidの簡単なライブラリ開発に取り組んでみました。

https://github.com/koji-1009/FailureStatus

「なにか手をつけてみよう」と考えて取り組む場として、なかなかいい環境なのではないかなと感じています。 気負わずに、軽い気持ちで参加してもらえる場として取り組み続ければなと考えています。

参加者のみなさま、ありがとうございました!

次回の開催日は?

次回のもくもく学習会の開催日は6月を予定しています。

5月は弊社オフィスにてFlutter Meetup Tokyo #9を開催するので、5月のもくもく学習会はお休みです。

Flutter Meetup Tokyo #9の詳細な日程は、4月末ごろに公開しますので、しばしお待ちください。

try! Swift TOKYO 2019行ってきました

初めまして、iOSチームに昨年10月から入社しております明渡(ID: m_yamada1992)と申します。

入社してからといいますか、社会人8年目にして初めて平日に丸1日単位で開催される技術カンファレンスへ大手を振って参加してきました!

開催が3月21日から23日でしたので少し日数が経ってしまいましたが、私が参加した1日目と2日目にて見聞きしたセッションの感想を中心にレポートを書かせていただきます。

try! Swift TOKYO 2019 にスポンサード

www.tryswift.co

スタディプラスはシルバースポンサーとして、参加受付した際に配布してたトートバッグ内のノベルティ提供などもしておりました。

2日目になってからスポンサー一覧の看板に参加してる人のメンションがマジックペンで書き込まれていたので、僭越ながら書き込んで参りました。

今回他のiOSチームメンバーは新規事業の業務都合なり私用なりが重なって 弊社からは私一人で参加だったのですが、頻繁に写真撮影が行われる合間を縫って急いで書いてパシャって退散してみると賑やかさが恋しくなり・・・ 来年はもう少しメンバー増えてわいわいしながら参加できると良いなと思いますね。

印象に残ったセッション

native macOS application、またはAppKitの世界

1024jpさんの発表。

Macアプリは特に開発する機会ないからなぁと、正直なところ流し聞きするつもりだったセッション。

speakerdeck.com

Macアプリを例として上げているだけで、本題はユーザーが快適にアプリケーションを利用するために必要なものについて。 プラットフォームが提供している標準の仕様に則ることの大切さと、則るために必要なことを分かりやすく言語化した内容でした。

Macのアプリケーションを開発してそれをユーザーが使う際、ユーザーにとってはあくまでMacを操作している。 決してアプリケーションを使うためにMacを操作しているわけではないことをわきまえなさい。 アプリケーションは、ユーザーの目的を達成するために用いられるものである。 目的を達成する以外に気が散る要素を入れぬよう、開発者のエゴは殺し、オレオレ実装に走らずMacの仕様を尊重することを大前提とすべき。 そのためには、Macの場合だとAppKitを深く理解して有効活用しようねというお話。

スマートフォンアプリの開発に関わっているとわりとよく聞く「AndroidはiOSと同じデザインで!」ってぶん投げられる系の案件に対して素晴らしい説得材料の手札になりそうだなと思ってました。 弊社のディレクターチームやデザインチームにこの辺り理解のある方々ばかりなので、その手の不毛な説得コストは発生したことないですが。 普段関わっているStudyplusのアプリでも、できるだけ普段使っているユーザーに違和感なく使ってもらえるように検討を重ねたうえで開発を進めておりますし、今後もこういう姿勢で開発し続けたいです。

アクセシビリティのためのカラーコントラスト

Liz Marleyさんの発表。

以下は「照明の関係で見え方が違っていて分かりづらいから」と事前に手元へダウンロードすることを勧めていらっしゃったスライドのPDFです。

https://raw.githubusercontent.com/emarley/ColorContrast/master/ColorContrast.pdf

アプリケーションで使う色を選ぶ際に、適切とみなす基準は具体的にどういったものか、何故その基準を満たすべきなのか。

人間の見え方を考慮した公式を用いてコントラスト比率を計算した結果、4.5:1 〜 7:1を守りさえすれば自分の好きな色を組み合わせてOK。 コントラストチェッカーはWebサイトなどにすでに存在しているので、開発する際はそういったツールを活用するとよいだろう。 基準を問い合わせた先がヒューマンインタフェースガイドラインの専門家とのことだが、 回答をもらった基準というのがWeb Content Accessibility Guidelinesと一致していたので、 こちらを参考にしているだろうとのこと。

コントラストを重視すると、視覚になにかかしらの障害を持っていない人だったとしても恩恵がある。 太陽の下で画面が見づらい状態で操作したり、前の夜に寝不足をして体調が悪い人にも見やすくなり、あらゆるユーザーにとって易しいデザインにできる。 近いうちiOSでもダークモード対応が必要になるでしょうから、その際に是非意識してね、というお話。

弊社にも緑が見にくいという方が数名いたり、旦那が最近目の疾患で急激に視力が落ちて「白の背景にこのグレーだと眩しすぎて文字が読み取れない」等ぼやいていたり。 身近で自分が日常的に見ている景色と異なる視界で認識している人間がいることを意識する機会が多かったにも関わらず、こういった視点で主体的に調べようともしたのを個人的に反省しました。 また、来るダークモード対応時に意識すべき明確な基準としてとてもありがたい内容でした。

Introducing SourceKit-LSP

Ryo Izumiさんの発表。

speakerdeck.com

LSP(Language Server Protocol)でSwiftが使えるようになって、好きなエディタでSwiftを書けるようになったよ!というお話。

私自身が普段Swift言語ではiOSアプリの開発しかやっていなかったり、サーバーサイドSwiftの存在は知っていても触ったことはない状態。 過去に経験した開発案件もIDEごと乗り換える(AndroidStudioやPyCharm、Eclipceなど)のが普通の感覚でいました。 故に、LSPサポートによりどのような恩恵があるのかという話はとても新鮮でした。

魔法の法則

Dave DeLongさんの発表。

スライドは共有されていなくはないのですが、try! Swift参加者用のSlackへ直接PDFファイルをアップロードなさっていたのでこちらに貼るのは断念しました。

エンジニアチームだけじゃなくて他部署のいろんな人に共有したい!って感じた内容でした。 あとからスライドのPDFだけ眺めても、自分がセッションを聴いたときに伝わってほしいなと思った内容が伝わるか微妙な気がして諦めて放置しちゃってますね・・・

AppleでUIKitを開発しているかたのお話なのですが、概要は以下のような感じです。

高度な技術はある意味魔法と区別がつかないもので、iPhoneという端末そのものも、私たちのような開発者がソースコードを書くことにより実現する挙動ですらユーザーにとっては魔法である。 魔法を実現するため役立つ3つの法則がある。

1つ目に、造り手が魔法を深く理解していること。 UIKitでは、深く理解していない開発者から意図しない使われ方をされないようにSwiftの型システムを利用している。 コンパイル時にエラーを投げたり、代わりのメソッドについてのドキュメントの記載も欠かさない。

2つ目に、なんでもできてしまうことよりも制約を重視すること。 できないことは、できることより面白い。制約があるからこそ創造的になる。 ゲームなどが例に上げられていて、できないことだらけの中からできることを見つけるほうが楽しいですよね、と。

3つ目に、新しい要素の追加よりもすでに追加済みの要素を拡張しよう。単純に見えるものが、奥深いことを発見するととても嬉しい。

これらを意識して、すでに作り上げたものもより素晴らしいものにしてゆきましょう!というお話でした。

3つ目の、新しい要素の追加より追加済み要素の拡張をしていこうという話にいろいろ思うところがございました。 Studyplusへ昨年暮れ頃、追加したボタンのタップまたは画面のスワイプで開閉可能なメニュー画面が実装されました。でも、スワイプで開閉してるユーザーが1%に満たない現実を目の当たりにして、「スワイプ操作の開閉実装、あんなに苦労していたのに・・・」とショックを受けまして。 少なくとも、国内のスマートフォンユーザーは画面上にある要素へタップ以外の動作をあまりしないんだな、という印象があります。

正解はないのでしょうが、めったに使われないと予測できる要素を、それを見つけたときに感動してもらうためにどこまで対応するのが良いのかなと考えさせられました。

例えば、iOSでいうところのUITableViewRowActionをサポートしていない箇所を適宜対応したりする、っていうのはいろいろなコスト面でも手軽にできそうだなと。 「この画面だったらこの導線もサポートしてよいのでは」ってタイミングがあれば提案していければ良いなと思います。

次へつなごう— Extending a hand to the next generation of Apple developers @hellomayuko

Mayuko Inoueさんの発表。

資料は展開されていませんが、口頭で話されていた内容のほうが本質な気がするので当然なのかも・・・?

iOSに限らず、Tech業界の将来性や展望のお話です。

この業界のダイバーシティ性に課題がある。 iOSデベロッパーの採用のプロセスに参加してみたところ、マイノリティな人が少なかった。 周りの人達に尋ねてみたところ、Macを買うための費用が確保できず諦めていたり、かかる費用の具体的なイメージも特にない様子だった。 視点の多様な人達が協力することでよりよい開発が可能となるので、Tech業界の外の人に見えるように自分のことをどんどん発信していきましょう。 巡り巡ってTech業界に興味を持っている人に届いて良い刺激になるかもしれないから、というお話。

こちらの発表者のまゆこさんはもちろん、普段からTwitterやブログを駆使して自分のことを発信している人たちを尊敬しております。 私は、自分の何かを積極的に発信するってそこはかとなく怖い気持ちが拭えずにおりますゆえ。 「この業界でどんな人がどんなふうに働いているか見えないのも良くないんだ!もっと自分を発信しよう!」って思い立って行動してそれを続けているのを目の当たりにして、畏敬の念すら覚えました。 完璧に真似できそうにないですが、精神が削られない程度に何かかしら発信する心がけをしてみようとは思います。 iOSデベロッパー業界の費用面の話は、先述したLSPサポートによりMacじゃなくても開発できる方法が普及して事情が変わってくると良いといいですね。

1日目・2日目を通しての感想

私は英語全然駄目な人間なのですが、セッション自体は同時通訳のおかげで「何を話しているか全くわからん!」ということは起こらずに快適に参加できました。

休憩時間、セッション会場やブースのある会場やコーヒー待ちの列に至るまであちこちで英語によりわいわい会話がなされていて、英語使いこなせるようになるとより楽しいのだろうなと思いながら眺めておりましたが。銘打たれていた通り、すごく国際的なカンファレンスでした。

そして、セッションの内容がSwift言語自体に関するテーマだけでなく、アプリケーションのユーザビリティやアクセシビリティ、エンジニアとしての働き方に関するお話などもあって思っていたより幅広かったです。もっとSwift初心者の頃に参加しても楽しめただろうなとも・・・ 様々な人達の努力が実った結果なのも認識しておりますが、こういった催しが積極的になされるって良い世の中になったなぁとしみじみ思います。

さいごに

参加中に眺めていたTwitterで「暑い」「寒い」「Wi−Fiが〜」などなど思い思いな発言が流れてきてて、そりゃ900人入る大きな会場だといろんな人もトラブルもあるよなぁと・・・

そんな中でも運営の皆様がさまざまな心配りをしてくださっていたおかげで、セッションに集中したりふらっと会場を歩き回ったりとマイペースに楽しめたんだと思っております。ご尽力いただき、ありがとうございました。

やりたいことベースでWebpackにCSS周りの設定をする

こんにちは、ForSchool事業部の石上です。

あるSPAを作る際、CSSを書きやすくするためにいくつかWebpackの設定を書きました。 今回は、これらの設定がなぜ今こうなっているのかを社内のメンバーに説明するつもりで、どれが何のために必要な設定なのかを書いてみます。

背景

ウェブフロントエンド全般に言えることですが、CSS周りにもツールや設定方法はたくさんあります。一から用意する際は、毎回何を選んでどうすればいいのか悩んでしまいます。そこで今回のプロジェクトに使う設定をやりたいことベースで整理したところ、以下のような要件となりました。

  • 配信するときは1ファイルで、なるべくサイズを小さくしたい
  • コンポーネントごとにスタイルを閉じたいけど、BEMは面倒
  • デザイナーさんに用意してもらった変数を一箇所で管理したい
  • ベンダープレフィックスを自動でつけてほしい

設定

MiniCssExtractPlugin

その前段階で何をするにしろ、最終的にはサイズを小さくした1つのCSSファイルに出力したいです。これにはMiniCssExtractPluginを使います。

f:id:shgam:20190405140655p:plain
1つのCSSファイルにする

CSS Modules

BEMという設計方法があります。Block, Element, Modifierに分ける命名規則です。

class名をblock__element--modifierの形にすることで、コンポーネント間の名前の衝突を避けることができます。

しかし、グローバルで一意な名前を付けるためにクラス名は長くなり、命名も面倒になってくるという問題があります。

そこで、CSS Modulesという仕様があります。

今回のプロジェクトでは、モジュールバンドラーにWebpackを利用しているので、Webpackのloaderを利用します。 CSS Modules形式で書いたCSSをcss-loaderというloaderに通し、これを実現しました。

f:id:shgam:20190405140420p:plain
CSS Modulesの仕様に従ってクラス名を変換したCSSにする

typed-css-modules

CSS Modulesを使って、CSSをJavaScript側からモジュールのように参照できます。

TypeScriptで書いている場合は、これに型を付けたくなります。

import * as styles from './styles.scss'

こういうものに対して、

<p className={styles.hoge}>
</p>

こう書いて参照しようとすると、エラーになります。stylesの型が決まっておらず、styles.hogeの存在を認識できないからです。

そこで、以下のようなファイルをstyles.d.tsとして用意してhogeを定義しておくと、このエラーはなくなります。

export const hoge: string;

これを自動でやってくれるのが、typed-css-modulesです。

作者のQuramyさん的にはバンドルの前にd.tsを生成しておくべきという意向のようで、loaderが提供されていません。ただこれが必要だと思う方もいて、loaderを書いた方がいました。CSSを変えるたびにコマンドを打ったりしないといけないのは面倒なので、そちらを使っています。

ここまでの流れはこうなりました。

f:id:shgam:20190405140330p:plain
型定義ファイルを自動生成

Sass

今回のプロジェクトでは、デザイナーさんがInVisionのDSMというツールで、色の変数などを管理しています。Sketchから上げられたこのデータを、DSM上でSassの変数として出力することができます。 これをそのまま使うべく、Sassも利用することにしました。

Webpackでの設定にはsass-loaderというものがあり、これを使いました。

先程のCSS Modulesの設定に加えると、流れは以下のようになります。

f:id:shgam:20190405140152p:plain
CSS Modulesの設定を加えた

PostCSS

ベンダープレフィックスを一つずつ手で書きたくなかったため、自動でベンダープレフィックスを付けてくれるautoprefixerの設定も必要でした。

以上までで、バンドリングの流れはこうなりました。

f:id:shgam:20190405134808p:plain
最終的なバンドリングの流れ

まとめ

ここまでで紹介したものは、最先端のイケてる設定というよりは、必要なものをなるべく単純に実現するための設定だと認識しています。

実際これを書きながら、

「DSMの変数をそのまま利用するためにSassを入れたが、これはCSS Modulesのcomposesで表現するべきでは?」

とか、

「最近はstyled-componentsがイケているというのをよく聞くし、CSS Modulesだと何か困ることがあるのか…?」

みたいな迷いも出てきました。最適化できる部分はまだありそうです。

今後も粛々と、ビルド設定を保守・改善していこうと思っております。

スタディプラス発OSSライブラリ Jasperについて

こんにちは、Androidチームの若宮(id:D_R_1009)です。 先日、JasperというOSSライブラリをリリースしました!

github.com

今回は開発目的やモチベーション、今後の方針などを記したいと思います。

Jasperとは

スタディプラス Androidアプリ内で利用しているUIパーツをベースに開発した、UIコンポーネントライブラリです。 2019年3月時点ではJasper-BottomNavigationViewのみとなりますが、今後ゲージやグラフなどのパーツを追加する予定です。

Jasperを作成した理由について

遡ること2016年、Androidアプリは大規模なリニューアルを行いました。 ありがたいことにGoogle Play「ベストオブ2015」Google Play「ベストオブ2016」を受賞するなど、高く評価していただいています。

2016年以後も順調に機能開発、メンテナンスを続けております。 しかしながら基本的に既存機能に新たな機能を付け足す方向で開発を進めた結果、コード全体を見渡すと現在の時流に合わない実装が散見されるようになってきました。

この傾向は特に独自のUIカスタムビューに現れています。 一般にUIカスタマイズを追求していくと、Viewクラス内でCanvasの利用を行なったり、FrameLayoutを親クラスとして複数のViewを重ねがちです。 これらの手法はやりたいことに対する柔軟性が高い一方、メンテナンスのしやすさや高い描画パフォーマンスを保つ点において、開発者の技量に大きく依存していきます。

Jasperはこの問題に対する、一つの試みとなります。 開発にあたり、次の3つの目標を立てました。

  • 多くの人の目を通してUIコンポーネントの質を高める
  • 様々な要望を想定することでAPI設計を洗練させる
  • 依存関係をクリーンな状態に保つ

多くの人の目を通してUIコンポーネントの質を高める

当然の話になりますが、OSSとしてライブラリを公開すると、全てのコードを一般公開することとなります。 結果として、スタディプラス社外の人にレビューをしてもらうこと以上に、スタディプラス社内のメンバーのコードを書く意識を引き上げると感じています。

社内にのみ開かれたコードベースを触っていると、どうしてもコードに対して妥協する余地が残ってしまいます。 コードに対して、満足いくまで検討することが難しい状況な場合もあります。また歴史的な経緯により、「後ほど検討する」こととして開発を進めることもあります。

OSSとして開発することで、より純粋に「より良いコードとは何か」を考えながら開発が進められると考えています。 これは開発チームにとって、コードの技術を高める非常に良いきっかけになるのではないでしょうか。

様々な要望を想定することでAPI設計を洗練させる

UIコンポーネントの開発において、個人的に一番難しいのはAPIの設計ではないかと考えています。

とりわけどういったケースでどういった表現を許容するか、その検討に時間を取られる印象があります。 必要性に駆られて開発をスタートする際は、開発目的に沿った設計であればまず十分と判断できます。 しかし将来的な機能の拡張やinterfaceによる抽象化など、一歩踏み込んだ設計は難しい設計に分類されると思います。

OSSで開発を進めていくと、将来的には「社外のケースにおいて必要となる」条件が生まれてきます。 また、開発やレビュー時にそういったケースを考慮に入れなければなりません。 そうなると自然と検討が必須となるケースが増えることとなるでしょう。

直接的にか間接的にかは明らかではありませんが、このステップはAPIの設計を少しずつ洗練させていくと考えています。

依存関係をクリーンな状態に保つ

既存のアプリからUIコンポーネントを外部へ切り出そうとすると、当然アプリ内部の依存グラフを整理することとなります。 この結果として、クラス間の関係性がライブラリ内で完結するようになります。

すでに開発をしているBottomNavigationBarでは、AndroidSDKのMenuクラスをそのまま読み込めるよう開発しました。 このための実装は一苦労だったのですが、この結果としてJasper独自のMenuオブジェクト開発を避けることができました。

依存関係については、ライブラリ間のスイッチングコストを抑える点でも役に立ちます。 特に2019年はSupport LibからAndroidXへの移行が必須となるため、AndroidSDKとKotlinへの依存のみで開発を進める予定です。

動作だけではなく、依存関係も軽量に開発を進めていければと考えています。

Jasperの今後

スタディプラスのAndroidアプリ内で使うUIコンポーネントは、可能な限りJasperとして実装していく予定です。 このためスタディプラスのAndroidアプリを開発する限り、Jasperのメンテナンスを続けていくこととしています。

2019年はまず既存のコンポーネントをOSS化すること、そしてandroidxのサポートに取り組む予定です。 機能追加や拡張についても順次取り組みたいと考えていますが、まずはUIコンポーネントライブラリとして立ち上げたいなと考えています。

スタディプラスではすでにJinraiというライブラリを公開しています。 社内ですでにOSSを開発し利用する先例があるため、Androidチームもその流れに乗ってやりきっていこうと話し合っています。

github.com

Jinraiの紹介はこちらの記事をご参照ください。

tech.studyplus.co.jp

終わりに

Jasperについて、長々と書き連ねてしまいましたがいかがだったでしょうか。 もし関心を持っていただけましたら、ぜひGithubやGitterからご連絡ください。issueなどもお待ちしております。

github.com

gitter.im

また、スタディプラスでは一緒にJasperだけでなくスタディプラスを開発してくれるエンジニアを募集しています。 ご興味がありましたら、ぜひこちらからご連絡いただければ幸いです。