組織特有の意思決定

組織で仕事をすることで多くの資源(ヒト・モノ・カネ)を使うことができるようになり、より大きな仕事ができるようになります。
しかし、一人で仕事する場合と比べて優れた意思決定ができるとは限らず、せっかく多くの資源を用いて仕事をしたとしても、仕事の方向性を誤ることがあります。むしろ、組織の中で意思決定するからこそ、誤った意思決定をしてしまう可能性がある。

この記事では、そのような意思決定がなぜ行われるのか、そして、それをどのように防げば良いのかを書いていきます。

また、組織で仕事をする上では、自分が推す案とは異なる意思決定がされることがあり、その場合にも組織として一貫性のある行動が行われるように協力する必要があります。
この記事では、どのような心構えで協力すれば良いのかについても書きます。

(1)集団浅慮の考慮

組織で意思決定を行うことで誤った結論や行動が導き出されてしまうことを「集団浅慮(グループ・シンク)」と呼びます。

バランスの良い意志決定を行うためには、特定の議題に対して、肯定・否定の両方の視点からの検討が必要です。
仮に、一人で意思決定を行った場合に肯定・否定の両方の視点を上手く取り入れられたとしても、組織ではそれが難しくなる場合があります。

具体的には、以下のような要素が存在する場合に、それが難しくなります。

・組織に対する帰属意識が高い

イエスマンとして組織についていくことが目的になる恐れがあり、多様な意見が出てきにくくなる。

・外部情報が入ってこない

物事を客観的に判断したり、さまざまな角度から見直したりすることが難しくなる。

・一部の人物の権力や影響力が強い

一部の人物の意見が重用されやすくなり、多様な意見が出てきにくくなる。

・決定事項に関係者の利害が絡む

各関係者が、自分に有利になるような特定の結論に導くのを目的に議論するようになる恐れがある。
(全体最適な結論に導くのが難しくなる)

・ノルマや時間に追われている

結論を出したり行動したりすることが目的になり、内容を深く検討することが難しくなる。
(短期的に見れば早急に行動した方が良い場合も多いが、長期的に見て望ましくない方向に進みやすくなる)

 

実例としては軍事の例が挙げられることが多く、例えば、第二次世界大戦で降伏の判断が遅れた日本政府の例は集団浅慮であると言われています。
また、戦後のアメリカのピッグス湾事件やチャレンジャー号爆発事故等も集団浅慮の例として取り上げられることが多いです。

集団浅慮を防ぐためには、以下のような方法が有効です。

・啓蒙活動を行う

「多様な意見を出すこと」「外部の意見を取り入れること」「中立な立場を守ること」「全体最適を考えること」等の意識を啓蒙することで、集団浅慮は起こりにくくなる。

・集団の在り方を変える

集団をどのように構成するかを変えることで、人間関係が変わり、集団浅慮を招く要素が解消されることがある。
例えば、「集団を小グループに分けて意思決定を行い、次にこれらの結論を持ち寄って集団としての意思決定を行う」という「バス・セッション法」と呼ばれる仕組みを導入することで、多様な意見が出やすくなり、集団浅慮が起こりにくくなる。

・稚拙な意思決定は例外事項とする

ノルマや時間に追われている場合は稚拙な意思決定も致し方ない場合もある。
しかし、これは例外事項として扱い、次回からは稚拙な意思決定を防ぐ仕組みを整備しそれを守らせる、ということを徹底するのが重要である。

(2)意思決定者の意向を汲んだ行動

組織での意思決定では、自分に最終的な決定権がないという状況が往々にして起こり得えます。
具体的には、取引先や上位会社、上司、先輩の決定に従わざるを得ない、ということが少なくありません。

集団浅慮ではない合理的なプロセスを踏んでいたとしても、最終的な意思決定が、自分の意に沿わないものであることもあります。
しかし、組織で活動する上では、自分が推す案に拘り、無理に押し通そうとするのは賢い判断ではありません。
自分の方が折れて、組織としての決定に従い、それに基づいた行動をすることが賢い判断です。

