自社のポジションを考える思考フレームワーク「ポーターの3つの基本戦略」「コトラーの競争戦略」

自社サービスを展開しているIT企業では、自社のサービス展開に関する戦略を練る必要があります。
優れた戦略を作る上では、それぞれ異なった立場や知見を持つ関係者が集まって、関係者間で思考をまとめるのが有効です。
そして、思考をまとめるのをサポートする手段として、思考フレームワークが数多く発表されています。

自社を中心に外部環境を俯瞰するのに適した思考フレームワークとしては、前回の記事で紹介した「SWOT分析」や「3C分析」といったものがあります。
今回の記事では、外部環境を俯瞰した上で、自社が取るべき戦略を考えるのに適した思考フレームワークである「ポーターの3つの基本戦略」と「コトラーの競争戦略」の2つを挙げていこうと思います。

例として、日本に実在するハンバーガーショップを挙げていきます。
(この記事は、思考フレームワークをわかりやすく解説するもので、ハンバーガーショップの具体的な戦略を考察するものではないので、それをご理解された上で記事を参照してください)


【ポーターの3つの基本戦略】

ポーターが提唱した戦略の分類であり、ターゲットが広いか狭いか、他者より低いコストで勝負するか特異性で勝負するか、により、以下の3つの戦略に分ける、というものです。

どの戦略を採用するかは、市場分析の結果から判断します。

例を挙げると、各々の企業の戦略を以下のように分類することができます。

・コストリーダーシップ戦略

マクドナルドが採用する戦略。
手軽に食べられる安い外食に対する需要があり、マクドナルドには低コストを実現するグローバルな生産拠点が存在するため、その需要に応えられる。

・差別化戦略

モスバーガーが採用する戦略。
美味しくて安全な外食に対する需要があり、モスバーガーには高品質と安全性を実現するプロセスが存在するため、その需要に応えらえる。

・集中戦略

地元のハンバーガーショップが採用する戦略。
全国規模・世界規模のプロセスに縛られるチェーン店に比べて小回りが効くため、地元の要望に応えられる独自性のあるハンバーガーを提供できる。


【コトラーの競争戦略】

コトラーもポーターと同じように、それぞれの企業が置かれた地位に応じて採るべき戦略を提唱しています。
コトラーは、以下の4つの戦略に分類しています。

・リーダ

市場においてナンバー1のシェアを誇る企業。

・チャレンジャ

リーダに次ぐシェアを保持し、リーダに競争をしかける2・3番手の企業。

・ニッチャ

小さいながらも特定の市場で、独自の地位を築いている企業。

・フォロワ

リーダやチャレンジャの戦略を模倣することで、市場での地位を維持している企業。

----
例を挙げると、各々の企業の戦略を以下のように分類することができます。

・リーダ

低コストを突き詰めたマクドナルドが該当します。

・チャレンジャ

品質と安全性で勝負するモスバーガーが該当します。

・ニッチャ

地元のハンバーガーショップや、高級ハンバーガーに特化した小規模チェーン店が該当します。

・フォロワ

ロッテリアやフレッシュネスバーガー等の中規模チェーン店が該当します。
これらの企業は、マクドナルドやモスバーガーと同じように、人が集まる場所に全国規模で出店しています。
リーダやチャレンジャの良い所をできる限り真似ながら、独自性のある商品や広告を模索している感があります。


このように戦略を分類すると、自社が取るべき戦略が見えてきます。
例えば、モスバーガーのような企業は、マクドナルドと価格競争になるのは避けるべきであり、品質と安全性で勝負するべきである、というのが見えてきます。

自社の戦略を確立する上では、自社のコアコンピタンス(自社独自の強み)が何であるか、何をコアコンピタンスにするべきか、というのを考えるのが重要です。
コアコンピタンスが不明確だと、価格競争に巻き込まれやすくなり、価格を下げられる仕組みがあるわけでもないので、利益(労働者目線で言うと待遇)が圧迫されやすくなります。


いかがでしたでしょうか。

