$30 off During Our Annual Pro Sale. View Details »

ソフトウェア設計原則【SOLID】を学ぶ #1 単一責務の原則(single-responsibility principle)

k-abe
July 20, 2023

ソフトウェア設計原則【SOLID】を学ぶ #1 単一責務の原則(single-responsibility principle)

2023/7/20(木)社内勉強会、2023/7/21(金)Twitterスペースの資料です。
学習の振り返り・深掘りにZennのスクラップを用意しました。ご利用ください。
https://zenn.dev/k_abe/scraps/9533a6f533dd8a

リンクが有効な資料はこちらにアップロードしています。
https://www.docswell.com/s/juraruming/K98M19-2023-07-20-143150

k-abe

July 20, 2023
Tweet

More Decks by k-abe

Other Decks in Technology

Transcript

  1. 【連続講座】ソフトウェア設計原則

    SOLID
    】を学ぶ
    #1
    単一責務の原則(single-responsibility principle)
    パーソルクロステクノロジー株式会社
    第1
    技術開発本部 第4
    設計部 設計2
    課 阿部耕二
    2023 @juraruming

    View Slide

  2. 目次
    自己紹介
    SOLID
    について
    単一責務の原則(single-responsibility principle)
    について
    テーマ説明
    原則違反のコード例
    原則違反のコード改善例
    設計についてのディスカッション・質問
    今回の設計所感
    参考資料
    2

    View Slide

  3. 自己紹介
    名前:
    阿部 耕二(あべ こうじ)
    所属:
    パーソルクロステクノロジー株式会社
      第1
    技術開発本部 第4
    設計部 設計2

    医療機器の組込みソフトウェア開発。C
    言語。
    趣味:
    宇宙開発(リーマンサットプロジェクト広報メンバー)
    LAPRAS
    ポートフォリオ: https://lapras.com/public/k-abe
    Twitter: @juraruming
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    2023 @juraruming 3

    View Slide

  4. SOLID
    について
    設計の5
    原則の頭文字をとったもの。
    S
    単一責務の原則(Single Respomsibility Principle

    O
    オープン・クローズドの原則(Open Closed Principle

    L
    リスコフの置換原則(Liskov Substitution Principle

    I
    インターフェイス分離の原則(Interface Segregation Principle

    D
    依存関係逆転の原則(Dependency Inversion Principle

    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    4

    View Slide

  5. SOLID
    原則の重要性
    凝集度が高くなる
    他のモジュールと疎結合になる
    各モジュールの目的が明確に分けられると、コード変更の際の影響
    は局所化される。結果、テストしやすい設計になる。
    上記の特徴を持つと再利用しやすいコードになる。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    参考資料2
    より引用


    5

    View Slide

  6. 単一責務の原則
    (single-responsibility
    principle)
    について
    モジュールは単一の責務を持つようにする。
    モジュールはひとつのことだけをすべきであり、変更の理由もひと
    つであるべきということ。
    単一責務の原則を適用するとモジュールの凝集度が高くなる。
    まとまりのあるひとつの目的を持つ関数とデータから構成されるモ
    ジュールになる。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    参考資料2
    より引用


    6

    View Slide

  7. テーマ説明
    趣味で開発した連射測定ゲームをテーマにする。
    連射測定ゲームとは???
    私の少年時代の1980
    年後半に流行ったシュウォッチをマイコンボード
    で再現したもの。
    動画はこちら
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    7

    View Slide

  8. ゲーム実行画面
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    8

    View Slide

  9. ゲーム環境紹介
    Spresense
    メインボード
    Spresense
    拡張ボード
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ
    9

    View Slide

  10. ゲーム環境紹介2
    APS
    学習ボード:
    このボードにLED,
    スイッチが実装されている
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    10

    View Slide

  11. ゲーム環境紹介
    3
    Spresense
    メインボード +
    拡張ボード + APS
    学習ボード
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    11

    View Slide

  12. マイコン内部ブロッ
    ク図
    Spresense
    のプロセッサ
    CXD5602
    の内部ブロック図
    こちらから引用
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ
    12

    View Slide

  13. マイコン ソフトウ
    ェアフレームワーク
    Spresense SDK
    の構造
    こちらから引用
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ
    13

    View Slide

  14. 原則違反のコード例
    対象コード:
    https://github.com/grace2riku/spresense_game/tree/main/shooting_
    watch
    shooting_watch_main.c
    shooting_watch_gpio.c
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    14

    View Slide

  15. 概要のクラス図
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    15

    View Slide

  16. 原則違反コードの改善ポイント
    1
    1.
    ファイル名から責務が想像できない
    ファイル名から処理内容が想像できたほうが良い。
    shooting_watch_gpio.c
    ではGPIO
    を超えた上位の知識を持ってい
    る。
    LED
    の名称(USER_LED1, USER_LED2
    )、スイッチの名称(SW1,
    SW2
    )を知っているのは上位のモジュールでよい。LED
    、スイッチ
    などのデバイスがマイコンのどのピンに接続されているか知ってい
    るのは下位のソフトウェアモジュールというのが自然。
    上位は下位より抽象的な概念を扱う(下位は具体的)。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    16

    View Slide

  17. 原則違反コードの改善ポイント
    1
    ソースコード
    // APS
    学習ボードピンアサイン
    #define SWITCH_1 (39)
    #define SWITCH_2 (29)
    void shooting_watch_gpio_create(void)
    {
    /*
    割り込み設定 */
    board_gpio_intconfig(SWITCH_1, INT_FALLING_EDGE, true, shooting_watch_gpio_switch_1_handler);
    board_gpio_intconfig(SWITCH_2, INT_FALLING_EDGE, true, shooting_watch_gpio_switch_2_handler);
    if (board_gpio_int(SWITCH_1, true) < 0) {
    message("gpio_create board_gpio_int(switch_1) failure.\n");
    }
    if (board_gpio_int(SWITCH_2, true) < 0) {
    message("gpio_create board_gpio_int(switch_2) failure.\n");
    }
    return;
    }
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    17

    View Slide

  18. 原則違反コードの改善ポイント
    2
    2. shooting_watch_gpio.c
    はGPIO
    デバイスドライバーとしての責務を
    超えている
    デバイスドライバーは上位からの指示でデバイス制御することで再
    利用しやすくなる。
    デバイスドライバーの中に割り込みハンドラが書かれている。デバ
    イスドライバ単体で再利用しにくい。割り込みハンドラにはデバイ
    スドライバより抽象的なアプリケーションロジックを書きたいこと
    もある。
    デバイスドライバより上位の層に割り込みハンドラを書けるように
    デバイスドライバは関数仕様を考えた方が使い勝手がよさそう。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    18

    View Slide

  19. 原則違反コードの改善ポイント
    2
    ソースコード
    static int shooting_watch_gpio_switch_1_handler(int irq, FAR void *context, FAR void *arg)
    {
    ++shooting_count;
    return 0;
    }
    static int shooting_watch_gpio_switch_2_handler(int irq, FAR void *context, FAR void *arg)
    {
    int sw2_status = board_gpio_read(SWITCH_2);
    int sw1_status = board_gpio_read(SWITCH_1);
    if (sw1_status && !sw2_status) next_state = true;
    if (!sw1_status && !sw2_status) exit_shooting_watch = true;
    return 0;
    }
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    19

    View Slide

  20. 原則違反コードの改善ポイント
    3
    3. main
    関数でハードウェアアクセス関数を呼び出している
    責務を意識せず作り込みしソフトウェアの階層を無視している。
    アプリケーションは実現方法(
    ハードウェアの具体的制御)
    を意識し
    ないつくりが良い。
    アプリケーション部でハードウェアアクセスすると非常に再利用し
    にくいコードになる。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    20

    View Slide

  21. 原則違反コードの改善ポイント
    3
    ソースコード
    int main(int argc, FAR char *argv[])
    {
    int one_time_counter = 0;
    int game_coundown;
    shooting_watch_gpio_create();
    printf("Hello, shooting_watch!!!\n");
    while(exit_shooting_watch != true) {
    switch (game_state) {
    case STOP:
    if (one_time_counter == 0) {
    printf("----- Press SW2 to start the game. When the game starts, shoot SW1 continuously.-----\n");
    printf("----- Press SW1 and SW2 to end the game.-----\n");
    one_time_counter = 1;
    board_gpio_write(USER_LED_1, USER_LED_TURN_OFF);
    board_gpio_write(USER_LED_2, USER_LED_TURN_OFF);
    }
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    21

    View Slide

  22. 原則違反のコード改善例
    対象コード:
    https://github.com/grace2riku/spresense_game/tree/refactoring_srp/
    shooting_watch
    aps_lerning_board_bsp.c, aps_lerning_board_bsp.h
    controller.c, controller.h
    game.c, game.h
    initialize.c, initialize.h
    main.c
    shooting_count.c, shooting_count.h
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    22

    View Slide

  23. 改善クラス図
    23

    View Slide

  24. 【再掲】原則違反コードの改善ポイント
    1
    1.
    ファイル名から責務が想像できない
    ファイル名から処理内容が想像できたほうが良い。
    shooting_watch_gpio.c
    ではGPIO
    を超えた上位の知識を持ってい
    る。
    LED
    の名称(USER_LED1, USER_LED2
    )、スイッチの名称(SW1,
    SW2
    )を知っているのは上位のモジュールでよい。LED
    、スイッチ
    などのデバイスがマイコンのどのピンに接続されているか知ってい
    るのは下位のソフトウェアモジュールというのが自然。
    上位は下位より抽象的な概念を扱う(下位は具体的)。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    24

    View Slide

  25. 改善ポイント
    1
    の改善内容
    ファイル名から責務が想像できるようにファイル名変更、分割をお
    こなった
    ->
    改善クラス図を参照
    部品の名称を知っているモジュール、部品のピン番号をしっている
    モジュールを明確にした
    部品の名称はaps_lerning_board_bsp.h
    に定義し公開する。
    ピン番号はaps_lerning_board_bsp.c
    に実装しヘッダーファイルで公
    開しないようにした。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    25

    View Slide

  26. 【再掲】原則違反コードの改善ポイント
    2
    2. shooting_watch_gpio.c
    はGPIO
    デバイスドライバーとしての責務を
    超えている
    デバイスドライバーは上位からの指示でデバイス制御することで再
    利用しやすくなる。
    デバイスドライバーの中に割り込みハンドラが書かれている。デバ
    イスドライバ単体で再利用しにくい。割り込みハンドラにはデバイ
    スドライバより抽象的なアプリケーションロジックを書きたいこと
    もある。
    デバイスドライバより上位の層に割り込みハンドラを書けるように
    デバイスドライバは関数仕様を考えた方が使い勝手がよさそう。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    26

    View Slide

  27. 改善ポイント
    2
    の改善内容
    LED
    、スイッチの制御はaps_lerning_board_bsp
    のled_onoff,
    read_user_switch
    のみから行う方針にした。
    割り込みハンドラはデバイスドライバではなく、上位の層に定義し

    controller -> nextstate_and_exit_interrupt
    ゲーム開始・終了のスイッチ操作の割り込み
    shooting_count -> shooting_count_interrupt
    連射測定の割り込み
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    27

    View Slide

  28. 【再掲】原則違反コードの改善ポイント
    3
    3. main
    関数でハードウェアアクセス関数を呼び出している
    責務を意識せず作り込みしソフトウェアの階層を無視している。
    アプリケーションは実現方法(
    ハードウェアの具体的制御)
    を意識し
    ないつくりが良い。
    アプリケーション部でハードウェアアクセスすると非常に再利用し
    にくいコードになる。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    28

    View Slide

  29. 改善ポイント
    3
    の改善内容
    階層構造と責務の分担を意識してクラス図を書いた
    上の層はゲームの目的を達成するロジックを担当する部分
    下の層はゲームの目的を達成するための具体的な手段を担当するよ
    う意識した。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    29

    View Slide

  30. 設計についてのディスカッション・質

    自分以外の設計の視点が学びになると個人的に考えています。
    ぜひぜひお気軽にフィードバックをよろしくお願いします
    こちらに学習の振り返りに使う目的でZenn
    のスクラップを用意しま
    した。
    活用ください。
    【SOLID
    原則】"
    単一責任の原則 (single-responsibility principle)"
    の勉
    強会後の振り返り
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    30

    View Slide

  31. 今回の設計所感
    階層化を意識してファイル分割、責務分割をしたつもり。階層化の
    デメリットとして高速な動作を求められる場合は改善が必要だと感
    じた。
    設計する際は性能などの非機能要件を考慮することも大事だと改め
    て認識した。
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    31

    View Slide

  32. 参考資料
    1.
    オブジェクト指向習得のための5ステップ【SOLID
    原則】
    2.
    テスト駆動開発による組み込みプログラミング―C
    言語とオブジェク
    ト指向で学ぶアジャイルな設計
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    32

    View Slide

  33. ご清聴ありがとうございました
    【連続講座】ソフトウェア設計原則【SOLID
    】を学ぶ #1
    単一責務の原則(single-responsibility principle)
    2023 @juraruming 33

    View Slide