しかし、自分が異なる意見を推していたということは、組織で決定した結論には何かしらの問題があることに気付いているはずです。
組織としての結論を覆さない形で、かつ実作業に近い細かいレベルで、問題を解消する方法を提案するのが賢い判断です。

例えば、Javaのコーディング規約を検討している時に、「業務ロジックが膨大というシステムの性質からして人海戦術に頼らざるを得ない」ということを重視し、組織として「習得者が多くないラムダ式は使用禁止とする」という決定をしたとします。
また、自分がリーダーポジションの技術者であり、ラムダ式の利点を理解した上でラムダ式を使いたいと思っていたとします。
ここで、組織としての決定を無視するような形でラムダ式を使うのは賢い判断ではありません。ソースコードが統一的な書き方をされなくなることにより可読性や保守性が低下したり、組織内で衝突を生んだりする恐れがあるためでです。
その代わり、「共通処理に関しては、実装する技術者が限定され、どの技術者も一定以上のレベルであるため、共通処理に限りラムダ式を使わせて欲しい」といった形で提案をすることが賢い判断です。このような提案であれば通る可能性が高く、通れば組織としての決定を無視しない形で、快適に作業することができるようになります。


前回の記事に続いて、ソフトスキル関連の記事でした。

先日、株式会社サイゼントから書籍「絶対にJavaプログラマーになりたい人へ」を発売し、お陰様でご好評いただいています。
感想も寄せられ、今まで気づいていなかった要望があることに気付くこともできました。
要望に応えるため、新たな執筆活動に取り掛かりました。
ブログの執筆に時間を割くことが難しくなってしまいますが、続報にご期待ください!

上記の書籍は、Javaプログラマーとしてのキャリアをスタートしたい人向けのプログラミングスクール「サイゼントアカデミー」でも用いています。
書籍の執筆を通して、スクールのコンテンツもどんどん改善したいと思います!

会議による効率的な協働

仕事を進める上で、関係者間で情報共有や意思決定を行う会議は欠かすことができないものです。

例えば、以下の目的で会議は必要になります。

  • 管理表やチケットで管理されたタスクの棚卸
  • 要件や作業状況等のヒアリング
  • 問題に対する対応案の検討
  • 成果物に対する方針確認やレビュー

会議を上手く運営することで、仕事をスムーズに進めることができます。
しかし、会議には複数の人の時間を取らせてしまうという問題もあるので、効率的な運営が欠かせません。

この記事では、会議を効率的に進めるために心掛けるべきことを記載します。

(1)会議開催の判断

会議を行う利点として、リアルタイムに相互にコミュニケーションが取れるというものがあります。
逆に言うと、その利点を活かせないのであれば、会議を行わずに、テキストベースでやりとりして各自が作業した方が効率は良いです。

リアルタイムでの相互のコミュニケーションが必要になる場面としては、他の人の反応により結論が変わりやすい場面になります。
例えば、要件のヒアリングは、話を聞くまでどのような話(結論)になるか予測するのか難しいため、会議を開催する必要性が高いです。
逆に、プログラムの不具合の調査は、不明点が見つからない限りは自分一人で結論を出すことができるため、会議を開催する必要性は薄いです。

このように、まずは、会議を行う必要があるかどうかを考えるべきです。

ちなみに、この時点で誰とリアルタイムにコミュニケーションすれば良いかが見えるので、会議に召集する必要がある参加者も自ずとイメージできると思います。

(2)会議の日時設定と準備

会議を行うためには、事前の日時設定と準備が欠かせません。
これらは順番が前後しても構いませんが、どちらも必ず行う必要があるものです。

・会議の日時設定

会議の準備の一貫として、参加者の時間を押さえる必要があります。

特に、組織の上位者は会議参加や外出の頻度が高く、空いていない時間が多いので、上位者から先に押さえるのがポイントになります。

会議の時間を押さえるのが難しいのであれば、時間設定を先に行ってしまった方が良いです。
会議への参加が必須ではないメンバーについては、任意参加という形で会議が存在することだけ通知し、参加するかどうかを判断してもらい、参加しないにしても後で結果を展開する、という形にすると良いです。

