togami2864のゴミ箱

CyberAgent 2days Webフロント向け 開発型インターンシップ ONLINEに参加した

2021-04-22

3/27(土)~3/28(日)でCyberAgent 2days Webフロント向け 開発型インターンシップ ONLINEに参加した。
イベントの詳細はこちら
結論からいうと作品としてはとてもしょっぱい出来(後述)だったものの、審査員特別賞(戦略賞)をいただくことができた。
戦略賞らしく戦略とそれに至るまでの思考の過程を事前に用いた学習リソースを交えながらつらつらと書く。同じ轍を踏まないように。。。。

事前に決めていた挑戦


技術面

1: 設計にターゲットユーザーやストーリーを織り込もう
そもそもなんでいろんな会社はコード書いてるんだっけ?という疑問から始まった。
もちろんプロダクトを作るためである -> そしてプロダクトはそれを使うユーザーのためにあるよね。という考えにたどりついた。いつもデザインから始めていたが、ターゲットがいないと意味がないので今回の作品には盛り込んだ。

2: フロントエンドテストをかこう。
Jestとreact-testing-libraryを用いたテストに前から興味があり、実戦投入しようとした。

3: a11yを意識しよう。
2で上げたreact-testing-libraryと相性が良いと聞き、せっかくだから取り組もうと考えた。
簡単なものでいうとeslint-pluginの導入からはじめ、もっと踏み込んでreact-spectrum(react-aria,react-stately)を試してみようした。
ちなみに某W社でメンターをしてくださった某kobayang大先輩にネタ提供をいただきました。

技術以外の面

何をしないか/切り捨てるかの判断をしよう。
2日間という時間で開発するということで意思決定の練習としてぴったりなので設定した。
もっと具体的な言葉に落とすと、
"どんなでかいトラブルがあったとしても最後に作品が最低要件を満たしている状態である"ことを目標に設定した。なお、参加した方々はもうご存知かもしれないが、まごうことなき特大フラグである。折るどころか全身串刺しにされることとなった。

テーマ発表と市場調査

テーマはECサイトだった。
最初聞いたときAmazon・楽天みたいな総合的なECかと思っていたがAPIの内容を見るとすべてファッション系商品だった。なのでPinterestで"EC design fashion"みたいなキーワードでサイトを漁った。
サイトの構造はほぼ同じなのに受ける印象がぜんぜん違うことに気づいたのでざっくり類似点と差異を出してる点を洗い出した。代表的なのを挙げる。

共通点

  • トップにカルーセルがある
  • Headerにログイン、カートへの導線や検索ボックス
  • 女性向けの圧倒的な多さ

上2つに関してはかなりコモディティと化してた。

各社差異をつけているところ

  • カラーパターン(白 + 他の色が多い。青、ピンク、黒等)
  • 写真、商品の配置


ターゲット選定・デザイン

調査と商品をふまえて、ターゲットの選定とざっくりとしたデザインを考えた。あと商品の画像や値段帯も考慮してばばーとアイデアを出した。
デザインモック
以下リソース↓

UX MILK: UXについての話題が中心。UIの話もある。興味があるタイトルの記事を読むだけでもかなり勉強になる。今までまったくUI/UXにノータッチだった人は最初にこれらの記事を読むといいと思う。

UIとUXをこれから学ぼうとしているデザイナーへ vol1 ~ vol3: 株式会社LIGさんの記事。これでざっくりどんな感じにターゲット選定するか学んだ。

技術選定

・Next.js
嫌われがちなwebpack周りのセットアップも含めてno-configでできる。個人的にはあんまり抵抗がないが(過去にこんな記事も書いた。こんなのも作った)やはりスピーディーにできるのはありがたい。
加えてパフォーマンス周りの最適化の恩恵を受けれるので採用。

・TypeScript
これなしは考えられない。

・Styled-Components
完全に惰性で採用。というか最近ほぼこれしか使ってない。

とにかく作る

気合でとにかく作った。
ローカルのstorybookが凡ミスで動かず立ち往生してた。メンターのShagamiiさんがいなければここで爆死してました。ありがとうございました。

二日目

なんとか気合で1日目で最低要件は満たしていた。
この時点で登録やカートをギリギリつけたところであんまり代わり映えしないだろうなーという気持ちだったので投げた。
作戦を変更した。

卍あとは任せた作戦卍

・2日でできるとこまでやったんであと細かい導線と決済部分はお願いします!という状況を(勝手に)想定。
・ECサイトとしてのディティール、クオリティを捨てた。しょっぱい出来だがとにかく提出することに決めた。
・代わりに開発環境やコードのでき、発表に全振りする。
ここで施策を一部紹介します。(あくまで個人開発レベルであることに注意)

