こんにちは スナックミー 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
の挙動の整理
Field
の example
を examples
への変更
deprecated
を json_schema_extra
への変更
非推奨から推奨方法へ
dict()
から model_dump()
へ
__root__
から RootModel
へ
__fields__
から model_fields
へ
class Config
から model_config = ConfigDict()
へ
必須対応
Optional
の挙動の整理
Field
の example
を examples
への変更
deprecated
を json_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では、example
を examples
に変更し、deprecated
を json_schema_extra
で表現します。
v2
class UserName(BaseModel):
name: Optional[str] = Field(
None,
title="ユーザー名",
examples=["須那田 クミ子"],
json_schema_extra={"deprecated": True}
)
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 / 株式会社スナックミー