・会議の準備

会議を行うことを決めたら、下準備をします。
会議中に自分一人で行うべきタスクを実施してしまうと時間の浪費につながるので、そのような作業は予め実施しておいた方が良いです。
この準備に時間を要するのであれば、早い段階から着手するべきです。

例えば、タスクの棚卸を行うのであれば、自分が把握しているタスクは全て管理表やチケットとして起票するべきです。
また、成果物のレビューを行うのであれば、レビュー対象の成果物を叩き台の形で良いので一旦作成する必要があります。

他の参加者に準備を依頼するのであれば、先にその旨を通知すると良いです。
準備の依頼が必要ないように思える場合についても、予め準備したいと考える参加者がいる可能性があるため、その場合も会議の議題やアウトラインは先に通知することが望ましいです。

(3)会議開催と議事録作成

(1)と(2)を実施できていれば、会議の目的も内容も明確であるため、準備時に考えていた通りに会議を進めるだけです。

ここで重要になるのは、会議の中で結論を決めることです。
より具体的に言うと、誰が何をやるのか、という次のアクションを決める必要があります。

例えば、要件のヒアリングであれば、ヒアリング結果を元に誰がいつまでに次の提案を行うのか、ヒアリングしきったのであれば誰がいつまでに要件定義書に書き展開するのか、ということを決める必要があります。
また、成果物のレビューであれば、誰がいつまでにレビューの指摘事項に対応するのか、を決める必要があります。

会議結果の共有や備忘のため、議事録のようなドキュメントに残し展開することも重要です。
最低限、会議の結論と、関係者が結論を理解する上で必要な背景を記載して展開した方が良いです。


一人の力では大きなプロダクトは作成できないので、協働をスムーズに行うためのソフトスキルを持った技術者は重宝されます。
ソフトスキルには、今回の記事で取り上げたような会議の運営に関するスキルも含まれ、システムエンジニアやリーダーのような上位者にとっては重要なスキルです。

と言っても、技術者として仕事をするのであれば、プログラマーとしての個のスキルを固めるのが前提になります。
個のスキルを固める上で有用な書籍として、先日、株式会社サイゼントから書籍「絶対にJavaプログラマーになりたい人へ」を発売しました。
同時に、Javaプログラマーとしてのキャリアをスタートしたい人向けのプログラミングスクール「サイゼントアカデミー」も開校しました。
ご興味のある方は是非!

二重サブミットのテストにはクリック連打ツールを用いる

Webシステムでは、同一のサブミット(リクエスト)が二重送信されることによる障害が起こり得ます。
二重サブミットが発生する原因としては、以下の3つが挙げられます。

  1. サブミットボタンを連打する
  2. ブラウザの戻るボタンで遷移元の画面に戻り、再度サブミットボタンを押下する
  3. サブミット後に遷移する画面で、ブラウザよりリロード操作が行われる

これらの原因による二重サブミットは、実装により回避することができます。
回避できているかどうかは、1~3の操作を行うことでテストすることができます。


ここで、1の操作については、手動でのクリックでは発生しないことがあるので、注意が必要です。
手動の場合は約0.1秒おきにクリックするのが限度だと思うのですが、端末やWebシステムの処理速度が早すぎる場合、手動で2回目のクリックを行う前に画面遷移が行われてしまい、二重サブミット対策の実装が行われていないのにも関わらず二重サブミットの問題が発見できないことがあります。

そこで、1の操作を試す場合は、クリック連打ツールを試すのが有効です。
クリック連打ツールであれば、0.01秒おきや0.001秒おきのクリックが可能になり、処理速度が早すぎる場合にも二重サブミットの問題をより高い精度で発見することができるようになります。

以下は、自作のWebシステムで、クリック連打ツール「連打くん」を試した結果です。
自作のWebシステムは、掲示板に文章を投稿するという簡単なものであり、クリックでは簡単に二重サブミットが発生しないほど性能は良いです。
このような性能が良いシステムに対しても、連打くんで0.01秒おきにクリックを行うことで、二重サブミットの発生を確認することができます。