見やすいコードをつくりたい

ざっくり3つの要素を意識している。

  1. コードの一貫性
  2. パラメーターの追加が容易
  3. UIとロジックの分離


コードの一貫性

自分の中でコンポーネントの記述の規則を決めている。

//ProductCard.tsx

// ① import 層
import React from 'react';
import styled from 'styled-components';
import Link from 'next/link';
import { Image } from '../atoms/Image';

// ② type 層  命名はコンポーネント名 + Props
export interface ProductCardProps {
  id: number;
  title: string;
  category: string;
  price: number;
  image: string;
}

// ③ コンポーネント層 
export const ProductCard: React.FC<ProductCardProps> = ({
  id,
  title,
  category,
  price,
  image,
}) => {
  return (
    <Link href={`/${id}`}>
      <DetailLink>
        <ProductCardWrapper>
          <ProductCardImage>
            <Image image={image} alt={title} />
          </ProductCardImage>
          <ProductCardTitle>{title}</ProductCardTitle>
          <ProductCardCategory>{category}</ProductCardCategory>
          <ProductCardPrice>{`¥ ${price}`}</ProductCardPrice>
        </ProductCardWrapper>
      </DetailLink>
    </Link>
  );
};

// ④ style層
const ProductCardWrapper = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 10px 20px 30px;
  margin-bottom: 20px;
  max-width: 400px;
`;

const ProductCardImage = styled.div`
  width: 300px;
  height: 300px;
`;
// 以下略。。。

style層が上にくると見にくいので自ずとこのような形になった。

パラメータの変更や追加が容易

TypeScriptをフル活用して初見の人でもパラメータの変更や追加がしやすいコードを目指した。
最も顕著なのがatomsなので例にとる。

atoms

最小単位であり、最も抽象度が高い。
atomsとしてアイコンやラベルなどが採用されることが多い。そのため、色や画像のURLなどを追加したいことがあるだろう。そのため、以下のようにコンポーネントを作った。
例:今回作ったIconコンポーネント

import React from 'react';
import styled from 'styled-components';
import { Image } from './Image';

const IconInfo = {
  abemakun: {
    url: 'ファイルパス',
    alt: 'アベマくんのアイコン',
  },
};

type IconName = 'abemakun';

interface IconProps {
  width: number;
  height: number;
  name: IconName;
}

export const Icon: React.FC<IconProps> = ({ width, height, name }) => {
  const { url, alt } = IconInfo[`${name}`];
  return (
    <IconWrapper width={width} height={height}>
      <Image image={url} alt={alt} />
    </IconWrapper>
  );
};

const IconWrapper = styled.div<Pick<IconProps, 'width' | 'height'>>`
  width: ${({ width }) => `${width}px`};
  height: ${({ height }) => `${height}px`};
