0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

サービスアーキテクチャの進化ロードマップ

0
Last updated at Posted at 2026-05-02

1.1 サービスアーキテクチャの演変

サービスアーキテクチャは、ビジネスの規模拡大と技術的な要求の変化に伴い、段階的に進化を遂げてきました。以下に、主要な4つの発展段階とその技術スタックを整理します。

image.png

1. 単体アプリケーション(ORM / All in One)

初期の小規模なシステムで採用される構成です。

  • 概念: すべての機能ユニットを一つのアプリケーションにまとめ、単一のプロセスとしてデプロイします。
  • プロセス: 負荷が増大した場合は、アプリケーション全体を水平方向にコピーして拡張し、ロードバランサーでトラフィックを分散させます。
  • 適用シーン: クラスター規模が 1 〜 10台 程度の初期段階に最適です。
  • 主要技術: データベース操作を効率化する ORM フレームワークが中心となります。

2. 垂直型アプリケーション(MVC / Vertical Application)

トラフィックの増加に伴い、アプリケーションを機能ごとに切り離した段階です。

  • 概念: 肥大化した単体アプリケーションを、業務ロジックごとに独立した複数のアプリケーションへ分割します。
  • プロセス: 各アプリケーションを個別にデプロイ・拡張することで、特定の機能へのトラフィック集中に対応します。
  • 適用シーン: クラスター規模が 10 〜 1000台 程度の中規模システムに適しています。
  • 主要技術: UIとロジックを分離する MVC アーキテクチャが採用されます。

3. 分散サービス(RPC / Distributed Service)

重複するビジネスロジックを共通サービスとして抽出し、疎結合化を進めた段階です。

  • 概念: コアとなるビジネスロジックを独立したサービスとして切り出し、ネットワーク越しに呼び出す構成をとります。
  • プロセス: サービス間の通信を標準化し、コードの再利用性を高めます。
  • 適用シーン: クラスター規模が 1000 〜 10000台 に達する大規模システムで必要となります。
  • 主要技術: 遠隔手続き呼び出しを行う RPC フレームワークが基盤となります。

4. 弾力的コンピューティング(SOA / Elastic Computing)

サービスの数が増大し、動的な管理とガバナンスが不可欠になった段階です。

  • 概念: サービス間の依存関係を動的に管理し、リソースを効率的に配分する「サービス指向アーキテクチャ」です。
  • プロセス: サービスレジストリによる自動的な発見や、流量制御、高度な負荷分散を組み込みます。
  • 適用シーン: クラスター規模が 10000台以上 の超大規模プラットフォームに適用されます。
  • 主要技術: サービスのガバナンスを司る SOA(Service Oriented Architecture)の概念が中心となります。

1.2 モノリス(単体)アーキテクチャの徹底解剖

クラウドネイティブ時代においても、システムの進化の原点である「モノリス(単体)アーキテクチャ」を理解することは非常に重要です。

アーキテクチャの概要と特徴

従来のシステムアーキテクチャ(単一マシンシステム)は、「1つのプロジェクト=1つのアプリケーション」という非常にシンプルな構成をとります。

  • All in One構成: 商品管理、注文処理、決済、在庫管理、ログイン、ユーザー登録など、システムに必要なすべての機能ユニットを一つのアプリケーション内に統合します。
  • 単一プロセスでの稼働: 統合されたすべての機能は、サーバー上の1つのプロセスとして実行され、一括でデプロイされます。
  • スケーリング戦略: トラフィックが増加してサーバーの負荷耐性が限界に達した場合は、アプリケーション全体を水平方向に複製(コピー)してサーバーを増設し、ロードバランサーを経由してアクセスを振り分けることで拡張を図ります。

技術スタック(Javaエコシステムの場合)

  • 実装とパッケージング: Java環境における伝統的な実装としては、JSPやServletを用い、最終的にアプリケーション全体を1つの jar または war ファイルとしてパッケージ化し、デプロイします。
  • Webアプリケーションサーバー: オープンソース製品(Tomcat、Jetty、GlassFishなど)や、商用製品(WebLogic、WebSphere、JBossなど)が利用されます。

モノリスアーキテクチャのメリット(利点)