今回は、「ポーターの3つの基本戦略」「コトラーの競争戦略」を記事として取り上げてみました。
市場を分析するだけでなく、それを元に企業の戦略を考えることも重要です。
戦略を考える上で、今回紹介したような思考フレームワークを使うと、コミュニケーションがスムーズになると思います。

思考フレームワークはまだまだありますので、今後も引き続き紹介していこうと思います!

自社を中心に外部環境を俯瞰する思考フレームワーク「SWOT分析」「3C分析」

自社サービスを展開しているIT企業では、自社のサービス展開に関する戦略を練る必要があります。
優れた戦略を作る上では、それぞれ異なった立場や知見を持つ関係者が集まって、関係者間で思考をまとめるのが有効です。
そして、思考をまとめるのをサポートする手段として、思考フレームワークが数多く発表されています。

今回の記事では、自社を中心に外部環境を俯瞰するのに適した思考フレームワークである、「SWOT分析」と「3C分析」について、紹介していこうと思います。
例として、地方銀行向けにレガシーな機関システムを広く提供している企業を挙げます。


【SWOT分析】

SWOT分析とは、経営環境を分析するために、内部要因(自社)の強み(Strength)・弱み(Weakness)と外部要因(市場)の機会(Opportunity)・脅威(Threaten)を表に書き出す手法です。

例としては以下の通りです。


【3C分析】

3C分析の「3C」とは、「Company(自社)」「Competitor(競合)」「Costomer(顧客(市場))」の頭文字を取ったもので、この3者について分析することで経営環境を分析する、という手法です。

例としては以下の通りです。

■自社

  • 地方銀行でも手が出しやすい価格でサービスを提供している
  • 地方銀行の業務に関する独自のノウハウを持っている

■競合

  • 地方銀行向け市場に参入しようとする競合他社は今の所は少ない
  • 都市銀行向け市場は他社に既に抑えられてしまっている
  • パッケージソフトやローコードを用いられた場合はより安価にサービス提供される

■顧客(市場)

  • 地方銀行には自社サービスを使ってもらえるが、統廃合で銀行の数が減りつつある
  • 都市銀行は既に自社独自のサービスを抱えている
  • 地方銀行は都市銀行に比べて地元密着であり、都市銀行ほど保守的な体質でもない

このように状況を整理すると
「ジリ貧の市場で価格競争をしている」
という危うい現状が見えてくると思います。

この現状を抜け出すためには、先端ITを用いて地方銀行の競争力を向上させることが有効です。
地元に特化したサービスで地元での顧客を増やしたり、先進的なサービスで都市部の顧客を増やしたりできれば、地方銀行の競争力を向上させることができます。

…このような判断を導きやすくするのが、「SWOT分析」「3C分析」という思考フレームワークです。
思考フレームワークの使い方が重要であるため、思考フレームワークを使ったからと言って適切な判断ができるわけではありませんが、関係者が集まって協議する上で役に立つでしょう。


いかがでしたでしょうか。

今回は、SWOT分析と3C分析を記事として取り上げてみました。
馴染みのない方も少なくないと思いますが、このような戦略系の思考フレームワークは自社サービスの企業では実際に使われている有用なフレームワークです。
(私自身も、思考フレームワークを使用して上長と会話したことがあります)

このような思考フレームワークは他にもありますので、何回かに分けて紹介していきたいと思います!

Visual Studio Codeでdraw.ioを使う

フローチャートやネットワーク図等は、フリーの作図ツール「draw.io」を使うと楽に記述できます。
Excelでも記述はできますが、draw.ioでは各々の図の記述に適した素材が提供されているという特徴があります。
また、draw.ioはブラウザ上での使用が想定されていますが、フリーのコードエディタである「Visual Studio Code」を用いるとローカル上で編集が可能になります。

今回は、使用手順を簡単に紹介していきたいと思います。


1.draw.ioのホームページにアクセスする。

https://app.diagrams.net/

2.ファイルの保存方法を選択する。

今回は「Device」を選択します。これで図がローカルに保存できるようになります。
また、選択後、新規にファイルを作成するかどうか聞かれるので、新規にファイルを作成する(Create New Diagram)を選択します。