`;


画像にalt属性もつけたかったのでIconのマッピングオブジェクトを作った。
もしもアイコンを増やしたいときは

  • union型に値を追加
  • IconInfoにマッピングを追加

すればよい。例として矢印アイコンを追加しよう。

// 矢印アイコンを追加
const IconInfo = {
  abemakun: {
    url: 'ファイルパス',
    alt: 'アベマくんのアイコン',
  },
// mapを追加
  arrow : {
    url:'ファイルパス',
    alt:'矢印のアイコン'
 },
};

// arrowを追加
type IconName = 'abemakun' | 'arrow';

これだけで新しいアイコンを追加でき、

<Icon name="arrow" height={60} width={60}/>

と呼び出すことができる。
上記は一例だが、型やstyed-componentsのpropsをフル活用して汎用性があり、パラメータの追加や変更に強いコンポーネントを書いていくことを意識した。

UIとロジックの分離

そもそもatomic designで作ってたら自ずと分離できる。すなわちpages要素でAPIをfetchして子コンポーネントに流している。子コンポーネントで状態を持たない。
分離されていることで個々のコンポーネントのunit testやstorybookを書くのが結構楽になる。

発表準備

2日目朝に冗談で「やばいけど発表でごまかしますわw」みたいなこと言ってたら本当にやらざるを得なくなった。周りよりも資料の作成に若干早く取り掛かっていかにして作品の魅力を伝えるか考えた。

成果発表

デモはほぼなし、ひたすら作品のターゲット・コンセプトと「こういうことになったのでこう考えてこうした」ということひたすら全面に出し、3分間喋り倒した。前置きだけで1分半くらい使った気がする。
発表資料

また、案の定だったが他の参加者の作品のレベルも高かった。

他の作品で印象に残ったこと

・vuexやrecoilによるstateの永続層を持つこと。これによって実現できるアイデアにすごく幅が広がっていた印象を持った。
・同じくLocalStorage。ログイン状態なしでもいいね・カートなどを実装できててうまいと思った。セキュリティーに気をつければ十分役立つ。ホワイト/ダークモードの状態の保存とかにも使えそうだと思った。
・"自分がこれ欲しかった"という思いがアイデアの源泉になっているように感じた。各作品の独自な部分はこれから生まれていることが多かった。

フィードバックタイム

自分の唯一無二な部分がそこそこ審査員の間でも刺さってたそうです。
これに作り切る技術が伴っていれば"すーぱーえんじにゃー🐱"だったとのことなので真に受けてがんばります。
ほかにはやはり技術のキャッチアップを習慣化していきたいよねという話になった。
後ろにも書いてあるが、特にUIコンポーネントはmaterialUIくらいまでで止まっていたのでいろいろ素振りしたいと思っている。

気づき・反省

・自分がReact/Nextエアプであることが判明

他の発表を聞いてて気づいた。"Next.jsの各レンダリング方法のコアコンセプトとユースケース説明して"って言われたら100%無理。今まで雰囲気で作ってたことが露呈した。パフォーマンスやapi関連の部分に関しても全くNext.jsを活かせてなかった。
また、Recoilに関してはノータッチだった。

・UIライブラリをもっと知ろう

materialUIくらいしか知らなかった。ChakraUIというナルト味を感じるイケてて便利なライブラリがあるそうなので素振りしようと思う。AntDesignも気になる。

・自分の技量の把握 / 技術の棚卸し

今回の最も大きな失敗は不確定な事項に襲われたことではなく、自分の技量を把握してさえいればある程度コントロールできる部分(見積もり)をしくじってるせいでグダリ、後半その余波をもろにくらったことにある。
ある意味今回、自分の技量を知ることなったが、同時に技術の棚卸しも進めて現時点での得意・不得意な領域や習熟度を把握しておきたい。

・Storybook人口意外といない問題

今回に限らず最近「storybook使ってんだ!いいね!」みたいな反応をもらうことがめちゃくちゃ多い。いつも使っている環境にいたせいかもっと使ってる人多いもんだと思ってた。
webpack5への対応や次世代のbuildツールへの対応も意欲的なようです。便利なのでもっと広まれーってなってる。

最後に

めっちゃ反省はしてますけど判断自体に後悔はしてません。
「こういう状況で自分はこう考えてこう動く」っていうサンプルが取れたのでチャラってことで。。。

運営の方々を始め、チームメイトの皆さんありがとうございました!!
またどこかで!!!
以下おまけ↓

おまけ1:実はこんなこともしてた(したかった)

Commit Prefix

少し話題にもあがっていましたがCommitにprefixをつけるのは

  • 個人開発とかなら誰でもすぐに始めれる
  • 絵文字より楽(絵文字の設定に挫折した記憶が)
  • きめておくだけで若干commitの粒度に気を配れるようになる

のでおすすめ。
基準は人それぞれ違うのでおこのみで。READMEに書いておくとちょっと親切。




AWS Amplify

追加で用意されたAPIではなく卍高速でフルスタックアプリケーションを作成する卍ためのAmplifyリソース(AppSync, Cognito, DynamoDB, Lambda)で自前で実装しようとした。しかし、デプロイの際にAmplifyモジュールを初期化するのを忘れてて、そのままgithubから連携してデプロイしてたことが発覚。デプロイし直しはちょっと怖かったのとゆーて巻けんやろということでボツ。
迷走したなーっていうおもいで。


storybookをそのままテストに流用

https://storybook.js.org/docs/react/workflows/unit-testing
某W社でメンターをしてくださった某kobayang大先輩に提供してもらったネタ。このやり方賢いよねーってなった。

おまけ2

・デザインのひみつ

なんやかんやで「ユーザーの学習コスト(スイッチングコスト)高いと嫌だよね」「ユニークな操作にするのはかなり作り込まないと逆効果だしむずかしいよね」という大義名分でほとんどがいろんなECのパクリになっている。
mockはこちら



・葬り去られた.github

まさかのリポジトリをforkして開発する形式で
・github actionsが動かせない
・issueが立てれない-> issue駆動ができない
ということに直前まで気づかず、結果プルリクテンプレート以外闇に葬り去られた。



・幻のコンポーネント

幻のセレクトボックスコンポーネントが存在する。react-ariaを用いてアクセシブルな感じにした。
storybook上にも存在している。でも一切登場しない。バグポケモン。