・実行前

・実行後


今回の記事で使用した自作の掲示板のWebシステムは、先日、株式会社サイゼントから発売した書籍「絶対にJavaプログラマーになりたい人へ」にて解説しています。

今回の記事で説明した内容は書籍の範囲から外れた発展的な内容ですが、発展的な学習を行うための基礎を固める上で最適な書籍だと思っておりますし、書籍で作成するような簡単なプログラムが手元にあれば今回の記事で見たように技術の検証もはかどります。

また、株式会社サイゼントでは、Javaエンジニアになりたい人向けのプログラミングスクール「サイゼントアカデミー」をオープンしています!
(前述の書籍をテキストとして用いたカリキュラムとなっています)
ご興味のある方はサイゼントアカデミーのページをご確認下さい。

java:オブジェクト指向を利用する本当の理由

オブジェクト指向を利用する理由として、プログラミングの入門書には
「オブジェクト指向を用いると、現実世界をプログラミングでそのまま表現できる」
という意のことが書いてあることが多いです。
その例として

  • 犬に「ワン」と鳴かせ、猫に「ニャーン」と鳴かせる
  • 乗用車に普通に走らせ、レーシングカーに速く走らせる

といった例が用いられることが多いです。

しかし、実務での使われ方を見ると
「現実世界をプログラミングでそのまま表現する」
というのは、目的ではなく手段と言うべきものです。
実務では
「ソースコードから重複を取り除き保守性を高めるため」
という目的で使用されます。

現実世界の関係性を機械の都合に置き換えると、ソースコードに重複が発生しやすくなります。
そこで、「継承」や「ポリモーフィズム」(同じメソッド名の指定でオブジェクト毎に異なる処理をさせること)といった特徴を持つオブジェクト指向を適用することで、現実世界の関係性をそのまま記述することができるようになり、重複の発生を防ぐことができるようになります。
(同じく、オブジェクト指向の特徴として挙げられる「カプセル化」も、オブジェクト指向のルールを守らせるという意味で強力な特徴です)

目的が保守性の向上であるため、現実世界では意識されにくい「思考ルーチン」「出力機能」といったものも、クラス化されることがあります。
また、保守性の向上に繋がらないのであれば、現実世界にあるものをクラスとして記述しないこともあります。

重複を取り除くことによる保守性向上、というのはイメージしにくい所だと思いますので、以下ではJavaのサンプルコードを用いて説明していきます。


今回のサンプルコードでは、「乗り物に乗って、タイミングを見計らって、乗り物を走らせる」という処理を実装していきます。
「乗り物に乗る」という処理と「乗り物を走らせる」という処理は別々のタイミングで実行する必要があるので、別々に実装する必要があります。
また、乗り物は複数種類があり、それぞれの種類毎で異なる処理を行う必要があるとします。

オブジェクト指向を使用しない場合は、下記に示すようなサンプルコードになります。

【オブジェクト指向を使用しない場合のサンプルコード】

・OOPTestMain.java

【サンプルコードの実行結果】

「乗り物に乗る」という処理と「乗り物を走らせる」という処理は、別々のメソッドとして実装しています。
乗り物の種類毎で処理を分ける必要があり、オブジェクト指向を使用しないサンプルコードではフラグ変数により分けています。

注目するべきは、各々のメソッドの中でフラグ変数を参照していることです。
各々のメソッドの中でフラグ変数を参照しているため、フラグ変数を参照する箇所はメソッドの数だけ存在することになります。
フラグ変数の参照方法が変更される場合、例えば「自転車」を示すフラグが2から3に変更になる場合、修正する箇所もメソッドの数だけ存在することになります。
(具体的な修正箇所はサンプルコード中にコメントで示した通りで、今回の場合は2か所です)
修正箇所が増えることで保守性が低下します。具体的には、修正漏れのようなミスが発生しやすくなります。


サンプルコードにオブジェクト指向を適用すると下記のようなコードになります。

【オブジェクト指向を使用する場合のサンプルコード】

・OOPTestMain.java

・OOPTestVehicle.java

・OOPTestCar.java

