snaqme Engineers Blog

おやつ体験メーカー snaq.me エンジニアによる開発プロダクトブログ

第5回【社内LT会】を開催しました🎉

こんにちは。スナックミーでエンジニアをしているタク(@yamataku3831)です。

つい先日、5回目の【社内LT会】を開催しました!今回もスナックミーの業務委託メンバーである“ぱーとなー”も多く参加してくれて、ワイワイしながら情報発信を行うことができました。

今回もスナックミーらしくおやつを楽しみながら…

今回もまたマレーシアを生活の拠点としている “ぱーとなー” が、現地で売られていたおやつを紹介してくださいました!

マレーシアのポテトのスナック菓子

Salted Egg Yolk Potato Crisps」というポテトのスナック菓子で、卵黄とチリパウダーがコーティングされている、やみつきになるお菓子とのことでした!さらに全て手作りで作られているらしく、商品によってちょっと違いがあったりするみたいです。なんだかちょっと心まで温かくなるようなお菓子ですね。食べてみたい!

発表内容

ボックスバランス

発表者:野澤

野澤 - 発表資料の一部切り抜き

野澤は主にデータ基盤構築やデータ分析を担当してくれているインターンメンバーです。最近はユーザーの「飽き」に対して改善できないかと、弊社のエンジニアである兼崎と二人三脚で日々様々なアプローチで分析・仮説・検証を繰り返してくれています。

解約時の「飽き」コメントが気になったことをきっかけに、チャーンユーザーとアクティブユーザーのボックス内容に違いがあるのではないかと SHAP 分析したところ、「8つのおやつのうち、”とあるカテゴリのおやつ” がひとつ入っていると飽きにくい」という考察を得られたとのこと。

そして、上記の仮説を検証するためにボックスに含まれる “とあるカテゴリのおやつ” の割合で A/B テストを行なったところ、ボックスに “とあるカテゴリのおやつ” がひとつ入っているとチャーンレートが低くなるという結果を得られました!

これまでカテゴリによるボックスバランスの調整を行ったことがなかったこともあり、この検証結果は今後の仮説検証を推進する大きな一歩となりました。インターンメンバーの活躍がきっかけで、今後のユーザー満足度に大きな影響を与えそうな、そんなワクワクする発表内容でした!

Rails 経験者が FastAPI 本を読んで感じたこと

発表者:タク

speakerdeck.com

私は前職で Ruby on Rails を使って6年間開発をしてきました。弊社も同じフレームワークで実装しているシステムもあるのですが、FastAPI での開発がメインになりつつあるため、エンジニア採用を担当する身として自社の技術に関して、キャッチアップしておきたいなと思うようになりました。

そこで「動かして学ぶ!Python FastAPI 開発入門」を手に取り、実際に手を動かしながら勉強しました。これまでサーバーサイドは Ruby on Rails でしか開発したことがなかったので、FastAPI が魅力的に感じる部分や、新鮮に感じる部分もあったので、それを忘れないよう言語化してみました!

スライドもありますが、テックブログにも文章でまとめていますので、興味のある方は併せてご覧ください。

labs.snaq.me

おわりに

今回で5回目の社内LT会でしたが、社会人がいる前で初めて発表してくれたインターンのメンバーも、みんなからのポジティブなフィードバックが嬉しかったのか、とっても嬉しそうな笑顔を見せてくれました。

チームメンバーが情報発信をしやすい土壌を整えたくて始めた社内 LT 会なので、メンバーのそういった嬉しそうな笑顔を見るととっても嬉しく感じます。これからもこの活動は続けていこうと思います!

そんなスナックミーでは、エンジニアを積極的に探しています!この記事を読んで興味を持ってくださった方や、おやつが大好きで「おやつと世界を面白くしていきたい」とお考えの方がいらっしゃれば、ぜひ応募していただけると嬉しいです。

engineers.snaq.me

募集ポジション

ソフトウェアエンジニア Backend (lead) / 株式会社スナックミー

ソフトウェアエンジニア FrontEnd (lead) / 株式会社スナックミー

ソフトウェアエンジニア Data Engineer / 株式会社スナックミー

FastAPI 0.100 (Pydantic v2)にアップグレードしました

こんにちは スナックミー CTO の三好 (@miyoshihayato) です

はじめに

