Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TypeScriptだったらFEとBEどっちも書けるし、楽じゃない? TypeScripte...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for 玉山 玉山
October 08, 2023

TypeScriptだったらFEとBEどっちも書けるし、楽じゃない? TypeScripter vs PHPerの戦い

Avatar for 玉山

玉山

October 08, 2023
Tweet

More Decks by 玉山

Other Decks in Programming

Transcript

  1. INDEX 1 .自己紹介 2 .発表の経緯 3 .PHPとTypeScriptとは 4 .型安全性の比較 ©

    kaonavi, inc. 2 5 .ユニットテストの書きやすさ比較 6 .APIを作る上での優位性の比較 7 .まとめ
  2. たまやま りお tamayama rio 自己紹介 © kaonavi, inc. 4 所属

    株式会社カオナビ 2020年度新卒入社 職種 バックエンドエンジニア X https://x.com/tama_php
  3. 企画職 Product Manager Product Owner Director エンジニア職 Back-end Engineer Front-end

    Engineer Native Application Engineer QC Engineer SRE Infrastructure Engineer DevOps Engineer デザイナー職 UI/UX Designer © kaonavi, inc. 8 一緒に働く仲間を募集しています
  4. フロントエンドの人がバックエンドやるスイッチングコス ト無い方がよくない? • FEは破壊メソッドはあまり使わない • JSではこう書くけどPHPだとどうやって書くんだっけ? • TSだとnumberだけどPHPはint, floatとかたくさんある •

    constとかつけるけどPHPは変数宣言のキーワードは存在しない? 
 • 変数のスコープの概念が違うため、置き場所わからん 
 • などなど...
 発表の経緯 © kaonavi, inc. 13
  5. • 1995年 ◦ 開発が開始 • 1995年 6月 ◦ PHPの元祖であるPHP Toolsが誕生

    • 1998年 ◦ PHP 3.0 が公開 ◦ ElePHPantのロゴが作られる • 2011年 ◦ Laravel 1の誕生 • 2022年 12月 ◦ 現在では8.2が最新バージョン PHPとは © kaonavi, inc. 18 出典: https://www.jetbrains.com/ja-jp/lp/php-25/
  6. • 2010年 ◦ 開発が開始 • 2012年 ◦ 最初のTypeScript 0.8が公開 •

    2015年 ◦ 安定版であるTypeScript 1.0が公開 • 2016年 ◦ オープンソース化 ▪ GitHubで公開中: https://github.com/microsoft/TypeScript • 2023年 8月 ◦ 現在では5.2が最新バージョン TypeScriptとは © kaonavi, inc. 22
  7. TypeScriptとは © kaonavi, inc. 24 デメリット • 静的型付けなため制限がかかることもある • 型定義ファイルなどファイル数が少し増える

    • JavaScriptで書かれているライブラリは@typesパッケージが必要 ◦ 無い場合は.d.tsファイルを自分で作成しなければならない
  8. • 型安全性の比較 ◦ TypeScriptで書いたときのメリットって? • ユニットテストの書きやすさ比較 ◦ テストちゃんと書ける? • APIを作る上での優位性の比較

    ◦ 実際に置き換えられるの? 発表の経緯 © kaonavi, inc. 25 この2つの言語を下記観点で比較してみて置き換えが 可能か調べてみました
  9. 型安全性の比較 © kaonavi, inc. 36 function sum(a: number, b: number)

    { // Type 'string' is not assignable to type 'number'. a = '3'; return a + b; } console.log(sum(1, 2)); 数字に文字列を入れようとするパターン
  10. 型安全性の比較 © kaonavi, inc. 37 配列に対する型定義 interface Hoge { fuga:

    string; } const hoge: Hoge[] = [ { // Type 'number' is not assignable to type 'string'. fuga: 1 } ]; // Type 'number' is not assignable to type 'string'. const piyo : string[] = [1];
  11. 型安全性の比較 © kaonavi, inc. 38 interface Hoge { fuga: string;

    } const hoge: Hoge = { fuga: 'hello!' }; // Property 'piyo’ does not exist on type 'Hoge'. console.log(hoge.piyo); 型定義に無い値を取得しようとした場合
  12. 型安全性の比較 © kaonavi, inc. 39 function hoge(x: number | string)

    { if (typeof x === 'string') { // OK x.substring(1); } else { // Property 'substring' does not exist on type 'number'. x.substring(1) } // Property 'substring' does not exist on type 'string | number'. x.substring(1); } 型ガードができる
  13. 型安全性の比較 © kaonavi, inc. 41 function sum(int $a, int $b)

    { $a = '3'; return $a + $b; } var_dump(sum(1, 2)); // int(5) 数字に文字列を入れようとするパターン
  14. function sum(int $a, int $b) { return $a + $b;

    } // $a of function sum expects int, string given. var_dump(sum('1', 2)); 型安全性の比較 © kaonavi, inc. 42 数字に文字列を入れようとするパターン
  15. 型安全性の比較 © kaonavi, inc. 43 class A { // $hoge

    (array{fuga: string}) does not accept default value of type array{fuga: 123}. /** @var array{fuga: string} */ private array $hoge = ['fuga' => 123]; } 配列に対する型定義 array-shapes: https://psalm.dev/docs/annotating_code/type_syntax/array_types/#object-like-arrays
  16. 型安全性の比較 © kaonavi, inc. 44 class A { /** @var

    array{fuga: string} */ private array $hoge = ['fuga' => 'hello!']; public function get(): string { // Offset 'piyo' does not exist on array{fuga: string}. return $this->hoge['piyo']; } } 型定義に無い値を取得しようとした場合
  17. 型安全性の比較 © kaonavi, inc. 45 function format(?CarbonImmutable $date) { if

    ($date instanceof CarbonImmutable) { // OK var_dump($date->format('Y/m/d')); } else { // Cannot call method format() on null. var_dump($date->format('Y/m/d')); } // Cannot call method format() on Carbon\CarbonImmutable|null. var_dump($date->format('Y/m/d')); } 型ガードができる
  18. Mockが簡単にできる ユニットテストの書きやすさ比較 © kaonavi, inc. 50 class HogeTest extends TestCase

    { public function test(): void { $mock = $this->createMock(Hoge::class); $mock->expects($this->once())->method('getHello')->willReturn('Hello!'); var_dump($mock->getHello()); // string(6) "Hello!" } }
  19. jest • meta社製のシンプルさを重視した、快適な JavaScript テスティングフレームワーク ◦ ts-jestと@types/jestが必要 • 別々のプロセスで実行することも可能 •

    コードカバレッジも対応 • mockもできる ユニットテストの書きやすさ比較 © kaonavi, inc. 52 引用: https://jestjs.io/ja/
  20. Expectが豊富 • .toBe(value) • .toHaveBeenCalled() • .toHaveBeenCalledTimes(number) • .toHaveReturned() •

    .toBeFalsy() • .toBeNull() • .toBeTruthy() • .toBeUndefined() • .toBeNaN() • などなど… ユニットテストの書きやすさ比較 © kaonavi, inc. 53 出典: https://jestjs.io/ja/docs/expect
  21. Mockも使える • jest.spyOn() ◦ 特定のメソッドをモックに置き換える • jest.fn() ◦ mock関数として存在しない関数を作り出せる •

    jest.mock() ◦ モジュール全体をmock化できる ◦ そのファイルに書かれているすべての関数を制御下における ユニットテストの書きやすさ比較 © kaonavi, inc. 54 const spy = jest.spyOn(a, 'get').mockImplementation(() => 'Hello!'); 出典: https://jestjs.io/ja/docs/mock-function-api
  22. 今回はNestJSを選択 APIを作る上での優位性の比較 © kaonavi, inc. 58 選んだ理由 • サーバーサイドに特化している •

    DIパターンをサポートしている • Testabilityな設計 特徴 • TSで作られていて、TSで開発しやすい • Angular風 • モジュール式アーキテクチャ • 依存関係の注入ができる • アイコンが猫 +100 引用: https://nestjs.com/
  23. 今回はLaravelを選択 APIを作る上での優位性の比較 © kaonavi, inc. 60 選んだ理由 • ドキュメントなど情報が豊富にある •

    サービスコンテナ、マイグレーションなど 強力な機能が備わっている • EloquentによってDB操作を直感的にできる 特徴 • 最も利用されているPHPフレームワーク • 文法が直感的でわかりやすい • ORMが採用されている 引用: https://laravel.com/
  24. APIを作る上での優位性の比較 © kaonavi, inc. 65 function getHogeMember(): Member { //

    membersテーブルから`name`が'hoge'のレコードを取得 return Member::where('name', 'hoge')->get(); } オブジェクトリレーショナルマッピング Eloquentを使用することでDBとのやり取りを直感的にできる また、ActiveRecordパターンを採用しているので、テーブルとモデルクラスが一対一に対応して おり構造が理解しやすい
  25. APIを作る上での優位性の比較 © kaonavi, inc. 68 @Injectable() export class CatsService {

    private dogService; constructor(dogService: DogService) { this.dogService = dogService; } getCats(): { cats: string[] } { return { cats: [ 'スコティッシュフォールド ', 'マンチカン', 'アメリカンショートヘア ', 'ベンガル', this.dogService.getDogs(), ], }; } } DI Laravelの様なDIもかける しかし、Laravelみたいに自動注入はできず Moduleというものに使うサービスを設定しなけれ ばならない @Module({ controllers: [CatsController], providers: [CatsService, DogService], exports: [CatsService], }) export class CatsModule {} 出典: https://docs.nestjs.com/fundamentals/custom-providers
  26. APIを作る上での優位性の比較 © kaonavi, inc. 69 オブジェクトリレーショナル マッピング @nestjs/typeormという公式パッケージがある Entityを作ることによって、MigrateやDB操作を簡 単に行うことができます

    OneToMany, ManyToOneなどもあるため様々な リレーションもできます import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() firstName: string; @Column() lastName: string; @Column({ default: true }) isActive: boolean; } 出典: https://docs.nestjs.com/techniques/database
  27. APIを作る上での優位性の比較 © kaonavi, inc. 70 Eloquentに近い書き方ができるし、生クエリも書くことはできる where, orderBy, groupBy, limit,

    offset, joins, leftJoinAndSelect, innerJoinAndSelect, Insert, Update, Delete… const user = await getRepository(User) .createQueryBuilder("user") .where("user.id = :id", { id: 1 }) .getOne(); 出典: https://docs.nestjs.com/techniques/database