3.どのような図を作成するか選択する。

今回は「Flowchart」を選択します。

4.ブラウザ上でファイルを編集してみる。

例えば、図形を追加する場合は、「Shapes -> General」から追加することができます。
また、図形の中に文字を入力したい場合は「右クリック -> Edit」で入力できます。
図を保存したい場合は、画面上部の「Click here to save.」から保存できます。

5.Visual Studio Codeに拡張機能を入れる。

ローカルでVisual Studio Codeを開き、拡張機能の検索画面を開きます。
そして、「draw.io」を検索し、「Draw.io Integration」をインストールします。

6.4でローカルに保存したファイルをVisual Studio Codeで開く。

すると、以下のように、ローカルでdraw.ioの図を編集できるようになります。
図形の追加は「General」から、文字編集は図形をダブルクリックすることで可能です。


いかがでしたでしょうか。

Visual Studio Codeはコードエディタではありますが、サクラエディタのようなテキストエディタというよりも、EclipseやVisual StudioのようなIDEに近く、「軽量IDE」と呼んだ方が実態に近い位です。
そして、IDEと同じように、拡張機能も数多く用意されています。

機会があれば、便利な拡張機能をまた紹介したいと思います!

java:参照型変数やメモリの理解に苦しむ若手Java技術者に向けて

Javaの参照型変数の中身は、何年かJavaの実装経験を積んだ人でもイメージすることが難しいです。
しかし、ここがイメージできていないと、思わぬ落とし穴にはまることもあります。

C言語を経験していればイメージしやすくなりますが、そのためだけにC言語を学ぶのもハードルが高く感じると思います。
そこで、今回の記事で、参照型変数の中身のイメージについて、重要な点のみをピックアップして説明していきたいと思います。

0.そもそもメモリとは

参照型変数について理解する前に、まずはメモリについて意識する必要があります。

メモリとは、プログラムの実行中に取り扱っているデータを一時的に保存する領域です。
数学の問題を解く時に、答えを出す前に途中式を紙に書くと思いますが、その紙がメモリのようなものだと考えれば良いです。
なお、一般的には、プログラムの実行結果は最終的にファイルやDBに恒久的に保存するか、画面に表示するかします。
数学の問題の例で言うと、恒久的な保存領域や画面表示が答えに相当すると考えれば良いです。

そして、メモリは1バイト(8ビット)ずつ細かく区分けされており、それぞれの区分けについて「アドレス」と呼ばれる値により一意に場所を特定します。
アドレスのバイト数は、64ビットのOSの場合は8バイトになります。

文章で書かれてもイメージが難しいと思いますが、後ほど図を使って説明します。
とりあえず、「メモリと呼ばれる一時的な保存領域がある」という意識を持っていただければ、と思います。

1.プリミティブ型と参照型

Javaの変数は、プリミティブ型と参照型の2種類に大きく分けることができます。
どちらの型なのかによって、メモリに格納する内容が変化します。

プリミティブ型に分類される型については、以下の8つの型が存在します。

細かいですが、boolean型についてはデータの保持に使うのは1ビットのみで、メモリに値を保存する時にはバイト単位になっているはずです。
Javaの実装上は1バイトになることが多いようなのですが、boolean型が何バイトになるのかは正式な取り決めはないので、万が一これを気にする必要がある場合は調査した方が良いです。

そして、プリミティブ型以外の型の変数は、全て参照型変数に分類されます。
newでオブジェクトを生成する変数は全て参照型変数です。
また、プリミティブ型の配列についても、参照型変数に該当します。
プリミティブ型のラッパークラス(Integer型、Character型、等)やString型についても参照型変数に該当しますが、特定の場面においてはプリミティブ型に見えるような動きをします(詳しくは後述します)。

プリミティブ型変数と参照型変数では、メモリに格納する値が異なります。
プリミティブ型変数では値そのものをメモリに格納するのに対し、参照型変数ではメモリ上にその変数用の保存領域を確保した上で、その保存領域の場所を指し示すアドレスを変数の領域に格納します。
図に表すと、以下のようになります。

この違いは、プログラムの挙動の違いとなって現れます。それを以降で説明していきます。