スナックミーはマイページのAPI開発をFastAPIで開発し、フロントはReactで開発しています。

詳しくは FastAPIについての採用背景

labs.snaq.me

フロントの取り組み

labs.snaq.me

こちらをご覧ください。

背景・課題

以前は、品質とスピードの間にトレードオフがあるという思い込みにより、プロダクト開発を進めていました。その結果、アップグレードへの対応力が低く、アップグレード作業には多大な労力が必要でした。

上記込みで様々な課題を解決するために 2021年にPHPからFastAPIのリプレイスすると決めて動き始めました。 課題は先ほどのFastAPIの採用背景をご覧ください。要約すると以下が要因になります。

* 高学習コスト
* コードの質
* 心理的安全性

今年7月、FastAPIのアップグレードが発表され、これを機に変更容易性を意識したアップグレードに取り組みました。(今は 2023/12/7 現在 0.104.1 が動いてます)

FastAPIの対応

主に対応したところのリスト 主に Pydantic V2に関するアップグレードがメイン

  • dict() から model_dump() への移行
  • __root__ から RootModel への移行
  • __fields__ から model_fields への移行
  • class Config から model_config = ConfigDict() への移行
  • @validation から @field_validator@model_validator への移行
  • Optional の挙動の整理
  • Fieldexampleexamples への変更
  • deprecatedjson_schema_extra への変更

非推奨から推奨方法へ

  • dict() から model_dump()
  • __root__ から RootModel
  • __fields__ から model_fields
  • class Config から model_config = ConfigDict()

必須対応

  • Optional の挙動の整理
  • Fieldexampleexamples への変更
  • deprecatedjson_schema_extra への変更

Optional 挙動の整理

v1

class UserName(BaseModel):
    name: Optional[str] = Field(title="ユーザー名", example="須那田 クミ子")

以前は、nameがNoneの場合、Noneとして扱われましたが、v2ではエラーになるため、以下のようにFieldにNoneを宣言する必要があります。

v2

class UserName(BaseModel):
    name: Optional[str] = Field(None, title="ユーザー名", example="須那田 クミ子")

Fieldの仕様変更

  • example から examples
  • deprecated から json_schema_extra

v1

class UserName(BaseModel):
    name: Optional[str] = Field(
        None,
        title="ユーザー名",
        example="須那田 クミ子",
        deprecated=True
    )

v2では、exampleexamples に変更し、deprecatedjson_schema_extra で表現します。

v2

class UserName(BaseModel):
    name: Optional[str] = Field(
        None,
        title="ユーザー名",
        examples=["須那田 クミ子"],
        json_schema_extra={"deprecated": True}
    )

Python 3.11の対応

Python 3.11へのアップデートは、Pythonのバージョンを3.8から3.11にすることによるもので、主に以下の点に対応しました。

  • Dict, List, Optional, Tuple, Union の基本廃止
  • インポート量の削減
  • コードのシンプル化

3.8

class SnaqmeInfo:
    def __init__(self) -> None:
        self.__name = str
        self.__items: List[Dict[str, int]] = []
        self.__status: Optional[Union[int, List[int]]] = None

3.11

class SnaqmeInfo:
    def __init__(self) -> None:
        self.__name = str
        self.__items: list[dict[str, int]] = []
        self.__status: int | list[int] | None = None

まとめ

今回のアップグレードは、時間的にも問題的にもスムーズに本番環境へデプロイできました。時間は合計で10時間ほどで20時間はかかってないと思います。 その成功要因としては、

  • テストのカバレッジが高い(95%以上)
  • ステージング環境での事前テスト
  • 異常検知システムの有効活用

などが挙げられます。新しい取り組みではなく、基本をしっかり押さえることがスケールアップにおいて重要であると改めて実感しました。弊社は全てを完璧に押さえることは難しいかもしれませんが、常に意識して取り組むことで、現状と将来への最善のバランスを図りながら、チームとしての開発を進めていきたいと考えています。

また、Pydantic V2へのアップグレードにより、型の取り扱いがより厳密になったと感じています。これにより、以前は曖昧だった部分をより明示的に表現しやすくなったという印象を持っています。

engineers.snaq.me

募集ポジション

ソフトウェアエンジニア Backend (lead) / 株式会社スナックミー

ソフトウェアエンジニア FrontEnd (lead) / 株式会社スナックミー