・OOPTestBicycle.java

注目するべきは、ポリモーフィズムを使用することで、フラグ変数参照に相当する記述を削減できていることです。
フラグ変数の参照に相当する処理としては、クラス名の参照がありますが、クラス名に変更が発生したとしても修正箇所は1カ所に留まるため、保守性が向上します。


今回の記事は、Javaプログラマーとして活躍し始めた後に意識するべき内容であり、入門レベルよりも少し高度なものになります。
しかし、意識するのとしないのとでは、プログラムをリリースした後の保守のしやすさが変わってきます。
指示されたものを作って終わりではない、お客様からの信頼を得られるシステムを主体的に作るためには、こうした設計思想も学ぶ必要があります。

設計思想を学ぶ上では、前提知識として、プログラミング言語の基礎的の文法の理解が必要になります。
先日弊社から発売した書籍「絶対にJavaプログラマーになりたい人へ」で基礎的な文法の理解を固めることで、今回のような設計思想の話も理解しやすくなるのではないかと思います。
(興味がある方は是非とも購入のご検討を!)

Java:リテラル用の領域の確保について

Javaの変数の型は、プリミティブ型と参照型に大別されます。
そして、変数の値が同じであるかどうかを確認する場合、プリミティブ型は == で同じ値であることを確認できる(同じ値の場合はTrueになる)のに対し、参照型の場合は原則として == では確認できず、equalsメソッドを使う必要があります。

しかし、参照型の場合であっても、== で確認できる場合があります。
それは、参照型の変数にリテラル(ソースコード内に直接記述された定数値)を直接代入した場合です。

以下で、順番を追って説明していきます。

【メモリーへの値の保持の方法】

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

プリミティブ型も参照型も、「メモリーに保持される」ということは変わりませんが、メモリーに保持する値は変わります。プリミティブ型変数では値そのものをメモリーに格納するのに対し、参照型変数ではメモリー上にその変数用の保存領域を確保した上で、その保存領域の場所を指し示すアドレスを変数の領域に格納します。

例として、以下のソースコードについて考えます。

このソースコードの場合のメモリーのイメージは以下です。
プリミティブ型変数の「i1」と、参照型変数の「il1」では、値の保持の方法が異なります。

【リテラル用の領域の確保】

リテラルの場合は、リテラル用の領域が別途確保されます。
そして、同じ値のリテラル値が複数の箇所で記述されていたとしても、全ての箇所において同じ領域が使いまわされます。

参照型変数でインスタンス化した(newした)場合は、仮に同じ値だとしても、インスタンス化する度に異なる領域が確保されるため、その挙動とは異なるものとなります。

例として、以下のソースコードについて考えます。

このソースコードの場合のメモリーのイメージは以下です。
リテラル値を代入した「s1」「s2」と、インスタンス化で新たに領域を確保した「s3」「s4」では、値の保持の方法が異なります。

【比較を行った場合の挙動の違い】

上記より、リテラル値を代入した場合と、インスタンス化を行った場合では、値の保持の方法が異なります。

この違いが表れるケースの一つとして、値が同一であるかどうかを確認するケースがあります。
リテラル値を代入した参照型変数同士を比較する場合は、インスタンス変数同士の比較と同じように、== で値が同一であることを確認できます。
(もちろん、equalsメソッドでも比較可能です)
しかし、インスタンス化を行った参照型変数の比較では、== で値が同一であることを確認することはできず、equalsメソッドを使用する必要があります。

また、equalsメソッドであれば、リテラル値を代入した参照型変数とインスタンス化を行った参照型変数の比較も可能です。

これをソースコードで示すと以下の通りです。
(実行結果となる標準出力はコメントで示しています)


リテラル用のメモリー領域の確保について深堀りする機会があったので、記事を書きました。

実務では、普段からString型のような参照型の変数をequalsメソッドで比較する癖をつけておけば大丈夫です。
しかし、リテラル代入と == の組み合わせで比較している場合、後の修正でリテラル代入の代わりにインスタンス化を使う箇所が現れると上手く比較できなくなるので、注意が必要です。