2.変数をコピーした際の挙動の違い

プリミティブ型変数と参照型変数の挙動の違いを実感するのは、変数をコピーした時でしょう。
実務でも躓きやすいポイントなので、サンプルコード付きで詳しく説明していきます。

以下は、プリミティブ型の変数をコピーした後に、コピー元の変数を変更する例です。
コピー元の変数の変更は、コピー先の変数に影響しません。
これはイメージ通りだと思います。

しかし、同じような書き方で参照型変数をコピーした場合、コピー元の変数の変更がコピー先の変数にも影響してしまいます。
以下は、配列をコピーした例と、ArrayList型をコピーした例です。

なぜこのようなことが起こるのかと言うと、この書き方ではアドレス値をコピーしてしまっており、領域を新たに確保しているわけではないからです。
このようなコピーは、シャローコピー(浅いコピー)と呼ばれます。

文章だけではイメージするのが難しいので、図も交えながら、シャローコピーの挙動を説明します。

コピーした段階では、アドレス値をコピーしてしまっており、指し示す領域はコピー元と同一になってしまっています。

そのため、コピー後にコピー元の変数を変更すると、その影響がコピー先の変数にも表れてしまいます。

これを回避するためには、新たに領域を確保し、その領域に格納する値をコピーした後、新たな領域を指し示すアドレス値を変数に格納するような形でコピーする必要があります。
このようなコピーは、ディープコピー(深いコピー)と呼ばれます。

ディープコピーのイメージは以下の通りになります。

コードで言うと、以下のようなコードになります。

上記のコードは原始的なディープコピーの方法です。
ディープコピーを行うためのCloneableインターフェースがJavaでは用意されており、これを使用した方が効率的にディープコピーを行うことができることもあります。
詳しくは、java:オブジェクトの中身をコピーする方法(cloneメソッド実装)を参照して下さい。

なお、プリミティブ型変数と参照型変数の挙動の違いを実感する代表的な場面としては、他にはメソッドの引数に変数を引き渡す場面が挙げられます。
情報処理技術者試験では値渡しと参照渡しの違いについても出題範囲になっていますが、これは値そのものを渡しているか、アドレス値を渡しているかの違いです。
参照型変数を引数で渡す時にアドレス値を渡している感覚(参照渡しをしている感覚)を持っていないと、これもバグの原因になり得ますので、注意が必要です。

3.メモリの開放

参照型変数の値を保持するための領域は、newする度に確保され直します。
(配列の場合は、配列を宣言し直す度に確保され直されます)

例えば、以下のコードでは、2回目のnewにより領域が再確保されています。

これを図解すると以下のようになります。

ここで問題になるのが、newし直す前に確保していた領域です。
この領域はプログラムで確保していたものの、使われなくなった領域です。
newで確保した領域が他のプロセス(プログラム)から使われることはあってはならないので、確保した領域は他のプロセスから使えなくなるような制御がかかります。
再び他のプロセスから使えるようにするためにはメモリを開放する必要があるのですが、この開放を忘れたまま領域の再確保を繰り返すと、他のプロセスが使えるメモリの領域が徐々に減っていきます。
これが「メモリリーク」と呼ばれる現象であり、放置すると空きメモリの不足により、プロセスの挙動や、場合によってはシステム全体の挙動が不安定になります。

C言語では、メモリの開放はコーディングにより明示的に行う必要がありました。
しかし、Javaでは「ガベージコレクション」と呼ばれる仕組みにより、開放するべき領域がある程度増えたら自動的に開放が行われるようになりました。

意図しないタイミングでのガベージコレクションは予期せぬ性能劣化を招く可能性があるので、性能要件がシビアなシステムではガベージコレクションについても気を配る必要があります。
ガベージコレクションについて詳しく見ていくにはこの記事ではとても足りないのですが、調べる上でメモリのイメージがついていれば理解は早まると思います。

4.イミュータブルな参照型変数について