ソフトウェアエンジニア Data Engineer / 株式会社スナックミー

Rails 経験者が FastAPI 本を読んで感じたこと

こんにちは。スナックミーでエンジニアをしているタク(@yamataku3831)です。

私は前職で6年間 Ruby on Rails で Web サービスを開発してきました。スナックミーでも Ruby on Rails で開発しているシステムがあるのですが、コンシューマー向けの Web サービスに関しては FastAPI と React を使って開発をしています。

エンジニア採用を担当する身として、自分たちが使っている技術についてもしっかり伝えられるようになりたいと思い、「動かして学ぶ!Python FastAPI開発入門」という本を手に取りました。

www.shoeisha.co.jp

サーバーサイドは Ruby on Rails でしか開発してこなかったため、この本を読んで FastAPI が魅力的に感じたり、新鮮さを感じたりする部分がありました。今回はそれらを言語化したいと思います。

私と同じように Ruby on Rails で開発をしていて、FastAPI に興味を持っている方々の判断材料になれば嬉しいです。

FastAPI に魅力を感じたところ

FastAPI 自体に魅力を感じたところや、この本の中で紹介されているものに興味をそそられたものがあったので、3つにまとめてみました。

不具合を型定義により未然に防ぐ

そもそも Python は動的型付け言語でありながらも、昨今の型を重視するトレンドに例に漏れず、「型ヒント」の仕組みが導入されています。「型ヒント」を使用することで⁠コードの可読性を向上⁠したり⁠、⁠IDEによるコード補完を充実⁠させたりすることができます。

一方で、通常「型ヒント」は実行時に影響を及ぼさない仕様になっていることが多いようです。そのため、以下のように指定した型とは異なる値を変数に格納しても、Python ではエラーを発しません。

>>> order: int = 1
>>> order = ‘string’

しかし、FastAPI では Pydantic というライブラリの力によって、API の入出力のバリデーションを行う仕様となっています。 それにより、想定していない値を返却すると以下のようなエラーが発生するようになっていて、フロントエンドとバックエンドを接続して動作確認をする前に不具合を検知することができるというメリットがあります。

pydantic.error_wrappers.ValidationError: 1 validation error for Task
number
  value could not be parsed to a integer (type=type_error.integer)

Ruby 3.0 で Ruby にも型定義情報を提供する RBS という仕組みが導入され、Ruby on Rails でのアプリケーション開発でも型を使った開発が可能になっているようです。私は当時型を使用してプロダクト開発をしていなかったため、開発効率を向上する上で非常に強力な仕組みだと感じました。

特に TypeScript の普及によって型を使用した開発が一般的になってきたフロントエンド開発との相性が良さそうという印象を受けました。

フロントエンドとの協業をスムーズにする仕組み

昨今のプロダクト開発において、フロントエンドとバックエンドを分離して開発する場合が多く見られるような気がします。FastAPI はそういった開発において本領を発揮するフレームワークであるとも感じました。

FastAPI では Router にパスオペレーション関数を定義し、リクエストとレスポンスのスキーマを定義した段階で、Swagger UIのドキュメントと API モックが自動的に提供されます。

swagger.io

つまり、ビジネスロジックなど詳細な実装に手をつける前に、フロントエンドの実装に着手することができます。また継続したプロダクト開発において起こりがちな、ドキュメントの更新漏れやそれに伴って起きる実装の手戻りなどを、普段の開発の流れで解消することができる仕組みにもなっています。

以前 Ruby on Rails で開発していた時は、API を追加したり更新した場合は「忘れずに Apipie-rails のドキュメント部分も更新しましょう」といった呼びかけをしていました。そういった中で更新が漏れたりすると「やってしまった」とネガティブな気持ちになりがちだったことを思い出しました。

そういったことがこの仕組みによって改善され、精神衛生を保つことにもつながり、モチベーションとパフォーマンスを高く保ちながら開発できるひとつのソリューションになりそうだと感じました。

保守性を高めやすいアーキテクチャ

これは FastAPI 自体の魅力というよりかは、この本の中で紹介されていたアーキテクチャーに関する魅力なのですが、MVC モデルで問題になりがちな Controller や Model の肥大化を、極力避けれるような設計がなされています。

