なになれ

IT系のことを記録していきます

Angular+AWS Amplifyを試した

AWS AmplifyとはAWSのリソースをクライアントアプリから直接操作することができるライブラリ群です。
これによって、サーバレスなバックエンドにすることができます。

aws-amplify.github.io

似たものではFirebaseがあります。

今回はAngular製のWebアプリでAmplifyを試した内容と所感です。

Amplify CLIをインストール

Amplifyを操作するためのCLIをインストールします。

$ npm install -g @aws-amplify/cli
$ amplify configure

指示にしたがって設定していけば、CLIの設定は完了します。

AngularでのAmplifyの使い方

新規作成

Angular CLIでアプリを新規に作成するところまで実施します。

作成したアプリに下記のnpmモジュールをインストールします。

$ npm install --save aws-amplify aws-amplify-angular 

globalオブジェクトを扱えるようにします。
polyfills.ts(window as any).global = window;を追記

設定

アプリにAmplifyを設定します。

$ amplify init

環境の名前を入力する必要があります。環境名はAmplifyの環境を分けるための識別子になります。
開発環境や本番環境といった形で環境を分けたい場合に活用します。

distribution directoryはAngularのビルド後のディレクトリを指定します。
例えば、dist/myAmplifyProject

AWSのサービスを追加

AWSのサービスは以下のようなものが用意されています。

| Category      |
| ------------- |
| analytics     |
| api           |
| auth          |
| function      |
| hosting       |
| interactions  |
| notifications |
| storage       |

api、auth、hosting、storageあたりがよく利用するものだと思います。

サービスの追加は以下のコマンドで実行します。このコマンドではローカルにサービス用のファイルが作られるだけです。

$ amplify add <category-name>

以下のコマンドで実際にAWS上にリソースが作られます。内部的な動作としてはCloud Formationが使われます。

$ amplify push

認証を試す

ここでは、authのCategoryを試します。

$ amplify add auth
$ amplify push

aws-exports.jsというファイルが作られます。
Amplifyを扱うために必要なファイルです。

以下のようにソースを修正します。

TypeScriptのオプションでJavaScriptファイルを読み込めるようにします。
aws-exports.jsをTypeScriptで読み込むために必要な設定です。

tsconfig.json

"compilerOptions": {
  "allowJs": true   // <-追加
}

Amplifyのモジュールの内部で使われるaws-js-sdkのための対応をします。

tsconfig.app.json

"compilerOptions": {
  "types": ["node"]   // <-追加
},

AngularアプリでAmplifyを使えるようにします。

main.ts

// 省略
import Amplify from 'aws-amplify';
import amplify from './aws-exports';
Amplify.configure(amplify);
// 省略

app.module.ts

// 省略
import { AmplifyAngularModule, AmplifyService } from 'aws-amplify-angular';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AmplifyAngularModule
  ],
  providers: [
    AmplifyService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

認証情報の有無で動作を変えるコードを記述します。

app.component.ts

import { Component } from '@angular/core';
import { AmplifyService } from 'aws-amplify-angular';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
    signedIn: boolean;
    user: any;
    greeting: string;
    constructor( private amplifyService: AmplifyService ) {
        this.amplifyService.authStateChange$
            .subscribe(authState => {
                this.signedIn = authState.state === 'signedIn';
                if (!authState.user) {
                    this.user = null;
                } else {
                    this.user = authState.user;
                    this.greeting = 'Hello ' + this.user.username;
                }
        });
    }
}

Amplifyで認証向けのコンポーネントが用意されているので利用します。

app.component.html

<amplify-authenticator></amplify-authenticator>

ユーザ登録からユーザのログインができるコンポーネントが表示されます。

f:id:hi1280:20190321175642p:plain

デザインが何もないので分かりづらいですが、Create accountの部分などがクリックできるようになっています。

Webアプリをホスティングする

Webアプリの場合、Hostingする必要があります。
Amplifyではこれが簡単にできます。

$ amplify add hosting
$ amplify publish

開発向けにはS3でホスティング、本番向けにはCloudFront+S3のホスティングをコマンド操作だけで完結してくれるのは便利です。

まとめ

Cloud Formationを介しているためかAWSリソースの作成に時間がかかるのが気になります。
ただAWSのリソースが簡単に使えるのが魅力で、まだまだ発展途上な様子なのでこれから期待したいサービスです。
まだ東京リージョンには対応していませんが、Amplify ConsoleというCDのサービスもあるので使ってみたいです。