参照型変数の中には、イミュータブルな変数も存在します。
イミュータブル(immutable)とは「不変」という意味であり、ミュータブル(mutable)の対義語です。
オブジェクト指向言語においては、「イミュータブル」は、「オブジェクトの生成後に、そのオブジェクトの状態(メモリ領域に保持されている値)が変化しない」という意味を指します。

イミュータブルな参照型変数の場合、newして領域を確保した後にオブジェクトの状態を変更したい場合は、再度newして領域を確保し直す必要があります。

Javaにおいては、プリミティブ型のラッパークラスやString型が、イミュータブルな参照型として用意されています。
これらの変数については、newを書かなくとも、領域が都度確保され直す、という挙動となります。
その結果、値の代入や参照においては、あたかもプリミティブ型の変数かのような挙動となります。
(ただし、本当にプリミティブ型の変数というわけではないため、プリミティブ型変数と異なりnull値を持つことができ、メソッドも持っています)

Javaで用意されているイミュータブルな参照型変数のコピーする例は以下の通りとなります。
これはシャローコピーと同じ書き方ですが

実際の挙動としては以下のように明示的にnewしているのと同じ挙動となるため

結果としてはディープコピーの挙動となります。
(つまり、シャローコピーすることはできず、意図せずともプリミティブ型のような動きとなります)


いかがでしたでしょうか。

Javaの入門レベルを脱し、Javaのコーディングで意図しないバグの発生を防いだり、性能改善を図ったりしたいのであれば、メモリの話に踏み込まざるを得ません。
しかし、JavaではC言語と異なりメモリについて意識しなくてもコーディングできるようになっているので、生産性の高さと引き換えに、メモリについて想像するのが難しくなっています。
また、基本情報処理技術者試験で来年度(2023年度)からC言語を含む言語選択問題が出題対象から外れる(疑似言語に統一となる)ため、C言語に触れる機会が減ることが予想されます。

このような背景があるため、後継のJava技術者にメモリについて教える機会は今後ますます増えることが予想されます。
その際、C言語未学習者でも要点をかいつまんで理解してもらい、かつ躓きやすいポイントを押さえた記事が必要であると感じたため、今回の記事を執筆しました。

これからも、教育上必要と感じることがあれば、記事にしていきたいと思います!

余談ですが、Javaの挙動を確認するため、今回の記事の執筆時にpaiza.ioのサービスを使ってみました。
これは、オンライン上でコードを書き実行できるというものであり、Javaにも対応しています。
Chromeのデベロッパーツールのコンソール上でのJavaScript実行のようなことがJavaでもできるので、ちょっとした挙動確認でとても便利でした。

SpringFrameworkのAOPとは

AOPとは、「アスペクト指向プログラミング(Aspect Oriented Programming)」の略称です。
「アスペクト」を日本語に直訳すると「相」ですが、プログラミングの世界では「オブジェクト指向ではうまく分離できない横断的な機能」のことを指します。代表例としてはログ出力機能(各クラスの処理の開始・終了等のタイミングで割り込むような形で使われる)が挙げられます。
AOPをサポートするフレームワークでは、横断的な機能を別のプログラムとして切り出し、そのプログラムが特定のタイミングで呼び出されるように別途定義できるような機能が組み込まれています。

SpringFrameworkにも、AOPが機能の一つとして組み込まれています。
AOPを利用することで、横断的な機能を切り出して可読性を高めたり重複を排除したりすることができます。


以下は、SpringFrameworkでのAOPの書き方の一例です。
test関数の開始時と終了時に標準出力を割り込ませるサンプルコードです。

なお、便宜上、サンプルコードではRestControllerを併用していますが、AOPはRestControllerを併用する必要はありません。

【サンプルコード】

・SmpSpringBootApplication.java

・MyFirstAspect.java

【実行結果(コンソール)】

・SmpSpringBootApplication起動後、http://localhost:8080/testにアクセス


いかがでしたでしょうか。

SpringFrameworkのAOPについて簡単なサンプルコードが欲しかったので、簡単な解説を付けた上で記事に起こしました。
本日ではSpringFrameworkの情報は書籍やWeb上に十分に揃っているのですが、情報を付け加えたくなったらまた記事を起こしたいと思います。