これは FastAPI のフレームワーク自体がもつ高い自由度だからこそ為せる業になりますが、この本では CRUD の処理が Router(MVC における Controller)から切り離されていました。これによって、処理やロジックをカプセル化できるようになるため、再利用性が向上することで、テスタビリティも向上することができます。

Ruby on Rails で開発している時は、Controller の中で CRUD の処理を書いていました。ただでさえ条件分岐が多くなりがちな Controller で、条件付きのデータアクセスを実装すると、その分だけテストケースが増えてしまいます。その条件分岐やそれを網羅するためのテストを Controller の外でかけるのは、非常にありがたいなと感じました。

FastAPI に新鮮さを感じたところ

自前でエクセプションを返す必要がある

この本では、データが見つからなかったときに 404 の HTTP エクセプションを返す処理を自身で実装していました。

私はこれまで Ruby on Rails で開発してきて、Active Record や Action Controllerといった仕組みの恩恵に与ってきていたこともあり、自身でエクセプションを返さなくても自動的に 404 エラーを返せていました。

そういったこともあり、実装者自ら明示的にコーディングしている点に新鮮さを感じました。忘れないよう都度実装したり、スナックミーのテックブログでも紹介させていただいているようにモジュール化したりする必要がありそうです。

labs.snaq.me

自由度の高い設計が可能

Ruby on Rails の設計理念のひとつに「CoC(Convention over Configuration: 設定より規約)」というものがあります。前職では可能な限り Ruby on Rails の規約に則り、Rails Way に沿ったプログラミングをしていたので、特にチーム開発において余計なコミュニケーションコストやドキュメント管理コストなどが発生しないよう意識しながら開発していました。

rubyonrails.org

一方で FastAPI は Ruby on Rails と比べると自由度が高いため、チームでどういった設計で実装していくのか、しっかり認識を合わせた上で開発していく必要があると感じました。現に弊社では DDD を意識して開発していることもあり、domain というディレクトリを作って、そこに各ドメインに依存したロジックなどをまとめていたりします。

おわりに

開発言語が異なる環境に転職をして、実装で苦労する部分などはありますが、様々なフレームワークについて触れることで、それぞれの良さや違いを感じることができました。またそれらを言語化することによって、開発する上で何に注意するべきかなどを把握する助けにもなると実感しました。

スナックミーは FastAPI をかなり早い段階からプロダクションで開発してきたので、今後も様々なチャレンジをして、情報を発信できるように頑張っていきたいと思います!

そんなスナックミーでは、エンジニアを積極的に探しています!この記事を読んで興味を持ってくださった方や、おやつが大好きで「おやつと世界を面白くしていきたい」とお考えの方がいらっしゃれば、ぜひ応募していただけると嬉しいです。

engineers.snaq.me

募集ポジション

ソフトウェアエンジニア Backend (lead) / 株式会社スナックミー

ソフトウェアエンジニア FrontEnd (lead) / 株式会社スナックミー

ソフトウェアエンジニア Data Engineer / 株式会社スナックミー

第4回【社内LT会】を開催しました🎉

こんにちは。スナックミーでエンジニアをしているタク(@yamataku3831)です。

つい先日、4回目の【社内LT会】を開催しました!今回もスナックミーの業務委託メンバーである“ぱーとなー”も多く参加してくれて、ワイワイしながら情報発信を行うことができました。

今回もスナックミーらしくおやつを楽しみながら…

今回は、先月韓国に帰省したときに私がスーパーで買ったおやつを紹介しました!韓国の돼지바(テジバー)というアイスクリームと、食べたことがある方もきっと多い CRUNKY がコラボしてできたお菓子です。

韓国のチョコ菓子!

ちょっとスナックミーっぽくないので、紹介しようか迷いました(笑)。ただこういう商品からインスピレーションをもらって、スナックミーらしい商品として開発につなげることもできるかも?と思ったので、今回持ってきてみた次第です。

発表内容

MSX の昔と未来

発表者:大場

大場 - 発表資料の一部切り抜き

大場はマレーシアを拠点とし、スナックミーの開発に携わっている”ぱーとなー”です。彼が「MSX」という機械をきっかけにプログラミングと出会ったのは、小学生の頃。ブラウン管と MSX を繋いでプログラミングを行い、ゲームを作って遊んでいたんだとか。

