このエントリーをはてなブックマークに追加

Symfony Advent Calendar 2021 1日目の記事です!
昨年に引き続き、来週に迫ったSymfony Worldについて紹介します。
https://live.symfony.com/2021-world-winter/

Symfony Worldとは

Symfonyのカンファレンスです。基本的に最初から最後までSymfonyの話です。たまにSDGsだったりダイバーシティのセッションもあるところがヨーロッパらしいかもしれません。
カンファレンスは全編英語ですが、リプレイできるので、もし初回で聞き取れなくても何度も復習できます。字幕も出せます(前回自分自身が登壇者になってはじめて知ったのですが、Symfony Worldの字幕はYouTubeの自動字幕だけでなく登壇者自身によって整備されています)。

(夏の時点では)コロナが落ち着いてきたので最後のオンライン開催になるだろう、とのことでした。高額な渡航費用をかけずに自宅からSymfonyのカンファレンスに参加できる最後のチャンスになりそうです。

参加費

カンファレンスを聞くだけなら119ユーロ(約1万5千円)です。例によってSymfony自体へのカンパなので、国内カンファレンスより高めになっています。

時間帯

Symfony Worldは日本時間18:00〜24:00(ヨーロッパ時間)の回と、25:30〜翌7:55(アメリカ時間)の回があります。2回ともセッション内容は同一ですが、質疑応答で新しい質問が出たら少しだけ違う話が聞けるかもしれません。
私はアジア人に優しい18:00〜枠で参加予定です!

注目セッション

day1: Removing SPOFs

https://live.symfony.com/2021-world-winter/schedule#session-602

Fabienによるkeynoteです。タイトルのみで詳細は明かされていません。
昨年のSymfonyWorldでは、このday1のkeynoteでSymfonyUXの大々的な発表がありました。今年も何があるか楽しみです!

day1: Symfony Components and Design Patterns

https://live.symfony.com/2021-world-winter/schedule#session-614

デザインパターンの利点と、Symfonyコンポーネントの中で使われているデザインパターンについての解説とのことです。

day1: The New Testing Landscape

https://live.symfony.com/2021-world-winter/schedule#session-621

BrowserKitコンポーネントとDomCrawlerコンポーネントを使って機能テストを書いてきたところから、次の新しい世界を提案してくれるようです。
JavaScriptとかfixtureとか…まさに今、試行錯誤している部分をカバーしてくれそうな予感がします。

day2: Everything about Symfony 6

https://live.symfony.com/2021-world-winter/schedule#session-599

日本時間11/30の早朝、いよいよSymfony6がリリースされました :tada:
Symfony6はPHP8.0以上が必須要件となる他、様々な新しい機能を搭載しています。私自身、このセッションを聞く前に手元で触って試してしまいそうですが、Symfony6を隅々まで知るためにマストなセッションと言えるでしょう。

day2: From big ball of mud to clean architecture with Symfony

https://live.symfony.com/2021-world-winter/schedule#session-620

Symfonyの強力なコンポーネントに依存しまくってアプリケーション開発してからの、ある日複雑すぎて途方にくれる…Symfonyで作ったアプリケーション長期運用あるあるですし、私自身がSymfony Meetup Kansai等で発表してきたネタでもあります。
同じ問題に対して他のSymfony開発者がどうやって対処しているのか、興味部深い話が聞けそうです。期待大!

まとめ