参考資料

aws-amplify.github.io

エンジニアのキャリアを語るMeetUp【しがないラジオ×kiitok】に参加しました

f:id:hi1280:20190306203652j:plain:w600

エンジニアのキャリアを語るMeetUp【しがないラジオ×kiitok】に参加しました。
trackrecords.connpass.com

SIerからWeb系に転職したパーソナリティの二人がキャリアの話やTechの話をするポッドキャスト「しがないラジオ」と、転職を前提とせずに現役エンジニアにキャリアの相談ができる「kiitok(キイトク)」のコラボイベントです。

kiitokのメンターでもある、Gunosy加藤さん、エス・エム・エス田辺さん、リブセンス竹馬さんの3名から、ご自身のこれまでのキャリアに関するLTと登壇者によるパネルディスカッションが行われました。

イベントの内容と個人的な感想を書きます。

自分のポジションについて

SIerのSEです。大企業成分が含まれています。
登壇される方々はエンジニア組織のマネージャのポジションで活動されていることが興味を惹かれました。
SIerにおけるマネージャとは何が違うのか気になります。

はじまり

参加者がほぼしがないラジオリスナーでした。
しがないラジオの影響力すごい!

これまでのキャリアに関するLT(竹馬 力さん | 株式会社リブセンス不動産ユニットIESHILディベロップメントグループ グループリーダー)

内容

自己紹介

  • 2013年から現職で、サービスの立ち上げなどを経験してきた

これまでのキャリア

  • 大学卒業後、非エンジニアで働き始めたが理屈が通らない環境ですぐやめた
  • 働き始めてからいろいろ経験したが、自分を見つめ直したときに最終的にはエンジニアになると決めた

SES時代

  • 仕事が長続きしないことが当初の悩みで、我慢しながら継続していた
  • ただ先輩が愚痴だらけで成長が見込めない閉塞感があった
  • 小さな改善を繰り返した結果、SES/SIer商流上の欠陥に気づいた

ウォーターフォールからの脱却

  • 仕事量が多すぎた

苦労の乗り越え方

SES時代

  • 転職活動の中で今の現場の良さに気づいた

ウォーターフォールからの脱却

  • エンジニアリングの説明責任を果たした

現職でエンジニアリング文化を作る

  • 相手を認める心が大事
  • 副業を通して新しい技術に関わった

キャリアからの学び

SES時代

  • 人を変えるのは難しい、自分から変わった方が健全である

ウォーターフォールからの脱却

  • rubyのコミュニティなど外の世界から学んだことが役立った

成長のマインドセット

  • エンジニアは説明責任が求められるので悲観的になりがち
  • やってみようといった前向きな気持ちが大事

個人的な感想

人が好きであるということが端々の発言であり、人と接するマネージャという役割にやりがいを持っていることが感じられました。
副業で書籍を執筆したりと技術のキャッチアップも行なっていて自分の必要と周りからの必要をバランスをとりながらキャリアを積んでいるのが参考になりました。

これまでのキャリアに関するLT(たなべすなおさん | 株式会社エス・エム・エス プロダクト開発部 部長)

内容

自己紹介

  • 好きなコミュニティはRuby
  • 好きな言語はいろいろ
  • 得意分野は開発現場の改善
  • 文系出身プログラマ

どういうことを考えてキャリアを積んできたか

  • キャリアのはじめはSI系で、中盤でWeb系で働くようになった。合計で6社ほど経験した
  • グローバルに展開する大手企業から数十人規模の会社
  • 2社目から楽しく仕事してきて、転職周期は2年〜4年くらい
  • 少し先を見て、リスクを取りながら転職をしてきた
  • 大企業から小さい企業への転職は年収が下がってリスクがあった
  • 会社の立ち上げフェーズで転職したが、自分のやりたいこととはアンマッチ感があった
  • 自分の能力に不安があり、優秀なエンジニアや企画の人と働けそうな会社を選んだ。そこでは契約社員になったが能力が理由ではなかったので許容した
  • 開発組織の見直しのフェーズで経験を積める会社を選んだ

思い

  • 楽しく働きたいのがベースにある

個人的な感想

働き始めた当初から自分の現状を見て、先々この場所にいて大丈夫かという姿勢を一貫して続けられているというのが参考になりました。
2年〜4年ほどで必要性を感じたタイミングで転職を繰り返していることもその思いが現れている行動なのだと感じました。