一般の人たちが MSX で作ったゲームのソースコードを集めた雑誌もあったみたいで、そのソースコードを見ながら MSX に直打ちして、同じファンの人が作ったゲームを楽しんでいたようです。なんだかエモい気持ちになりますね…!

MSX は現在も開発が続いていて、IoTプロダクトや Watch なども作られているみたいです。スナックミーとしても「ファンに愛されるプロダクト」を目指していきたいなと改めて実感しました。

フロントエンドのベースライン

発表者:小林

小林 - 発表資料の一部切り抜き

小林はフロントエンド開発に携わっている”ぱーとなー”です。今回はブラウザやモバイル OS における市場シェアや、各ブラウザにおける標準仕様の比較、iOSAndroid のCPU パフォーマンスなどを調査してくれました。

その調査結果から、Safari の標準仕様に合わせて実装することや、低スペックな Android 端末にも対応できるようパフォーマンスを考えて実装することの大切さが理解できるように。

突き詰めるとユーザーのことを考えて画面を実装することに繋がりますが、ブラウザの仕様やモバイル端末のスペックとも戦いながら実装していると知れて、改めてメンバーに対して尊敬の念を抱くよいきっかけとなりました。

おわりに

今回で4回目の社内LT会でしたが、発表してくれたメンバーからも「貴重な体験になりました!また機会があればぜひ!」と嬉しい言葉をもらえるようになってきました。

チームメンバーが情報発信をしやすい土壌を整えたくて始めた社内 LT 会なので、メンバーからそういった言葉をかけてもらうととっても嬉しく感じます。これからもこの活動は続けていこうと思います!

そんなスナックミーでは、エンジニアを積極的に探しています!この記事を読んで興味を持ってくださった方や、おやつが大好きで「おやつと世界を面白くしていきたい」とお考えの方がいらっしゃれば、ぜひ応募していただけると嬉しいです。

engineers.snaq.me

募集ポジション

ソフトウェアエンジニア Backend (lead) / 株式会社スナックミー

ソフトウェアエンジニア FrontEnd (lead) / 株式会社スナックミー

ソフトウェアエンジニア Data Engineer / 株式会社スナックミー

Framer Motion でアニメーションを実装する

こんにちは。スナックミーでフロントエンドをやっている前田です。
今回は、 snaq.me のマイページで使用している Framer Motion についてご紹介したいと思います。

Framer Motion とは

Framer Motion は複雑なアニメーションを簡単に実装できる React のライブラリです。
シンプルな例では、下記の記述で左右に 100px ずつ跳ねながら移動する円を描画できます。

<motion.div
  style={{
    width: 30,
    height: 30,
    background: "red",
    borderRadius: 30
  }}
  initial={{ translateX: 0 }}
  animate={{ translateX: 100 }}
  transition={{
    type: "spring",
    bounce: 0.5,
    repeatType: "mirror",
    duration: 2,
    repeat: Infinity
  }}
/>

デフォルトでバネのようなエフェクトが使用され、 bounce のオプションに 0~1 の少数値を指定することにより、その動きを制御できます。

bounce: 1 を使用する事はほとんどありませんが、ユーザーにしっかり気づいて欲しいインタラクションには高め(0.6 ぐらい)、自然に振る舞って欲しいときには未指定(デフォルトが 0.2)を使用する事が多いです。

なぜ Framer Motion を使うのか

Web でアニメーションを表現するには、多くの手法が存在します。

  1. gif や スプライト画像でアニメーション
  2. Lottie を使用して JSON ファイルで管理
  3. CSS アニメーション
  4. JavaScript で DOM やスタイルなどを操作

それぞれ一長一短あり、 1 や 2 はデザイナーとの協業が必要となることなどから、 UI デザインに携わらないフロントエンド実装者が主導する場合は 3, 4 の手法を取ることが多いのではないでしょうか。
しかし、どちらも少し手間がかかり、 実装時にアニメーションを定義することを習慣づけるのは難しいと考えています。

どのような手間が必要となるか、例として簡単なフェードアニメーションを実装する場合を見てみましょう。
styled-components では以下のように書けます。

const Block = styled.div<{ isShow: boolean }>`
  opacity: ${({ isShow }) => isShow ? 1 : 0};
  transition: opacity 0.2s ease;
`;

これを Props を受け取らず、レンダリング後にフェードインするように変更するには keyframes を使用します。