小規模なシステムや立ち上げ初期のプロジェクトにおいては、強力な選択肢となります。

  • 開発とテストが容易: プロジェクトが一つにまとまっているため、ローカル環境での立ち上げやテストがシンプルに行えます。
  • デプロイが簡単: 単一のパッケージファイル(warなど)をサーバーに配置するだけでデプロイが完了します。
  • スケーラビリティの確保: 処理能力を拡張したい場合は、war ファイルを複数サーバーにコピーし、手前にロードバランサーを配置するだけで簡単にスケールアウトが可能です。

モノリスアーキテクチャのデメリット(課題)

システムの大規模化や、現代のビジネススピードに対応する段階になると、以下のような深刻な課題が浮き彫りになります。

  • 単一障害点(SPOF)のリスク: ある一つの機能モジュールで障害(メモリリークや無限ループなど)が発生すると、プロセス全体を巻き込み、サイト全体がアクセス不能になる危険性があります。
  • デプロイ時のダウンタイム: 小さなバグ修正や一部の機能アップデートであっても、サービス全体を一度停止し、巨大なアプリケーション全体を再パッケージ化・再デプロイする必要があります。
  • 結合度の高さによるアジリティの低下: 機能モジュール間の依存関係(密結合)が強いため、ある機能の変更が予期せぬ別の機能に影響を及ぼしやすくなります。これは、現代のインターネットビジネスで求められるような「高速なイテレーション(反復開発)」に不向きです。
  • 保守・運用とチーム分業の限界: 特に大規模なアプリケーションの場合、すべてのコードを一つのプロジェクトに収めることは非現実的です。コードベースが巨大化すると、メンテナンスの難易度が跳ね上がり、複数の開発チームでの分業や協業が困難になります。

1.3 マイクロサービス(Microservices)とは何か?

モノリスアーキテクチャの限界を克服し、現代のクラウドネイティブ開発における事実上の標準(デファクトスタンダード)となっているのが「マイクロサービス(Microservices)」です。

マイクロサービスの定義と中核思想

ソフトウェアアーキテクチャの権威であるMartin Fowler(マーチン・ファウラー)氏とJames Lewis氏は、2014年にマイクロサービスを以下のように定義しています。
image.png

「要約すると、マイクロサービス・アーキテクチャ・スタイルとは、単一のアプリケーションを小さなサービスの集合体(スイート)として開発するアプローチです。各サービスは自身のプロセスで実行され、軽量なメカニズム(多くの場合、HTTPリソースAPI)で通信します。これらのサービスはビジネス機能を中心に構築され、完全に自動化されたデプロイメント機構によって独立してデプロイ可能です。これらのサービスに対する集中管理は最小限に抑えられ、異なるプログラミング言語で記述されたり、異なるデータストレージ技術を使用したりすることができます。」
— James Lewis and Martin Fowler (2014)

マイクロサービスの主要な特徴

資料から読み解く、マイクロサービスの中核となる特徴は以下の通りです。

  1. 徹底した疎結合と単一責任の原則:
    従来の「オールインワン」のアプリケーションをビジネスドメインに基づいて個別のサービスに分割し、結合度を徹底的に下げます。各マイクロサービスは「1つのサービスは1つのビジネス機能のみを提供する(1つの事だけをやる)」ように焦点を絞って構築されます。
  2. 独立したライフサイクル(デプロイと実行):
    各サービスは技術的にも小さく独立した処理プロセスです。そのため、他のサービスに影響を与えることなく、単独で起動、停止、そして本番環境やテスト環境へ個別にデプロイすることが可能です。
  3. 専門特化と分散データ管理:
    分散システムにおいて「専門の人が専門の事を行う」という思想に基づき、各モジュール/サービスが独立性を保ちます。最大の特徴として、サービスごとに独自の専用データベースを選択・利用することができます。
  4. 軽量な通信プロトコル:
    サービス間の連携には、複雑なプロトコルではなく、一般的にHTTPベースのRESTful APIなどの軽量な通信メカニズムが採用されます。

組織アーキテクチャへのパラダイムシフト(コンウェイの法則)