これまでのキャリアに関するLT(加藤 慶一さん | 株式会社Gunosy技術戦略室VPoE)

内容

自己紹介

  • VPoE、採用担当をしている

これまでのキャリア

グリー時代

  • 主にソーシャルゲームのタイトルを担当した
  • ガンダムのゲームを担当してガンダムを覚えさせられた
  • ゲームの運営会社移管作業をして、孤独に作業をした
  • 濃密に作業をしていて時間の概念を感じていなかった
  • 障害対応を度々実施していたが良い経験になっている

株式会社フリークアウト時代

  • 周りの能力が高かったので、不安を感じた
  • Hadoopを触り続けた
  • 自作サーバでデータパイプラインを構築する作業を続けていた
  • 自作サーバで管理していたのが辛くなってきた

株式会社Gunosy時代

  • ニュースアプリの開発初期に関わった
  • 開発チームのマネージャをやっていくようになってきた
  • サマーインターンシップのイベント企画を実施するようになった
  • CTOやエンジニアマネージャの人がたまたまいなくなったタイミングで自分がその役割を担当するようになった
  • エンジニアの採用や育成、全社の採用担当をしている

キャリアパスについて

  • あまり仕事を選んでいなかった
  • 社内での要望に応じて仕事を続けていたら希少な存在になっていた
  • こだわらずに仕事をしていくのも良いかもしれない
  • 今ではコードをあまり書かなくなっているが、マネージャも面白いと感じている

感想

こういうキャリアの積み方もあるのかと驚きました。
人との繋がりから自然とキャリアが作られていくというのは良い話です。
信頼貯金ってあるんだなーと思いました。

スポンサーLT

エンジニアが喜ぶ制度がある企業はいいなーと思います。
いい椅子が買えたりするとか。

パネルディスカッション

転職活動をどのようにしたか

加藤 慶一さん

  • 人の紹介で転職をしてきた

たなべすなおさん

竹馬 力さん

  • リクナビNEXTで知り合ったエージェント経由
  • エージェントの人とは個人的に交遊するようになった

転職活動を気軽にしていいのか

竹馬 力さん

  • 出会いは運の要素が強い
  • 先入観を持たずにカジュアルに活動して良い

たなべすなおさん

  • 転職する気がなくても転職することもある
  • 採用側としても転職意欲が3割くらいの人でも選考に進んでくれる感覚がある
  • あまり気にせず活動して良い

加藤 慶一さん

  • カジュアルに人の紹介で転職が決まった

カジュアルに話を聞きに行ったら選考が始まる問題

  • 転職活動ということで会社にいきなり訪問するのはハードルが高い
  • kiitokのようなサービスを使うと良い

社会人3年目でのキャリアの考え方について

竹馬 力さん

  • 3年目くらいになると1人で仕事をこなせるようになってきている時期
  • 仕事に飽きていて、周りに期待をしなくなる時期

たなべすなおさん

  • 2年くらいで転職した
  • SIで下請けで働いていた
  • 会社の将来性が不安だった

加藤 慶一さん

  • 3年目で転職している
  • 自然と転職することを考えるようになった

ポジティブな理由での転職はあるか

加藤 慶一さん

  • フリークアウト、Gunosyでの人の繋がりで恩返しのつもりで転職をした

たなべすなおさん

  • 自分が楽しみながら働き続けるという意味でポジティブに転職をしている

竹馬 力さん

  • 今のところでは自分が希望していることができない点を感じて転職をしている
  • 自分視点ではポジティブに転職をしている

マネージャ職の立場で今でも技術を追っているか

加藤 慶一さん

  • 採用を簡略するためのGoogle App Scriptを書いた
  • いろいろなエンジニアと採用を面接するのに広く浅く技術をカバーするようにしている
  • 有識者の話を聞くなどをしている

たなべすなおさん

  • 技術のできないエンジニアリングマネージャと働くのは辛い
  • マネージャはプログラマの立場にたった支援をしてもらえるとありがたい
  • JavaScript界隈は追いきれない
  • ベースとなりそうな技術は原典となる技術書を読んでキャッチアップしている
  • 旬の技術はその都度必要になったら学んでいる

