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

ソフトウェア設計原則【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. 自己紹介 名前: 阿部 耕二(あべ こうじ) 所属: パーソルクロステクノロジー株式会社   第1 技術開発本部 第4 設計部 設計2

    課 医療機器の組込みソフトウェア開発。C 言語。 趣味: 宇宙開発(リーマンサットプロジェクト広報メンバー) LAPRAS ポートフォリオ: https://lapras.com/public/k-abe Twitter: @juraruming 【連続講座】ソフトウェア設計原則【SOLID 】を学ぶ #1 単一責務の原則(single-responsibility principle) 2023 @juraruming 3
  2. 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
  3. 原則違反コードの改善ポイント 1 1. ファイル名から責務が想像できない ファイル名から処理内容が想像できたほうが良い。 shooting_watch_gpio.c ではGPIO を超えた上位の知識を持ってい る。 LED

    の名称(USER_LED1, USER_LED2 )、スイッチの名称(SW1, SW2 )を知っているのは上位のモジュールでよい。LED 、スイッチ などのデバイスがマイコンのどのピンに接続されているか知ってい るのは下位のソフトウェアモジュールというのが自然。 上位は下位より抽象的な概念を扱う(下位は具体的)。 【連続講座】ソフトウェア設計原則【SOLID 】を学ぶ #1 単一責務の原則(single-responsibility principle) 16
  4. 原則違反コードの改善ポイント 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
  5. 原則違反コードの改善ポイント 2 2. shooting_watch_gpio.c はGPIO デバイスドライバーとしての責務を 超えている デバイスドライバーは上位からの指示でデバイス制御することで再 利用しやすくなる。 デバイスドライバーの中に割り込みハンドラが書かれている。デバ

    イスドライバ単体で再利用しにくい。割り込みハンドラにはデバイ スドライバより抽象的なアプリケーションロジックを書きたいこと もある。 デバイスドライバより上位の層に割り込みハンドラを書けるように デバイスドライバは関数仕様を考えた方が使い勝手がよさそう。 【連続講座】ソフトウェア設計原則【SOLID 】を学ぶ #1 単一責務の原則(single-responsibility principle) 18
  6. 原則違反コードの改善ポイント 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
  7. 原則違反コードの改善ポイント 3 3. main 関数でハードウェアアクセス関数を呼び出している 責務を意識せず作り込みしソフトウェアの階層を無視している。 アプリケーションは実現方法( ハードウェアの具体的制御) を意識し ないつくりが良い。

    アプリケーション部でハードウェアアクセスすると非常に再利用し にくいコードになる。 【連続講座】ソフトウェア設計原則【SOLID 】を学ぶ #1 単一責務の原則(single-responsibility principle) 20
  8. 原則違反コードの改善ポイント 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
  9. 原則違反のコード改善例 対象コード: 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
  10. 【再掲】原則違反コードの改善ポイント 1 1. ファイル名から責務が想像できない ファイル名から処理内容が想像できたほうが良い。 shooting_watch_gpio.c ではGPIO を超えた上位の知識を持ってい る。 LED

    の名称(USER_LED1, USER_LED2 )、スイッチの名称(SW1, SW2 )を知っているのは上位のモジュールでよい。LED 、スイッチ などのデバイスがマイコンのどのピンに接続されているか知ってい るのは下位のソフトウェアモジュールというのが自然。 上位は下位より抽象的な概念を扱う(下位は具体的)。 【連続講座】ソフトウェア設計原則【SOLID 】を学ぶ #1 単一責務の原則(single-responsibility principle) 24
  11. 改善ポイント 1 の改善内容 ファイル名から責務が想像できるようにファイル名変更、分割をお こなった -> 改善クラス図を参照 部品の名称を知っているモジュール、部品のピン番号をしっている モジュールを明確にした 部品の名称はaps_lerning_board_bsp.h

    に定義し公開する。 ピン番号はaps_lerning_board_bsp.c に実装しヘッダーファイルで公 開しないようにした。 【連続講座】ソフトウェア設計原則【SOLID 】を学ぶ #1 単一責務の原則(single-responsibility principle) 25
  12. 【再掲】原則違反コードの改善ポイント 2 2. shooting_watch_gpio.c はGPIO デバイスドライバーとしての責務を 超えている デバイスドライバーは上位からの指示でデバイス制御することで再 利用しやすくなる。 デバイスドライバーの中に割り込みハンドラが書かれている。デバ

    イスドライバ単体で再利用しにくい。割り込みハンドラにはデバイ スドライバより抽象的なアプリケーションロジックを書きたいこと もある。 デバイスドライバより上位の層に割り込みハンドラを書けるように デバイスドライバは関数仕様を考えた方が使い勝手がよさそう。 【連続講座】ソフトウェア設計原則【SOLID 】を学ぶ #1 単一責務の原則(single-responsibility principle) 26
  13. 改善ポイント 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
  14. 【再掲】原則違反コードの改善ポイント 3 3. main 関数でハードウェアアクセス関数を呼び出している 責務を意識せず作り込みしソフトウェアの階層を無視している。 アプリケーションは実現方法( ハードウェアの具体的制御) を意識し ないつくりが良い。

    アプリケーション部でハードウェアアクセスすると非常に再利用し にくいコードになる。 【連続講座】ソフトウェア設計原則【SOLID 】を学ぶ #1 単一責務の原則(single-responsibility principle) 28