![](https://habrastorage.org/getpro/habr/post_images/11c/369/743/11c369743198bc984ae5fd64a673d06f.jpg)
今日では、 RESTful APIが完全に存在するようです。 支払いから予約テーブル、簡単な通知から仮想マシンの展開まで-ほぼすべてが簡単なHTTPインタラクションを通じて利用できます。
独自のサービスを開発している場合、多くの場合、複数のプラットフォームで同時に動作するようにしたいことがあります。 OOD(オブジェクト指向設計)の昔からの原則により、コードの復元力が高まり、拡張性が簡素化されます。
この記事では、SOLID(これは頭字語です)と呼ばれる特定の設計アプローチを検討します。 Slack統合を使用してサービスを作成する際に実際に使用し、 Twilioで使用するために拡張します。
このサービスは、マジックザギャザリングカードをランダムに送信します。 今すぐ動作を確認したい場合は、 マジックという言葉を1-929-236-9306に送信します(米国とカナダのみ-MMS経由で画像を受信するため、オペレーターの料金が適用される場合があります)。 こちらをクリックして、Slack組織に参加することもできます 。 ログイン後、 / magicと入力します。
SOLID for Magic
SOLIDを初めて使用する場合、これはボブ・マーティンおじさんが普及させたオブジェクト指向設計(OOD)の原則のセットです。 SOLIDは以下の頭字語です。
- S-SRP-単一責任の原則
- O-OCP-オープンクローズドプリンシプル
- L-LSP-バーバラリスコフ代替原理
- I-ISP-インターフェース分離の原則
- D-DIP-依存性反転の原理
この一連の原則に従うと、コードのフォールトトレランスが向上し、拡張性が簡素化されます。 記事の後半で、これらの各原則について詳しく説明します。
さまざまな言語の多くの良い例があります。 有名な
Shape
、
Circle
、
Rectangle
、
Area
例を繰り返す代わりに、実世界の完全に機能するアプリケーションでSOLIDの利点を示したいと思います。
私は最近Slack APIでプレイしました。 スラッシュを使用して独自のチームを作成するのは非常に簡単です。 私はマジックザギャザリングの大ファンでもあるので、マジックザギャザリングのランダムカードの画像を生成するSlackスラッシュコマンドを作成するというアイデアを思いつきました。
私はすぐにSpring Bootで計画を実行しました。 後で見るように、Spring Bootはすぐに使用できるいくつかの固い原則に従います。
Twilioには、優れた音声およびテキストメッセージングAPIがあります。 Slackの例を取り上げてTwilioと統合することがどれほど簡単かを見るのは面白いと思いました。 アイデアは、チームとテキストメッセージを既知の電話番号に送信し、マジックザギャザリングのランダムな画像を取得することです。
以下は、このプログラミング演習中の実際の動作中のSOLID原則(故障)の内訳です。
すべてのコードはここにあります 。 必要に応じて、このコードをご自身のSlackやTwilioアカウントに適用する方法については後ほど説明します。
最初の実行:Slackを使用したマジック
Spring Bootを使用してMagicアプリケーションを作成するという事実だけで、特別な労力をかけることなく、5つのSOLID原則のうち2つが即座に提供されます。 ただし、正しいアプリケーションアーキテクチャについては引き続き責任があります。
コードの作成プロセスでさまざまな原則を学習するため、GitHubプロジェクトで対応するタグを確認することで、いつでもコードサンプルを見ることができます(「リリース」セクションで確認できます)。 この章の完全なコードは、
slack-first-pass
タグで表示されます。
SlackController
コードを見てみましょう(すべてのJavaソースはここにあります:magic-app / src / main / java / com / afitnerd / magic)。これはSOLIDの
D
と
I
原則の例です。
@RestController @RequestMapping("/api/v1") public class SlackController { @Autowired MagicCardService magicCardService; @Autowired SlackResponseService slackResponseService; @RequestMapping( value = "/slack", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE ) public @ResponseBody Map<String, Object> slack(@RequestBody SlackSlashCommand slackSlashCommand) throws IOException { return slackResponseService.getInChannelResponseWithImage(magicCardService.getRandomMagicCardImage()); } }
DIP:依存関係の逆転の原則
DIPの原理は次のとおりです。
A.上位レベルのモジュールは、下位レベルのモジュールに依存しないようにしてください。 どちらのタイプのモジュールも抽象化に依存する必要があります。
B.抽象化は詳細に依存するべきではありません。 詳細は抽象化に依存する必要があります。
JavaとSpring Bootを使用すると、この原則を非常に簡単に実装できます。
SlackController
*実装*
MagicCardService
サービス。 これは、Javaインターフェースであるため、*抽象化*です。 これはインターフェースであるため、詳細はありません。
MagicCardService
の実装は
MagicCardService
ません。 後ほど、アプリケーションをモジュールに分割して、インターフェイスとその実装をこのように分離する方法を確認します。 Spring Bootで依存関係を実装する他の現代的な方法を見ていきます。
ISP:インターフェース分離の原理
ISPの原則は次のように述べています。
多くの個別のクライアントインターフェイスは、1つのユニバーサルインターフェイスよりも優れています。
SlackController
MagicCardService
と
SlackResponseService
2つの個別のインターフェイスを実装し
SlackResponseService
。 それらの1つは、マジックザギャザリングのサイトと対話します。 別の人はSlackと対話します。 これら2つの個別の機能を実行する単一のインターフェイスを作成すると、ISPの原則に違反します。
次:Twilioでの「マジック」
この章のコードを追跡するには、
twilio-breaks-srp
タグを参照してください。
TwilioControllerコードを見てください:
@RestController @RequestMapping("/api/v1") public class TwilioController { private MagicCardService magicCardService; static final String MAGIC_COMMAND = "magic"; static final String MAGIC_PROXY_PATH = "/magic_proxy"; ObjectMapper mapper = new ObjectMapper(); private static final Logger log = LoggerFactory.getLogger(TwilioController.class); public TwilioController(MagicCardService magicCardService) { this.magicCardService = magicCardService; } @RequestMapping(value = "/twilio", method = RequestMethod.POST, headers = "Accept=application/xml", produces=MediaType.APPLICATION_XML_VALUE) public TwilioResponse twilio(@ModelAttribute TwilioRequest command, HttpServletRequest req) throws IOException { log.debug(mapper.writeValueAsString(command)); TwilioResponse response = new TwilioResponse(); String body = (command.getBody() != null) ? command.getBody().trim().toLowerCase() : ""; if (!MAGIC_COMMAND.equals(body)) { response .getMessage() .setBody("Send\n\n" + MAGIC_COMMAND + "\n\nto get a random Magic the Gathering card sent to you."); return response; } StringBuffer requestUrl = req.getRequestURL(); String imageProxyUrl = requestUrl.substring(0, requestUrl.lastIndexOf("/")) + MAGIC_PROXY_PATH + "/" + magicCardService.getRandomMagicCardImageId(); response.getMessage().setMedia(imageProxyUrl); return response; } @RequestMapping(value = MAGIC_PROXY_PATH + "/{card_id}", produces = MediaType.IMAGE_JPEG_VALUE) public byte[] magicProxy(@PathVariable("card_id") String cardId) throws IOException { return magicCardService.getRandomMagicCardBytes(cardId); } }
前に述べたように、中毒の実装にはより現代的なアプローチを適用します(ベストプラクティス)。 ご覧のとおり、Spring Boot Constructor Injectionでこれを行いました。 これは、Spring Bootの最新バージョンでは、依存関係の注入が次のように行われることを示す良い方法です。
1.クラスに1つ以上の非表示フィールドを設定します。次に例を示します。
private MagicCardService magicCardService;
2.セットの非表示フィールドのコンストラクターを定義します。
public TwilioController(MagicCardService magicCardService) { this.magicCardService = magicCardService; }
Spring Bootは、実行時にオブジェクトの実装を自動的に処理します。 利点は、ここで、コンストラクター内の埋め込みオブジェクトでエラーチェックと検証を実行できることです。
コントローラーには、
/twilio
と
/magic_proxy/{card_id}
2つの部分が含まれています。 magic_proxyパスには少し説明が必要なので、まずSRPの原則に違反することについて説明する前に説明します。
TwiMLをお楽しみください
TwiMLはTwilioマークアップ言語です。 TwiMLはTwilioの指示であるため、これはすべてのTwilioの回答の基礎です。 また、XMLです。 通常、これは問題ではありません。 ただし、Magic the Gatheringサイトから返されるURLは、TwiMLドキュメントに含めるには問題があります。
Magic the Gatheringマップ画像が抽出されるURLは次のようになります。
http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=144276&type=card
URLのアンパサンド(&)に注意してください。 アンパサンドをXMLドキュメントに埋め込むには、2つの有効な方法しかありません。
1.エスケープ文字
<Response> <Message> <Body/> <Media>http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=144276&type=card</Media> </Message> </Response>
ここでは、アンパサンドの代わりに、
&
。
2. CDATAフラグメント(文字データ)
<Response> <Message> <Body/> <Media> <![CDATA[http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=144276&type=card]]> </Media> </Message> </Response>
これらのオプションはいずれも、Spring Bootに組み込まれたJackson JSONプロセッサーのJackson Dataformat XML拡張機能を使用して、Javaで簡単に実装できます。
問題は、Wizards of the Coast Webサイト(マジックザギャザリングメンテナー)から画像を受信するときに最初のオプションがエラーになり、Twilioでは2番目のオプションがサポートされないことです(ちょっとTwilio:TwiMLでCDATAサポートを実装しますか?)
リクエストのプロキシを使用してこの制限を回避しました。 この場合、TwiMLコードが生成されます:
<Response> <Message> <Body/> <Media> http://<my magic host>/api/v1/magic_proxy/144276 </Media> </Message> </Response>
このようなコードを受け取ると、Twilioはエンドポイント
/magic_proxy
参照し、すでに舞台裏でプロキシがMagic the Gathering Webサイトから画像を受信して発行します。
現在、SOLIDの原理の研究を続けています。
SRP:単独の責任原則
SRPの原則は次のとおりです。
クラスには1つの関数のみが必要です。
上記のコントローラーはそのまま動作しますが、TwiML応答と画像のプロキシの両方を返すため、SRPに違反します。
この例ではこれは大きな問題ではありませんが、状況がすぐに手に負えなくなることは容易に想像できます。
twilio-fixes-srp
タグに従うと、
twilio-fixes-srp
と呼ばれる新しいコントローラーが表示され
MagicCardProxyController
。
@RestController @RequestMapping("/api/v1") public class MagicCardProxyController { private MagicCardService magicCardService; public MagicCardProxyController(MagicCardService magicCardService) { this.magicCardService = magicCardService; } @RequestMapping(value = MAGIC_PROXY_PATH + "/{card_id}", produces = MediaType.IMAGE_JPEG_VALUE) public byte[] magicProxy(@PathVariable("card_id") String cardId) throws IOException { return magicCardService.getRandomMagicCardBytes(cardId); } }
その唯一のタスクは、Magic the Gathering Webサイトからプロキシで受信した画像のバイトを返すことです。
現在、唯一の
TwilioController
関数はTwiMLコードを発行することです。
DIP実装用のモジュール
Mavenを使用すると、プロジェクトをモジュールに簡単に分割できます。 スコープは異なっていてもかまいませんが、コンパイル(デフォルト)、実行、テストという同じスコープがあります。
モジュールがそのエリアでアクティブになると、エリアが制御を取得します。
runtime
スコープは、特定のモジュールのクラスがコンパイル時に*利用できない*ことを確認します。 それらは実行時にのみ利用可能です。 これは、DIP原則の実装に役立ちます。
例で簡単に表示できます。
modules-ftw
タグのコードを確認してください。 プロジェクトの構成が根本的に変更されたことがわかります(IntelliJで見られるように)。
![](https://habrastorage.org/getpro/habr/post_images/1dc/b34/901/1dcb34901a656194b425ed46f55f9882.png)
現在、4つのモジュールがあります。
magic-app
モジュールを見ると、
pom.xml
から他のモジュールにどのように依存しているかがわかります。
<dependencies> ... <dependency> <groupId>com.afitnerd</groupId> <artifactId>magic-config</artifactId> </dependency> <dependency> <groupId>com.afitnerd</groupId> <artifactId>magic-api</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>com.afitnerd</groupId> <artifactId>magic-impl</artifactId> <scope>runtime</scope> </dependency> </dependencies>
magic-impl
は
runtime
にあり、
magic-api
は
compile
ことに注意してください。
TwilioController
自動的にバインドします。
@RestController @RequestMapping(API_PATH) public class TwilioController { private TwilioResponseService twilioResponseService; … }
実装されたクラスをこの方法で自動的にバインドしようとするとどうなるか見てみましょう。
@RestController @RequestMapping(API_PATH) public class TwilioController { private TwilioResponseServiceImpl twilioResponseService; … }
![](https://habrastorage.org/getpro/habr/post_images/38f/275/a92/38f275a92c17705e62e43efee69863d1.png)
IntelliJはTwilioResponseServiceImplクラスを見つけることができません。これは、
compile
スコープ内に*ない*ためです。
楽しみのために、
pom.xml
から
runtime
行を削除してみてください
TwilioResponseServiceImpl
クラスを見つけて
TwilioResponseServiceImpl
ことが
TwilioResponseServiceImpl
ます。
これまで見てきたように、mavenモジュールとスコープを組み合わせることで、DIPの原則を実装できます。
フィニッシュライン:スラックリファクタリング
このアプリケーションを初めて作成したとき、SOLIDについては考えませんでした。 Slackアプリをハックして、スラッシュコマンドの機能を操作したかっただけです。
最初のバージョンでは、すべてのSlack関連のサービスとコントローラーは
Map<String, Object>
返しました。 これは、Spring Bootアプリケーションにとって良いトリックです。応答の構造を表す正式なJavaモデルを心配することなく、JSON応答を発行できます。
アプリケーションの開発に伴い、読み取り可能で信頼性の高いコードのより正式なモデルを作成したいという要望がありました。
slack-violates-lsp
のソースコードを参照してください。
magic-api
モジュールの
SlackResponse
クラスを見てみましょう。
public abstract class SlackResponse { private List<Attachment> attachments = new ArrayList<>(); @JsonInclude(JsonInclude.Include.NON_EMPTY) public List<Attachment> getAttachments() { return attachments; } @JsonInclude(JsonInclude.Include.NON_NULL) public abstract String getText(); @JsonProperty("response_type") public abstract String getResponseType(); ... }
ここで、
SlackResponse
クラスには
Attachments
配列、テキスト文字列、および
response_type
文字列があることが
SlackResponse
ます。
SlackResponse
は型
abstract
宣言し、
getText
および
getResponseType
メソッドの実装関数は子クラスに分類されます。
SlackInChannelImageResponse
子クラスの1つを見てみましょう。
public class SlackInChannelImageResponse extends SlackResponse { public SlackInChannelImageResponse(String imageUrl) { getAttachments().add(new Attachment(imageUrl)); } @Override public String getText() { return null; } @Override public String getResponseType() { return "in_channel"; } }
getText()
メソッドは
null
返し
null
。 この回答では、回答には*画像のみが含まれます。 テキストは、エラーメッセージの場合にのみ返されます。 ここ*明らかに* LSPのにおいがします。
LSP:バーバラリスク代替原理
LSPの原則は次のとおりです。
プログラム内のオブジェクトは、プログラムの精度を変更せずにサブタイプに置き換えることができる必要があります。
継承階層を処理していて、子クラス*が常に* nullを返す場合、これはLSP原則違反の明確な兆候です。 子クラスにはこのメソッドは必要ありませんが、親クラスに記述されているインターフェイスのために実装する必要があるためです。
GitHubプロジェクトの
master
ブランチをご覧ください。 そこで、
SlackResponse
階層はLSPに一致するように
SlackResponse
れました。
public abstract class SlackResponse { @JsonProperty("response_type") public abstract String getResponseType(); }
これで、実装する必要があるすべての子クラスに共通する唯一のものは
getResponseType()
メソッドです。
SlackInChannelImageResponse
クラスには、正解に必要なすべての写真が含まれています。
public class SlackInChannelImageResponse extends SlackResponse { private List<Attachment> attachments = new ArrayList<>(); public SlackInChannelImageResponse(String imageUrl) { attachments.add(new Attachment(imageUrl)); } public List<Attachment> getAttachments() { return attachments; } @Override public String getResponseType() { return "in_channel"; } … }
再び
null
を返す必要はありません。
もう1つ小さな改善があります。以前、
SlackResponse
クラスにいくつかのJSONアノテーションがあり
SlackResponse
。
@JsonInclude(JsonInclude.Include.NON_EMPTY)
と
@JsonInclude(JsonInclude.Include.NON_NULL)
です。
値がゼロの空の添付ファイル配列またはテキストフィールドがJSONに入らないことを保証するために必要でした。 これらは強力な注釈ですが、そのため、モデルのオブジェクトは脆弱になり、他の開発者には何が起こっているのかがはっきりしない場合があります。
OCP:オープン/クローズド原則
SOLIDでの旅の最後の原則はOCPです。
OCPの原則は次のとおりです。
ソフトウェアエンティティ...は拡張のために開かれている必要がありますが、変更のために閉じられている必要があります。
考え方は、参照条件を変更するとき、クラスを拡張し、既存のクラスにコードを追加しない場合、コードは新しい要件により効果的に対処するということです。 これにより、コードが忍び寄るのを防ぎます。
上記の例では、
SlackResponse
クラスを変更する追加の理由はありません。 他のタイプのSlack回答タイプのサポートをアプリケーションに追加する場合、この特異性をサブクラスで簡単に説明できます。
ここでも、Spring Bootの強さは明らかです。
magic-impl
SlackResponseServiceImpl
クラスを見てください。
@Service public class SlackResponseServiceImpl implements SlackResponseService { MagicCardService magicCardService; public SlackResponseServiceImpl(MagicCardService magicCardService) { this.magicCardService = magicCardService; } @Override public SlackResponse getInChannelResponseWithImage() throws IOException { return new SlackInChannelImageResponse(magicCardService.getRandomMagicCardImageUrl()); } @Override public SlackResponse getErrorResponse() { return new SlackErrorResponse(); } }
インターフェースによると、
getInChannelResponseWithImage
および
getErrorResponse
は
SlackResponse
オブジェクトを返します。
これらのメソッド内で、さまざまな
SlackResponse
子オブジェクトが
SlackResponse
ます。 Spring BootとJSONに組み込まれているjackson-mapperは、特定のオブジェクトに対して正しいJSONを生成するのに十分なほどスマートであり、これは内部的に特徴付けられています。
Slackで組織に統合を提供するか、Twilioアカウントのサポート(またはその両方)を実装する場合は、先に進んでください! それ以外の場合は、記事の最後にある履歴書にアクセスできます。
アプリケーションの展開
このアプリケーションを最大限に使用する場合は、Herokuにアプリケーションをデプロイした後、SlackとTwilioを適切に構成する必要があります。
または、SlackまたはTwilioをインストールできます。 いずれの場合でも、最初に行う必要があるのは、アプリケーションをHerokuにデプロイすることです。 幸いなことに、それは簡単です。
Herokuの展開
アプリケーションをHerokuにデプロイする最も簡単な方法は、GitHubプロジェクトのREADMEセクションにある紫色のフレンドリーなボタンをクリックすることです。
BASE_URL
と
SLACK_TOKENS
2つの詳細を指定する必要があります。
BASE_URL
は、Herokuアプリケーションの完全なパスと名前です。 たとえば、 https : //random-magic-card.herokuapp.comにアプリケーションをインストールしています 。 アプリケーション名を選択するときは、
https://<app name>.herokuapp.com
と同じ形式に従い
https://<app name>.herokuapp.com
。
HerokuにはSlackからの情報が必要であり、Slackの統合にはHerokuについての情報が必要であるため、ここには鶏卵に関する問題があります。 最初は、デフォルト値を
SLACK_TOKENS
フィールドに残しておくことができます。後でこの値を返し、現在のSlack APIトークンで更新します。
https://<app name>.herokuapp.com
して、インストールを確認でき
https://<app name>.herokuapp.com
。 ブラウザにマジックザギャザリングマップがランダムに表示されます。 エラーが発生した場合は、HerokuアプリケーションのWebインターフェイスでエラーログを確認してください。 動作中のWebインターフェイスの例を次に示します 。
スラックのセットアップ
https://api.slack.com/appsに移動し、[
Create New App
の
Create New App
]ボタンをクリックして開始します。
![](https://habrastorage.org/getpro/habr/post_images/490/591/d0c/490591d0c324beebd5471a622c9d6682.png)
名前
App Name
を入力し、アプリケーションを追加する
Workspace
を選択します。
![](https://habrastorage.org/getpro/habr/post_images/f4e/238/a70/f4e238a702026a0dba23a6b413e92aa8.png)
次に、左側のスラッシュコマンド
Slash Commands
リンクをクリックします。新しいコマンドを作成するためのボタンがあります新しいコマンドの
Create New Command
:
![](https://habrastorage.org/getpro/habr/post_images/4a7/35f/3e5/4a735f3e598e4be981ee4c2eecdd1242.png)
コマンドの値(例:
/magic
)、
Request URL
(例:
https://<your app name>.herokuapp.com/api/v1/slack
)および短い説明を入力します。 次に[
Save
]をクリックし
Save
。
![](https://habrastorage.org/getpro/habr/post_images/457/162/919/45716291997dfca0c064850a0a0fc701.png)
Slackのスラッシュコマンドが完全に構成されました。
![](https://habrastorage.org/getpro/habr/post_images/287/68e/ae1/28768eae1e16889b3964f61980305898.png)
左ペインの
Install app to your workspace section
Basic Information
セクションに移動し、画面上の
Install app to your workspace section
に
Install app to your workspace section
の
Install app to your workspace section
を展開します。 [
Install app to Workspace
]ボタンをクリックします。
![](https://habrastorage.org/getpro/habr/post_images/ecf/bf2/5b4/ecfbf25b409fe8ed84c5365c1df13fb8.png)
次に、承認のためのボタン:
![](https://habrastorage.org/getpro/habr/post_images/030/2a2/956/0302a2956aa441009f4646850fd1377e.png)
戻った
Basic Information
画面までスクロールし、検証トークンを記録します。
![](https://habrastorage.org/getpro/habr/post_images/b7d/855/8d4/b7d8558d4f1b12c773c2f8509a3f94db.png)
Heroku CLIをインストールした場合、次のコマンドで
SLACK_TOKENS
プロパティ
SLACK_TOKENS
正しく設定できます。
heroku config:set \ SLACK_TOKENS=<comma separated tokens> \ --app <your heroku app name>
または、 Herokuダッシュボードに移動し、アプリケーションに移動して、設定の
SLACK_TOKENS
値を変更します。
これで、組織のSlackチャンネルでスラッシュコマンドが機能するはずです。その代わりに、マジックザギャザリングカードを受け取ります。
![](https://habrastorage.org/getpro/habr/post_images/b4e/b34/ead/b4eb34eade4d648d39c6a9152615f696.png)
Twilioのセットアップ
Twilio統合を構成するには、コンソールのTwilioダッシュボードに移動します。
![](https://habrastorage.org/getpro/habr/post_images/312/437/179/312437179a21639161ae7b11a40bfc49.png)
省略記号をクリックして、
Programmable SMS
を選択します。
![](https://habrastorage.org/getpro/habr/post_images/349/2af/d8f/3492afd8f1206b9abd1eb6cabbc450ee.png)
Messaging Services
選択し
Messaging Services
。
![](https://habrastorage.org/getpro/habr/post_images/920/f6a/c0f/920f6ac0f620cd5123e30b03b21df9cf.png)
赤いプラスの付いたボタンをクリックして、新しいメッセージングサービスを作成します(サービスがまだない場合は[新しいメッセージングサービスの作成]をクリックします)。
![](https://habrastorage.org/getpro/habr/post_images/e80/f23/271/e80f23271aea37606a32c0dc756f34d2.png)
Friendly Name
入力し、[
Use Case
]列で[
Notifications, 2-Way
Friendly Name
を選択し、[
Create
]をクリックし
Create
。
![](https://habrastorage.org/getpro/habr/post_images/289/e21/988/289e21988648ec6cb120b1f897b51381.png)
Process Inbound Messages
チェックマークを確認し、Herokuアプリケーションの
Request URL
を
Request URL
します(例
https://<your app name>.herokuapp.com/api/v1/twilio
):
![](https://habrastorage.org/getpro/habr/post_images/62f/af7/e7d/62faf7e7da8fd9867de50ed0886137f0.png)
[
Save
]ボタンをクリックして、変更を保存します。
左メニューの[
Numbers
セクションに移動し、メッセージングサービスにTwilio番号が追加されていることを確認します。
![](https://habrastorage.org/getpro/habr/post_images/c5e/833/b43/c5e833b43393e15226dd6dbc97c2b632.png)
これで、
magic
という単語を番号にテキストメッセージとして送信して、Twilioサービスをテストできます。
![](https://habrastorage.org/getpro/habr/post_images/8bf/e06/0b3/8bfe060b3545138ae2c0e62dbb2b14b1.png)
**注:**大文字と小文字を問わず、
magic
という単語以外を送信すると、上記のエラーメッセージが表示されます。
ソリッドサマリー
もう一度、SOLIDテーブルを公開します。今回は、各原則に一致するGithubプロジェクトタグを使用します。
- S-SRP-唯一の責任の原則。 タグ:
twilio-fixes-srp
TwilioController
コントローラーを2つの部分に分割します。各コントローラーには1つの機能しかありません。 - O-OCP-オープンネス/クローズネスの原則。 タグ:
master
SlackResponse
クラスSlackResponse
ワンピースであり、変更できません。 既存のサービスのコードを変更せずに拡張できます。 - L-LSP-バーバラリスコフの置換原理。 タグ:
master
SlackResponse
子クラスはどれもnull
返さず、不要なクラスや注釈は含まれません。 - I-ISP-インターフェースの分離の原理。 タグ:
slack-first-pass
master
SlackResponseService
とSlackResponseService
は異なる機能を実行するため、互いに分離されています。 - D-DIP-依存関係の反転の原理。 タグ:
slack-first-pass
master
依存サービスは自動的にコントローラーにバインドされます。 コントローラーの実装は、依存性注入の「ベストプラクティス」です。
このアプリケーションの開発にはいくつかの困難があります。TwiMLの問題については、すでに上で述べました。しかし、Slackには、この記事で説明した特別な問題があります。TL; DR:Slackは
application/x-www-form-urlencoded
、最新のコマンドではなく、スラッシュコマンドの*のみ* POSTリクエストを受け入れます
application/json
。これにより、Spring BootでJSON入力を処理することが難しくなります。
基本的な考え方は、SOLIDの原則により、コードの作業と拡張がはるかに簡単になるということです。
これで、SOLID原則の概要は終わりです。通常の単純なJavaの例よりも便利であることを願っています。