竹馬 力さん

  • 書籍を執筆している関係で最新のRubyRailsのバージョンは追っている
  • 個人でやっているWebサービスの中で新しい技術を使っている
  • 本業では組織が成熟してきて、技術よりも組織づくりに力を入れている
  • コードを書くよりも組織づくりの方が本業に貢献しそうだと感じている

マネージャのスタンス

  • エンジニアのマネージャはコードを書くだけではなく、組織のパフォーマンスをより良くすることを考える必要がある

マネージャは楽しいのか

たなべすなおさん

  • プログラムを書いている方が楽しい
  • マネージャは開発組織が目的に向かって働けるようにする役割
  • 半年ごとぐらいにやりがいを感じる
  • 毎日が楽しいという感覚はない

竹馬 力さん

  • エンジニアはヒューマンスキルも大事
  • メンバー同士でのコミュニケーションの場が楽しい
  • メンバー間のコミュニケーションの問題を解決しながら、組織がより良くなっていくのが見える
  • 新卒で育ててきたメンバーが会社のMVPを選ばれたのは嬉しかった
  • 人が成長する姿を見れるのが楽しい

加藤 慶一さん

  • 自分が採用した子が活躍しているのを見れるのは楽しい

エンジニアのキャリアを考える人に一言

加藤 慶一さん

  • 心の持ちようで変わる
  • 生活のリズムを変えることで感じ方も変えられる

たなべすなおさん

  • 人が経験できる会社の数には限界がある
  • 楽しくなければ転職すればいいと思う
  • 楽しくないのは何か先に閉塞感を感じているからだと思う

竹馬 力さん

  • マインドセットが大事である
  • 自分のいる場所で楽しさを見つけ出すのもスキルである

感想

お三方とも歩んできたキャリアは全然違うのにそれぞれの場所でマネージャとして活躍されているのが面白いです。
自分の興味に応じた行動力とエンジニアとしての考え方が大事なのかなと思います。

まとめ

エンジニア組織のマネージメントには何が大事なのかということが個人的な興味としてあります。
その1つの気づきとして、エンジニアとしてのキャリアを積んでいくとそれがマネージメントにも役に立つことが分かりました。
Web系のような自分たちで考えて行動する人たちに対しては、その人たちの気持ちを分かったマネージメントが大事なのだろうということを感じました。
エンジニアとしてのキャリアがある人がエンジニア組織をまとめた方がそこに所属する人たちも話が通じやすくて満足度が高いはずです。

Chrome拡張機能を作る過程で学んだReactのこと

以前にChrome拡張機能を作りました。UI部分はReactで実装しました。

hi1280.hatenablog.com

今回はこのChrome拡張機能を作る際にどのようにReactを使ったのかを紹介します。

Option Page

Chrome拡張機能の設定画面です。

f:id:hi1280:20190228220929p:plain

Material-UI

今回は以下のReact用のモジュールを使っています。

material-ui.com

Material-UIを使えば非Webデザイナーでもある程度見た目が良いWebページを作れるので利用します。

今回は、Material-UIのCSS-in-JS機能を使ってReactコンポーネントCSSを適用しています。
個人的にはこの部分を理解するのに苦労しましたので自分の整理も兼ねて説明します。

Material-UIのCSS-in-JS

CSS-in-JS機能を使うのにwithStylesという関数を使ってCSSのstyleを適用します。

コードの全体像は以下の通りです。

option.tsx

// ...省略

const styles = (theme: Theme) =>
  createStyles({
    // ...省略
  });

interface IProps extends WithStyles<typeof styles> {}

const Option = withStyles(styles)(
  class extends React.Component<IProps> {
    // ...省略
    public render() {
      const { classes } = this.props;
      return (
            // ...省略
            <main className={classes.layout}>
              <Paper className={classes.paper}>
                <Grid container={true} spacing={24}>
                  <Grid item={true} xs={12}>
                    <this.apiKeyMessage />
                  </Grid>
                </Grid>
              </Paper>
            </main>
            // ...省略
      );
    }
    // ...省略
  }
);

ReactDOM.render(<Option />, document.getElementById('option'));

このようなコードにおいて、CSSを適用する流れは以下の通りです。

  • CSSのstyleを定義する
  • propsにclassesプロパティが生成される
  • classesプロパティをコンポーネントのclass名にセットする
TypeScriptで扱う

このwithStylesを使う場合にTypeScriptでは型を扱うためちょっとした対象法を実施する必要があります。