アーキテクチャの変更は、開発チームの組織構造にも大きな変革をもたらします。

  • 従来の水平型組織: フロントエンド、バックエンド、DBA(データベース管理者)、QA(テストエンジニア)など、職能ごとに独立したチーム(水平アーキテクチャ)で構成されていました。
  • マイクロサービス向けの垂直型組織: ユーザー管理ビジネス、決済ビジネスなど、特定の「ビジネス(機能)」ごとにチームを分割する垂直型の組織構造へとシフトします。
    • ※Amazonの創設者であるJeff Bezos氏の有名な言葉「2枚のピザで全員が食べられる規模(約6〜10人程度)が理想のチームサイズである」という思想が、このチーム編成のベースとなっています。ただし、現実の企業では完全に垂直に分割することは難しく、理想的なモデルとして捉えられています。

(補足)SOAとマイクロサービスの違い

image.png

マイクロサービスを深く理解するためには、その前身であるSOA(Service Oriented Architecture)との関係性や、なぜマイクロサービスへと移行する必要があったのかという歴史的背景を把握することが不可欠です。

SOA(Service Oriented Architecture)の課題

SOAは、複数の独立したサービスを組み合わせて構築される分散システムです。しかし、運用していく中で以下のような深刻な課題が浮き彫りになりました。

  • 通信の複雑化とESBへの依存:
    各サブシステム間で統一された通信標準が存在しなかったため、システム間のデータ連携が異常に複雑化しました。これを解決するために導入されたのが ESB (Enterprise Service Bus) です。ESBは大量のルールと原則を統合したソフトウェアアーキテクチャであり、異なるアプリケーションを単一のインフラストラクチャに統合する役割を担いました。
  • ESBがもたらした新たなボトルネック:
    しかし、ESBの導入は新たな問題を引き起こしました。
    • 高コストとベンダーロックイン: 使い勝手の良いオープンソース製品が少なく、大手ベンダーの高額な商用製品に依存せざるを得ない状況(ベンダーへの縛られ)が発生しました。
    • 重量級で運用が困難: ESB自体が非常に重量級の製品であり、デプロイやアーキテクチャの計画が異常に煩雑でした。
    • 単一障害点 (SPOF): ESBへの過度な依存により、ESB自体がシステム全体のボトルネック、あるいは単一障害点となってしまいました。

SOAからマイクロサービスへの進化

上記のような背景から、「マイクロサービスはSOAのサブセットである」と捉えることができます。
SOAを「サービス指向アーキテクチャのバージョン1.0」とするならば、マイクロサービスは「サービス指向のバージョン2.0」へと進化した形態と言えます。

1.4 モノリスとマイクロサービスの構造的比較

システムの拡張性とデータ管理の観点から、モノリスとマイクロサービスには根本的な違いがあります。それぞれの構造的な特徴を比較してみましょう。

image.png

1. 実行プロセスとデプロイ単位

  • モノリスアーキテクチャ:
    • 全ての機能ユニットを単一のプロセス内に集約して実行します
    • 開発したコードは一つの大きなパッケージとして統合されます
  • マイクロサービスアーキテクチャ:
    • 機能の各要素を個別の独立したサービスとして分離します
    • 各サービスが自身のプロセスを持ち、独立して稼働します

2. スケーリング(拡張)の仕組み

  • モノリスのスケーリング:
    • 負荷が増大した際、サーバー上のアプリケーション全体をそのままコピー(レプリケーション)して対応します
    • 特定の機能だけに負荷が集中していても、アプリ全体を複製してリソースを割り当てる必要があります
  • マイクロサービスのスケーリング:
    • 各サービスをサーバー間に分散配置し、必要なサービスだけを個別に複製してスケールさせることが可能です
    • リソースの利用効率が極めて高く、細やかな拡張(きめ細かなスケーリング)が実現できます

3. データベースの管理手法

  • モノリス(Single Database):
    • 全ての機能モジュールが単一のデータベースを共有します
    • データの整合性は保ちやすい反面、データベースが単一障害点(SPOF)になりやすく、スキーマの変更が全機能に影響を及ぼします
  • マイクロサービス(Application Databases):
    • 各サービスが独立した専用のデータベースを保持します
    • サービスごとに最適なデータベース(RDB、NoSQLなど)を選択できる「ポリグロット・パーシステンス」が可能になり、サービス間の疎結合がより徹底されます

デプロイ・運用イメージの比較

インフラエンジニアの視点で、これら二つのアーキテクチャの運用操作を比較すると以下のようになります。