const fadeIn = keyframes`
  to { opacity: 1 }
`;

const Block = styled.div`
  opacity: 0;
  animation: ${fadeIn} 0.2s ease-in-out forwards;
`;

opacity の定義が分断されたことにより、少し複雑さが増してしまいました。
さて、このコンポーネントを何らかの UI 操作などでフェードアウトさせたい場合はどうなるでしょう。

const fadeIn = keyframes`
  to { opacity: 1 }
`;

const fadeOut = keyframes`
  from { opacity: 1 }
  to { opacity: 0 }
`;

const Block = styled.div<{ isShow: boolean }>`
  opacity: 0;
  animation: ${({ isShow }) => (isShow ? fadeIn : fadeOut)} 0.2s ease-in-out forwards;
`;

やり方はいろいろあるかと思いますが、今回は animation-name を Props で切り替える仕様にしてみました。
keyframes の定義が増え、fadeOut は from の記述が必須(fadeIn は不要)となるなどさらに複雑性が増したように感じます。
このような手間が必要となれば、つい isShow && <Block /> と書いてしまいたくなるのも頷けるのではないでしょうか。

今度は同様の仕様を Framer Motion で記述してみましょう。

<motion.div
  initial={{ opacity: 0 }}
  animate={{ opacity: isShow ? 1 : 0 }}
/>

だいぶすっきりしましたね。 フェードだけだと描画エリアを確保してしまうので、要素ごと消す場合には以下のように書きます。

<AnimatePresence>
  {isShow && (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  )}
</AnimatePresence>

このように、インタラクションの定義を自然に取り込める記述性の高さと、type: "spring" による目を引くエフェクトの実装しやすさから、 snaq.me では Framer Motion を採用しています。
ここまで小さなサンプルコードで紹介してきましたが、やや実践的なサンプルとして snaq.me で良く使うエフェクトもご紹介します。

Framer Motion を使う場合に考慮すべき点

Framer Motion の良いところばかりを紹介してきましたが、いくつか注意すべき点も存在します。

バンドルサイズが大きい

アニメーションのための機能が数多く提供されている Framer Motion ですが、バンドルサイズが膨らみがちな点が大きなデメリットであると考えています。
Bundlephobia によると、 minified された状態でおよそ 126KB ものファイルサイズになるようです。

bundlephobia.com

この問題については Framer Motion のドキュメントに記載されているので、目的に合わせて設定することでバンドルサイズを減らす事ができます。

www.framer.com

他のライブラリと記法が競合する

Framer Motion では styled(motion.div) などと書くことにより、初期状態のスタイルを styled-components で書くことが可能です。 しかし、 animateexit で指定するプロパティを initial 以外で指定していると正しく動作しないため、 競合しないように管理する必要があります。

// 上手く動かない
<Block animate={{ translateX: 0 }}  />

const Block = styled(motion.div)`
  transform: translateX(100);
`;

これにより、スタイルで JSX の宣言が肥大化して読みづらくなったり、事前に styled-components で定義されているスタイルにアニメーションを付けようとして上手くいかなかったりなどの問題が発生しています。 弊社では Framer Motion を使うときは style を使用するようにして回避していますが、オブジェクト形式で CSS を書くのに抵抗がある方や、デフォルトのスタイルを styled-components に寄せたい場合には問題となる可能性があります。

JSX からスタイルの定義をを分離する手法としては styled-components の attrs を使用する事でも可能ですが、 attrs の generic に MotionProps を渡す手間が発生します。

const Block = styled(motion.div).attrs<unknown, MotionProps>(() => ({
  initial: { opacity: 0 },
  animate: { opacity: 1 },
}))``;

SVG を埋め込みすぎるとバンドルサイズが大きくなる

強力で便利な Framer Motion ですが、 SVG でアニメーションで多用しすぎるとバンドルサイズを大きくする要因となります。 Framer Motion では SVG の path, g, rect, circle などのタグを motion.path, motion.g, motion.g, motion.g などに変えることで個別にアニメーションを指定可能ですが、 d 属性なども同時にバンドルされてしまうため、配信される JS ファイルのサイズに影響を及ぼします。
ファイルサイズの大きい SVG には

  • Dynamic import を使用する
  • ラフ加工されてアンカーポイントの多い SVGPNG にする
  • フロントエンドでのアニメーションは諦める(GIF や Lottie などを使う)