createStyles関数を使って、withStylesの引数に与えるstyleを定義します。

option.tsx

const styles = (theme: Theme) =>
  createStyles({
    layout: {
      marginLeft: theme.spacing.unit * 2,
      marginRight: theme.spacing.unit * 2,
      width: 'auto',
      [theme.breakpoints.up(600 + theme.spacing.unit * 2 * 2)]: {
        marginLeft: 'auto',
        marginRight: 'auto',
        width: 600,
      },
    }
    // ...省略
  });

stylesの定義にしたがって、propsの型を定義します。

interface IProps extends WithStyles<typeof styles> {}

これにより、propsに型がある状態で、classesプロパティを扱うことができます。

下記がTypeScriptを使う場合の詳しい解説になります。

material-ui.com

Content Script

ここでは、Chromeで表示しているWebページにDOMを追加する処理をしていて、そのDOMがCanvasになっています。
Webページのブラウザ上で見える部分全体をCanvasとするために見える部分全体のサイズを計測する必要があります。

Reactにおけるコンポーネントのサイズの取得について説明します。

サイズの計測には下記のモジュールを利用しました。

github.com

サイズを計測するコンポーネントを配置する

Measureコンポーネントを配置します。

content-script.tsx

<Measure
  offset={true}
  onResize={contentRect => {
    this.setState({
      wrapper: contentRect.offset,
    });
  }}
>
   // サイズを計測するコンポーネントなどのコンポーネント群
</Measure>

上記ではoffsetを計測するようにしています。そのほかにもDOMのサイズに関するプロパティを計測することができます。
onResizeイベントでサイズが変更される度にstateにサイズがセットされるように定義しています。

計測の設定

content-script.tsx

  // サイズを計測するコンポーネント群
  {({ measureRef }) => (
    <Wrapper ref={measureRef}>
      <Canvas width={this.state.wrapper.width} height={this.state.wrapper.height} />
    </Wrapper>
  )}

measureRefがサイズを計測する対象のコンポーネントを指定する変数になります。
ここではCanvasがWrapperコンポーネントのサイズをstateを介して取得して、サイズをプロパティにセットしています。

この内容に関してはこちらを参考にしました。

qiita.com

共通

拡張機能のUI全般で国際化対応を行いました。

国際化対応には下記のモジュールを利用しました。

github.com

React Intlを使った国際化対応について説明します。

言語ファイルを作成する

対応する言語ごとにファイルを作成します。

ja_JP.ts

const ja_JP = {
  apikey: 'APIキー',
  config: '設定',
  popup_main: 'オプション画面でAPIキーを設定してください',
  popup_sub: 'APIキーの説明',
};
export default ja_JP;

言語ファイルの設定をコンポーネントに適用する

addLocaleData関数を使用してReact Intlで用意されているLocaleデータを読み込みます。

index.tsx

import { addLocaleData, FormattedMessage, IntlProvider } from 'react-intl';
import * as en from 'react-intl/locale-data/en';
import * as ja from 'react-intl/locale-data/ja';

// ...省略
  constructor(props: object) {
    super(props);
    addLocaleData([...en, ...ja]);
  }
// ...省略

IntlProviderコンポーネントを配置します。
このコンポーネントの範囲が国際化の対応範囲になります。

index.tsx

class Popup extends React.Component {
  private locale = navigator.language.split('_')[0];

  // ...省略

  <IntlProvider locale={this.locale} messages={Util.chooseLocale(this.locale)}>
    // 国際化の対応範囲
    <FormattedMessage id="popup_main" />
  </IntlProvider>
}

navigator.languageで利用言語を特定しています。
言語ファイルの定義に存在するキーをid属性に指定することで各言語の内容を表示することができます。

util.ts

export class Util {
  public static chooseLocale(locale: string) {
    switch (locale) {
      case 'en':
        return en_US;
      case 'ja':
        return ja_JP;
      default:
        return ja_JP;
    }
  }
}

この内容に関してはこちらを参考にしました。
lizefieldwp.azurewebsites.net

まとめ

TypeScriptでReactを使う場合、実装方法に工夫が必要になる場合があります。
なぜそのような実装なのかに気づくためにもただコードをコピペするのではなく、TypeScriptとReactをもっと理解することが必要だと感じています。
まだ色々分かっていない感じです。

参考

Chrome拡張機能における各項目がどういった役割なのかはこちらを見ると理解できると思います。

qiita.com