# 【モノリス】 アプリケーション全体を複製してスケールさせる例
# 全機能が含まれるコンテナを単純に並列展開する
docker run -d --name app-instance-1 my-monolith-app:v1.0
docker run -d --name app-instance-2 my-monolith-app:v1.0

# 【マイクロサービス】 特定のサービスのみを柔軟にスケールさせる例 (Kubernetes等)
# 負荷の高い「注文サービス」だけを3つに増やし、他は1つのまま維持する
kubectl scale deployment order-service --replicas=3
kubectl scale deployment payment-service --replicas=1
kubectl scale deployment inventory-service --replicas=1

このように、マイクロサービスは「必要な場所を、必要な分だけ」拡張できるため、クラウドネイティブな環境において非常に強力な柔軟性を提供します。

1.5 マイクロサービスのメリットとデメリット

マイクロサービスアーキテクチャは強力な武器ですが、「銀の弾丸」ではありません。導入にあたっては、その利点と引き換えに発生する複雑性を正しく理解する必要があります。

1.5.1 マイクロサービスのメリット(利点)

マイクロサービスを採用することで、開発の柔軟性とスピードを大幅に向上させることができます。

  • 高い凝集度とコードの可読性: 各サービスが十分に小さく凝集されているため、特定のビジネス機能や要件にフォーカスでき、コードの理解が容易になります。
  • 開発効率と機動力の向上: サービスが「一つのことを専門に行う」ため、2〜5人程度の小規模なチームで独立して開発を進めることができます。
  • 疎結合による独立性: 開発フェーズでもデプロイフェーズでも、各サービスは機能的に独立しており、他への影響を最小限に抑えられます。
  • 技術スタックの多様性(ポリグロット): サービスごとに最適なプログラミング言語やミドルウェアを選択することが可能です。
  • エコシステムとの容易な統合: Jenkins、Hudson、BambooなどのCI/CDツールを用いた自動デプロイや、サードパーティ製ツールとの連携が柔軟に行えます。
  • 最新技術の導入が容易: サービスが分離されているため、HTML/CSSといったフロントエンドとバックエンドを完全に切り離し、常に最新の技術を取り入れやすい構造になります。
  • 独立したデータストレージ: 各サービスが専用のデータベースを持つことで、データ管理の独立性が担保されます(必要に応じて共有も可能)。

1.5.2 マイクロサービスのデメリット(課題)

一方で、分散システム特有の「代償」も存在します。

  • システム全体の複雑化: 1つのプロジェクトを複数の独立した工程に分解するため、開発、テスト、運用、監視のすべてのフェーズにおいて複雑さが増します。
  • データの一貫性の担保: サービス間でデータを同期させる必要があり、分散トランザクションや非同期の補償メカニズム(Compensation)の設計が大きな挑戦となります。
  • エンジニアへの高いスキル要求: 開発者とインフラ運用者の双方が分散システムの複雑さを扱う必要があり、より高度な技術力(アーキテクチャの理解)が求められます。
  • 過剰設計のリスク: マイクロサービスは複雑な大規模システムに適しています。小規模なアプリケーションに盲目的に適用すると、開発・維持コストがメリットを上回ってしまいます。

技術的な考察:運用監視の例(bash)

マイクロサービス化が進むと、各サービスの生存確認(ヘルスチェック)やログの集約が不可欠になります。

# サービスのヘルスチェックをシミュレーションする例
# 各マイクロサービスが公開しているエンドポイントをチェックする
curl -I http://order-service:8080/health
curl -I http://payment-service:8080/health

このように、マイクロサービスは「柔軟性と引き換えに運用コストを支払う」アーキテクチャです。プロジェクトの規模とチームの習熟度を見極めた上で、適切な分割レベルを検討することが重要です。

1.6 マイクロサービスの技術スタック

マイクロサービスアーキテクチャを構築・運用するためには、単にサービスを分割するだけでなく、分散システムの複雑さを管理するための包括的な技術スタックが必要となります。主要な技術領域は以下の5つに分類されます。

1. マイクロサービスガバナンス(Service Governance)