セッション一覧を見ているだけで今から楽しみでワクワクしています!(今回は自分が登壇しないので気楽です :grin:
オンラインで定員もないので、まだまだチケット購入可能です。前回Nicolasから「もっと日本のSymfonyユーザーにも参加してほしい」という言葉ももらっています 🤗
渡航費もかからないこの機会に、ぜひぜひ一緒に参加しましょうー!


このエントリーをはてなブックマークに追加

TDD (テスト駆動開発) 研修を通して学んだこと

カルテットコミュニケーションズ開発部でインターンをしている山本と申します。私は普段、大学生として機械工学を学んでいます。 FizzBuzz問題のテストコードをPHPとPhpUnitで実装した際に気が付いたことを紹介します。

目次

  • はじめに
  • テスト駆動開発の大切さ
  • タスクを分割する
  • プログラムを書いていく際の順序 (red・green・refactoring)
  • コミットを細かくする
  • おわりに

はじめに

今回僕がTDD (テスト駆動開発) 研修をするにあたって参考にさせていただいた動画がこちらです。 https://www.youtube.com/watch?v=Q-FJ3XmFlT8 この動画で話をしている方は和田 卓人さんという方でテスト駆動開発をあみ出したKent Beckの出版した「テスト駆動開発」という本を翻訳した方です。とても分かりやすい動画ですので、ぜひご覧ください。

テスト駆動開発の目的

テスト駆動開発をする目的は綺麗な動作するコードを書くためです。別に綺麗なコードを書けなくたって動けば使えるから別にいいでしょと思う人もいると思います。絶対に自分しか見なくて,過去にどんなコードを書いたか忘れないならそれでもいいと思います。ですがそれはとても難しくてレアなケースです。例えば複数人で働いていて今自分が任されているプロジェクトを他の人に任せないといけなくなった時に自分のコードがとても分かりにくいものだったらどうでしょうか。プロジェクトが始まったらまだどうにかなるかもしれませんが、終盤の場合は期日も守らないといけないので初めから書き直すと言うことはできません。この様な場合でも対応できるためにテスト駆動開発は必要だと思います。

問題解決に向けてタスクを分割する

タスク分割はテスト駆動開発をするときに何をすべきかを道しるべをしてくれる大切なものです。自分の想像していたよりもタスク分割することはとても難しい作業でした。下にあるものは今回のテストを実装したFizzBuzz問題です。試しに問題文のタスク分割をしてみて下さい。

1から100までの数をプリントするプログラムを書け。
ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

次に僕のタスク分割と見本としたタスク分割を紹介します。

- [ ] 3の倍数を「Fizz」に変換する
- [ ] 5の倍数を「Buzz」に変換する
- [ ] 3と5両方の倍数を「FizzBuzz」に変換する
- [ ] 出力する
テスト容易性:高 重要度:高
- [ ] 数を文字列に変換する
 - [ ] 1を渡すと文字列"1"を返す -> 仮実装
 - [ ] 2を渡すと文字列"2"を返す -> 三角測量

- [ ] 3の倍数のときは数の代わりに「Fizz」に変換する
 - [ ] 3を渡すと文字列"Fizz"を返す -> 仮実装 -> 実装

- [ ] 5の倍数のときは数の代わりに「Buzz」に変換する
 - [ ] 5を渡すと文字列"Buzz"を返す -> 明白な実装
- [ ] 3と5両方の倍数のときは数の代わりに「FizzBuzz」に変換する
 - [ ] 15を渡すと文字列"FizzBuzz"を返す -> 明白な実装

テスト容易性:低 重要度:低い
- [ ] 1からnまで
- [ ] 1から100まで
- [ ] プリントする

僕のToDoリストは容易性や重要度を深く考えずにできそうなことをなんとなく箇条書きにした形になっています。それに比べ見本のToDoリストは問題文を細かく分割した上にそれを自分なりにわかりやすい文に書き換え、テスト容易性や重要度を考慮して並び替えてあります。タスク分割は想像よりも難しく、テスト駆動開発をする時以外でもタスク分割をする癖をつけてスムーズに安全で綺麗なプログラムを書ける様になれるよう練習していこうと思います!

プログラムを書いていく際の順序 (red・green・refactoring)

今までエラーの沼にハマって直った時になんだこんな事かよって思ったことありませんか?redの作業はそのような無駄な時間をなくすためにエラーも予想通りに出せる様にします。一番気づきやすいのでいちばん初めにやります。 僕は今までコードを書くときはエラーが出たらそこで止まりで足踏みすることも珍しくありませんでした。知識が乏しいことが原因なことの方が多いですが、見やすいコードを目的として止まることもありました。greenの作業ではそのような無駄な時間は後に回してとりあえず動く様にします。 refactoringでは動くこと確認したら、とりあえず動くことだけを目的としたコードなので修正できる箇所はあると思うので、それを綺麗にします。 これを繰り返すことで僕がしてきた無駄な時間が減り、誰がみても簡単に解るコードを効率よく書く順序を改善できました。

コミットを細かくする

テスト駆動開発とは少しずれてしまいますが、研修中に気づいた大切なことなので共有させていただきます。僕は今までコミットがとても雑で作業がひと段落した時のみにしていました。それをコミットを細かくすることで過去の変更箇所がなんで変更したのかを明確にできることができ、自分がやったことある作業を振り返りたい時に検索できたりするのでとても便利だと言うことを教えていただきました。実際にやってみると次の週に忘れていたことも簡単に思い出したりできてとても便利だったので、もしコミットをあまりしないよって言う人がいましたらやってみて下さい!

おわりに

今回の研修ではコードを書く時に大切な知識を、たくさん知ることができました。なかなか言葉だけでは感じ取ることはできないと思うので、今回僕がやったような簡単なテスト駆動開発をやってみて下さい! 最後まで読んでくださりありがとうございました。


このエントリーをはてなブックマークに追加

はじめに

PHPチームの有澤です。

今まで自分が業務していく中で、サードパーティのAPIを使うことが多いのですが、 「こういう設計であれば使いやすくて助かる」と思うことが出てきたので、本記事で共有します😊

本題

商品情報を保存できるシステムを開発するとします。

その際に、以下のような「商品登録API」を実装するとします。

PUT /api/product


{
    "name": "おにぎり",
    "description": "ご飯を三角形・俵形・球状などに加圧成型した食べ物である。",
    "price": 100
}

ここでわかるのが、APIを受け取ったシステムのDBスキーマは、以下の構造になっていそうだと予想できます。

Product テーブル

name description price
“おにぎり” “ご飯を三角形・俵形・球状などに加圧成型した食べ物である。” 100

これらを踏まえた上で、何も考えずにAPIを実装した場合、以下の図の実装になるかと思います。

1モデルを使いまわしたシステム図

1モデルを使いまわしたシステム図

Product モデルをRequest、Response、DBスキーマの構造に使っているため、1モデルを使いまわしているシステム設計になります。 大まかな流れとしては「Productモデル(おにぎり)をWebアプリに送信して、ProductモデルをDBに保存した後、保存したProductモデルが返ってくる」イメージです。

ちなみに、商品情報を保存できる機能は、現状のシステムで実現できますが、 以下の仕様変更を加えてシステム設計を破綻させます。

仕様変更点

  • データベースにProductを登録する際、登録日時(createdAt)も保存する
  • Responseに「システム独自のステータスコード(statusCode)」を追加する

上記の仕様変更をモデルに加えた場合、システムの図は以下になります。

破綻したシステム図

破綻したシステム図

モデルを変更したことにより、以下の余計な変更が入ります。

Product Modelの構造を変更した際の意図しない影響

  • RequestにcreatedAtやstatusCodeが入っている
  • ResponseにcreatedAtが加わっている
  • データベースにstatusCodeが保存されている

1モデルを使い回す実装をしていたため、上記の余計な変更が加わるのは実は自然だと思いますが、 仕様変更の内容の割にインパクトが大きく、今後の仕様変更に耐えられない短命なシステムになりそうです。

さらに、Product(おにぎり)を送信しているにも関わらず、Product(おにぎり)は「createdAt」、「statusCode」というプロパティを持っています。 システム都合のプロパティに見えますが、これらはProduct(おにぎり)が持つ必要があったのでしょうか?

この問題が起きるのは、1モデルを使いまわすことで意図しない箇所に余計な変更が加わるためです。 これを避けるためには、共通して使われていた1モデルを分離させる必要があります。

モデルを分離した場合、以下の図になります。

Httpをモデリングしたシステム図

Httpをモデリングしたシステム図

モデルは1つから3つに増え、「Http Request Model」、「Http Response Model」というモデルが新たに加わりました。

これらのモデルはHttpを通じてAPIを実行する際の知識を持ちます。 APIを利用するクライアントの操作感にも直結したり、このモデルの知識を知ればAPIリファレンスも作成することができます。

これにより、仕様変更の際に加わる知識を、どのモデルに持たせておけば良いか判断しやすくなりました。

1モデルを使いまわしていた場合、「保存APIを実行する際に、StatusCodeを送信する必要がある仕様」になりますが、 それを避けるのに、無理やりロジックを加えることでstatusCodeにあたるプロパティを送信しなくて済む実装も可能ですが、保守性は乏しくなり、システムは破綻します。

危険な構造になっている設計だと思いますが、意外と見ることが多いのは気のせいでしょうか💧

最後に

サードパーティのAPIリファレンスを読む際に、RequestとResponseのプロパティがまとめて書かれていることがあり、 とても使いづらく、疲労困憊してしまうことがよくありました。

この問題は「HttpRequestのモデル、HttpResponseのモデル、Product(実体)としてのモデル」として分離すれば、こんな事態にはならかったのだろうと予想しています。

(ちなみに、SwaggerにはModelという括りがありますが、本記事の方法では「RequestModel」、「ResponseModel」を作ることになります)

また機会があれば、「仕様変更で破綻したシステム」と「仕様変更に耐えたシステム」のソースコードを書いて、どのくらい効果があるものかを紹介できたら良いなと思います😊