など、状況に合わせた対策が必要です。

まとめ

snaq.me で導入してから2年ほどが経過しましたが、今では snaq.me のマイページの多くの場所で使用しています。
その中でも特に多用しているのが snaq.me の eGift で、オンラインメッセージカードのインタラクションは Framer Motion を使用して実装しています。
近日中に、りっす(弊社の公式タレント)のかわいいクリスマス eGift カードが公開となるので是非覗いてくださいね。
(画像は実装途中の物です)

余談ですが、りっす氏は顔の作りがシンプルでデータ量が少なく、アニメーションを付けやすいのも推しポイントです。

スナックミーのエンジニアチームで直近動きたいこと (2023年10月)

こんにちは スナックミー CTO の三好 (@miyoshihayato) です
四半期ごとにチームに共有している近期の取り組みたい内容を一部変更し、こちらのエンジニアブログに載せたいと思います。

仲間集め

「仲間集め」今年は例年以上に力を入れています(特に後半から)ので、毎回仲間集めをテーマに入れ続けてます。

こちらに紹介してませんでしたが、おやつがユーザーの手元に届くまでのプロセスを詳細に解説した動画を公開しています。興味のある方は以下のリンクからご覧いただけます。

www.youtube.com

さらに、この取り組みの中でエンジニアがなぜ必要なのか、その背景と理由を動画で深堀りしています。関心がある方はこちらもチェックしてみてください。

www.youtube.com

私たちの取り組みに興味を持った方、ぜひカジュアルにお話ししてみませんか?お気軽にご連絡ください。

相談前に自分の考えを持つ取り組み

毎四半期ごとに取り組む社内テーマの一つを、新たな言い回しで紹介いたします。前回は「倍速」 に取り組み、チームの行動の迅速化を実感できるようになりました。具体的には、他チームからの要望や質問に対して、誰かが応答するのを待つのではなく、自分で積極的に対応する姿勢が増加しました。

この四半期のテーマは「自らの考えを持つ」です。スナックミーにはオペレーション、商品開発、パティシエ、CSなど多岐にわたる職種のメンバーが在籍しています。このため、様々な施策や案を実施する際、明確な方針が決まっていない段階でも前向きに取り組んでくれるメンバーが多いです(私たちの中で、このようなメンバーを「チームスナックミー」と称しています)。

しかし、様々な選択肢の中から誰かが決定した策に乗っかるのではなく、相談する前に自分の意見や考えを持つことが大切だと感じています。例えば、以下の2つの会話の違いを考えてみてください。

A案とB案どちらがいいですか?
A案とB案を考えましたが、私はA案がこの理由で良いと感じています。どう思いますか?

これらは似ていますが、後者には明確な意見や考えが反映されています。このため、実施結果を振り返った際、成功や失敗の理由を自らの経験として学び取ることができます。対照的に、前者のアプローチでは、失敗した際に「自分の意見ではなかった」という逃げの姿勢が生まれる可能性があり、成功した際もそれを自分の成果として受け取るのが難しくなると思います。

実際、私含めて全くできていないというわけではなく、意識して取り組んでいこうということになります。

来年(中長期)の課題の整理土台作り

スナックミーは定期便以外にもストア(EC)やtoB向けや卸、自社店舗(直営店)など多方面に渡り事業を大きくしていこうと考えています。 詳しくは以下をご覧ください。

www.wantedly.com

創業当初から、我々は定期便事業の最適化に努力してきました。その結果、他の事業領域と比べると、定期便の方が進展している状況ですが、それでもまだ完璧とは言えません。また、来年3月でスナックミーは創業から8年目を迎えます。この長い期間にわたり、良い意味での技術負債も積み重なってきました。数年前からは、これらの技術負債への対応を開始し、今後もその取り組みは継続していく予定です。

現在、仲間を増やす取り組みを強化する中で、事業の拡大やチームの成長に伴い、新たな技術的、組織的課題が生じると予想されます。そのため、これからの期においては、「課題の整理と土台作り」をキーセーマとして位置づけ、積極的に取り組んでいきたいと考えています。私たちエンジニアチームとしては、事業が安定して成長を続け、新しい仲間が迎え入れられる環境を整備することに焦点を当てて活動していきます。

まとめ