サービス間の連携と健全性を維持するための中核機能です。

  • 登録・発見(Service Discovery): 稼働中のサービスを動的に管理します。
  • リモート呼び出し(RPC): ネットワーク越しのサービス間通信を実現します。
  • 構成管理(Configuration): 環境ごとの設定を一元管理します。
  • ゲートウェイ・ルーティング: 外部からのリクエストを適切なサービスへ振り分けます。
  • 流量制御・システム保護: 負荷に応じた制限や、過負荷からの保護を行います。
  • レジリエンス(耐障害性): サービスの隔離、サーキットブレーカー(熔断)、フォールバック(降級)などを制御します。
  • 認証・認可: サービス間のセキュリティを担保します。
  • 分散トランザクション: 複数のサービスにまたがるデータの整合性を確保します(Seata、TCC/ATモデルなど)。

2. 非同期通信技術(Message Queue)

システム間の疎結合化とスループット向上のための技術です。

  • MQメッセージ制御: メッセージの流量や順序を制御します。
  • 信頼性と永続化: メッセージの損失を防ぎ、ディスクへの保存を行います。
  • 高度なキューイング: 蓄積問題の解決や、遅延キュー(デリバリー遅延)などを実装します。
  • 高可用クラスター: ミラーリングやクラスタリングによる可用性向上を図ります。

3. キャッシュ技術(Caching)

応答速度の向上とデータベース負荷の軽減に不可欠な層です。

  • Redisエコシステム: データ構造の活用、主従複製(Master-Slave)、センチネル、分片(Sharding)クラスターなどを構築します。
  • 多段階キャッシュ: OpenRestyやNginxのローカルキャッシュを組み合わせた層状の設計を行います。
  • データ同期: キャッシュとDB間の整合性を維持します。
  • 保護対策: キャッシュ貫通(Penetration)や雪崩(Avalanche)への対策を講じます。

4. 検索技術(Search)

大規模データに対する高度な検索・分析機能を提供します。

  • Elasticsearch (ES): DSLやRestAPIを用いた高速な全文検索を実現します。
  • 分析機能: データの集計統計、ランキング、自動補完、ピンイン検索などを提供します。
  • 地理空間情報: 地理座標を用いた位置情報検索をサポートします。

5. DevOps と運用基盤

迅速な開発と安定した運用を支える自動化基盤です。

  • コンテナ化: Dockerを用いたイメージ作成(Dockerfile)やオーケストレーション(Compose/Kubernetes)を行います。
  • CI/CD: Jenkinsなどを用いたビルド・テスト・デプロイの自動化を推進します。
  • 可観測性(Observability): SkyWalkingによる分散トレーシングや、Graylogによるログ集約、監視・アラートを構築します。

1.7 主要なマイクロサービス・フレームワーク

マイクロサービスを実装するためのフレームワークはいくつか存在しますが、現在のデファクトスタンダードとなっているのは Apache Dubbo と Spring Cloud の2つです。それぞれの特徴とアプローチの違いを理解しましょう。

1. Apache Dubbo

Alibabaによって開発され、現在はApacheソフトウェア財団(ASF)のトップレベルプロジェクトとなっている、高性能なJava RPCフレームワークです。

  • RPC(遠隔手続き呼び出し): モノリスなプログラムを複数の機能サービスモジュールに分解し、モジュール間をDubboが提供する高性能なRPCで接続します。
  • エコシステム: マイクロサービス・エコシステムにおける重要なコンポーネントであり、主にサービス間の高速な通信に特化しています。
  • サービスガバナンス: 内部的な調整には ZooKeeper を使用し、サービスの登録(Registration)、発見(Discovery)、およびガバナンス(Governance)を実現します。

2. Spring Cloud

マイクロサービス構築に必要な機能を網羅した、包括的なソリューションパッケージです。Dubboが提供する機能を包括しつつ、さらに広範な機能(構成管理、ゲートウェイなど)をカバーしているため、Dubboの「スーパーセット(超集合)」と見なすこともできます。

  • 粒度の細分化: 単体アプリケーションを、より粒度の小さい、単一機能に特化したサービスへと分解します。
  • RESTful 通信: モジュール間の通信には、HTTPプロトコルに基づいた REST(Representational State Transfer)形式を採用しています。
  • フルスタック: 開発から運用まで、マイクロサービスに必要なコンポーネントが「全部入り」の状態で提供されるのが最大の特徴です。

技術的な考察:RPC vs REST

システムエンジニアの視点から見ると、両者の最大の違いは「通信プロトコル」にあります。

比較項目 Apache Dubbo (RPC) Spring Cloud (REST)
通信速度 バイナリプロトコルによる圧倒的な高速通信 HTTP/JSONによる柔軟だがRPCよりは低速な通信
依存性 言語や特定のフレームワークへの依存が比較的強い 言語を問わず連携しやすい(ポリグロット向き)
学習コスト 通信層の理解と細かなチューニングが必要 ウェブ開発者にとって馴染みやすく、導入が容易

現在のトレンドとしては、内部の高速な通信にはDubbo(RPC)を、外部公開や多様な言語が混在する環境にはSpring Cloud(REST)を選択する、あるいは両者の強みを組み合わせる設計が一般的です。

1.8 モノリスか、マイクロサービスか?(アーキテクチャの現実的な選択)

image.png

現在、多くの開発現場でマイクロサービスが注目されていますが、「モノリス(単体アーキテクチャ)こそが、多くの場合においてより良い選択肢である」という考え方が、エンジニアの間で再評価されています。

ソフトウェア界の重鎮であるMartin Fowler(マーチン・ファウラー)氏は、2015年に「モノリス・ファースト(Monolith First)」という思想を提唱しました。

1.8.1 なぜ「モノリス・ファースト」なのか

Martin Fowler氏は、マイクロサービスの成功例と失敗例を分析し、以下の共通パターンを発見しました。

  • 成功例: ほぼすべての成功したマイクロサービスは、「大きくなりすぎたモノリスを分解した」ことから始まっています。
  • 失敗例: 最初からマイクロサービスとして構築されたシステムのほとんどは、深刻なトラブル(開発の停滞や複雑性の爆発)に見舞われています。

このことから、「たとえ将来的に巨大なシステムになることが確実であっても、最初はモノリスから始めるべきである」と多くの専門家は指摘しています。

1.8.2 「マイクロサービス・プレミアム(付加コスト)」の壁

マイクロサービスは強力ですが、導入には「マイクロサービス・プレミアム」と呼ばれる、一連のサービスを管理・運用するための多大なコストが発生します。

  • プレミアムの正体: サービス間の複雑な管理コストはチームのスピードを鈍化させます。
  • モノリスの強み: 最初にモノリスを構築することで、システムの複雑性やコンポーネント間の正しい境界線を見極める時間が得られます。これにより、適切な粒度でサービスを分割することが可能になります。

1.8.3 モノリス・ファーストを実現する4つの戦略

具体的にモノリスからどのように進化させていくべきか、4つの主要な戦略を紹介します。

  1. モジュール型モノリス(Modular Monolith)
    モノリス内部でAPIの境界やデータストレージの方式を注意深く設計し、モジュール化を徹底します。これができていれば、後にマイクロサービスへ移行するのは比較的容易です。
  2. エッジ剥離(Edge Peeling)
    モノリスを核(コア)として残し、周辺の機能(エッジ)から徐々にマイクロサービスとして切り出していく、最も一般的な手法です。
  3. 全体置換(Whole Replacement)
    市場への早期投入を最優先し、後に破棄することを前提に「犠牲的なアーキテクチャ」としてモノリスを構築します。スピードを武器に、ビジネスが軌道に乗ってからサービスを再構築します。
  4. 粗粒度サービス(Coarse-grained Services)
    最初から細分化せず、マイクロサービスよりも大きな単位の「粗いサービス」から始めます。境界が安定したのを見計らって、より細かい粒度のサービスへと分解していきます。

まとめ:現実的かつ賢明な選択を

現在は「ポスト・マイクロサービス時代」とも呼ばれ、モノリス・ファーストの考え方が業界の普遍的なコンセンサスとなりつつあります。

  • チーム人数が少ない
  • 資金やリソースが限られている
  • 迅速に市場へプロダクトを投入する必要がある

このような状況では、モノリス・ファーストを採用するのが最も合理的です。
ビジネスの問題を解決するのではなく、履歴書に書くための最新技術を追うだけの「Hype Driven Development(ハイプ/トレンド駆動開発)」に陥らないよう、自社のビジネスフェーズに合わせた現実的な選択を心がけましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?