以上が、エンジニアチームが直近で取り組みたい3つのテーマです。 常にエンジニアの仲間を探しています。エンジニアはあらゆる面でチーム力の底上げに貢献したいと考えています(PM、バックエンド、フロントエンド、データエンジニアなど)。

興味がある方は、ぜひカジュアル面談でお話ししましょう。

おやつと、世界を面白く。」 一緒に面白くしたい仲間をお待ちしてます!!

meety.net

engineers.snaq.me

募集ポジション

ソフトウェアエンジニア Backend (lead) / 株式会社スナックミー

プロダクトマネージャー / 株式会社スナックミー

ソフトウェアエンジニア FrontEnd (lead) / 株式会社スナックミー

ソフトウェアエンジニア Data Engineer / 株式会社スナックミー

第3回【社内LT会】を開催しました🎉

こんにちは。スナックミーでエンジニアをしているタク(@yamataku3831)です。

つい先日、3回目の【社内LT会】を開催しました!今回も業務委託メンバーが多く参加してくれて、ワイワイしながら情報発信を行うことができました。

今回もスナックミーらしくおやつを楽しみながら…

今回もまたマレーシアを生活の拠点とされている業務委託の方が、現地で売られていたおやつを紹介してくださいました!

トルコの伝統的なおやつ「ロクム」

「ターキッシュ・ディライト(ロクム)」という名前で、砂糖にデンプンとさまざまな種類のナッツを加えて作る、トルコの伝統的な甘いおやつとのこと。食感は柔らかく弾力があり、日本の「ゆべし(柚餅子)」に似ているようです。食べてみたい!

発表内容

おやつ体験の「飽き」をアサインで克服したい

発表者:兼崎

中身をお見せできないのが残念!

兼崎は2年以上前に、当時インターンとしてジョインしてくれたメンバーで、非エンジニアのメンバーとコミュニケーションを取りながら、弊社のシステムを幅広く開発してくれています。

最近はおやつの定期便の満足度を向上するため、パーソナライズのロジック部分を試行錯誤してくれています。特に「飽き」という部分にフォーカスを当てており、データアナリストのインターン生と協力して、どのようにデータ分析しているかなどを共有してくれました。

とても忙しいのにも関わらず、限られたリソースの中でしっかりスライドを作ってアウトプットする姿が、スタートアップのエンジニアらしくて感動しました。

アウトプットのモチベーションはみんな違ってみんな良い!

発表者: @yamataku3831

技術広報関連の勉強会などに参加すると、どうしても採用&組織のために技術発信してくれないかと働きかける方法…みたいなことが取り上げられている印象を受けます。自分もエンジニアリングマネージャーとして、チームメンバーにはどんどん技術発信をしてもらいたくて、さまざまな施策を行っています。

ただ、いちエンジニアとして過去を振り返った時に、私が技術発信を始めるようになったのは「自分のスキルを向上させるため」だったことを思い出しました。そして技術発信のおかげで言語化能力が鍛えられ、コミュニケーションが円滑になり、徐々に仕事がしやすくなったんです。

そう考えた時に「もっと自分のために技術発信してもいいよな。その結果チームに貢献できればWin-Winだと思えるくらいのスタンスでもいいよな」と思うように。そういったことを伝えたくて、今回の発表に至りました。

おわりに

社内LT会もいよいよ3回目。チームメンバーのアウトプットに対する向き合い方が、徐々に変わりつつあるように思えます。フロントエンドエンジニアのメンバーは約3ヶ月ごとにテックブログを書いてくれますし、どうすれば定期的に記事を書けるか模索している内容を Slack に投稿してくれていたりもします。

チームメンバーが情報発信をしやすい土壌を整えたくて始めた社内LT会なので、メンバーのそういった行動をとっても嬉しく感じます。これからもこの活動は続けていこうと思います!

スナックミーでは、エンジニアを積極的に探しています!この記事を読んで興味を持ってくださった方や、おやつが大好きで「おやつと世界を面白くしていきたい」とお考えの方がいらっしゃれば、ぜひ応募していただけると嬉しいです。

engineers.snaq.me

募集ポジション

ソフトウェアエンジニア Backend (lead) / 株式会社スナックミー

ソフトウェアエンジニア FrontEnd (lead) / 株式会社スナックミー

ソフトウェアエンジニア Data Engineer / 株式会社スナックミー