2012年07月02日

コミュニケーション能力とは何なのかな

よく言われるコミュニケーション能力。

いつも言われることは、飲みニケーションや趣味が充実していることが、最終的には営業としてうまく成約に結びつくという話です。彼らの言い分としては、飲みニケーションはコミニケーションを潤滑に行うために必要ということです。また、話の面白さもそういう面でコミュニケーション能力の一つだということが叫ばれています。
論理がおかしく、飲みニケーションはコミュニケーション能力の一部であるという主張をいいながら、それが全てでそれがなければコミュニケーション能力があるとは言えないと言い始めます。
話が常にそれぞれ独立して論理を展開するため、聞いている側は反論できないのがポイントです。
そして、それを発揮するから仕事が取れるという言い分をよく聞きます。
そうするから顧客から信頼が得られるとも主張されます。

さて、コミュニケーション能力とはどういう意味なのでしょうか。
普通に訳すと意思疎通でしょうか。Wikipediaによれば、「交流」であり、「生命体 (人間、動物、植物、微生物等)が、感情、意思、情報などを、発信受信応答、つまりは、相互連絡関係をもとうとすること。」のようです。
ポイントは相互に連絡関係がある状態であることでしょう。

意思疎通。意味は、自分の意思(考え、思い、感情、情報が主たるものでしょう)について、相手が疎んじている状態を通ずる状態にすることではないでしょうか。
疎んじている状態とは、理解が不完全であるということです。それを通ずるようにするということは相手に理解させるということです。

コミュニケーション能力は、会話の能力ではありません。相手に理解させる能力です。

確かに、英語において話すに関連する英語は、speak, talk, chat, lay on, conversation, open one's, tell, ask, have face等があります。これらは意味が異なり、speakとtalk(の半分ぐらい)は一方的な能力、askやtellは問い合わせる能力、chatやconversation、その他は会話や雑談のような意味です。では、理解はというと、comprehendやunderstandがありますが、これらは〜を理解するという意味です。
どこにもcommunicationが出てきません。ここでよく言われる飲みニケーションを考えると、確かにコミュニケーションを取る上で、話すということや理解するということはコミュニケーションの重要な要素、手段であることは確定できます。が、必ずなければならないというものでもありません。

なぜそんなことを言うのかといえば、私はコミュニケーションについての研究を学生時代担ってきたからです。
コミュニケーションには、大きくバーバルコミュニケーションとノンバーバルコミュニケーションがあります。この二つを発揮することがコミュニケーション能力を発揮するということです。
そして、バーバルコミュニケーションは、口頭でなくても手紙でもよく、むしろ飲み屋でなくても、面白い話でなくても、趣味が通じなくても良いものです。
ノンバーバルコミュニケーションは非言語コミュニケーション。つまり、仕草や表情といったものです。これらを駆使し、相手に自分の主張を理解させることができる能力をコミュニケーション能力というと私は考えます。ポイントは、バーバル、ノンバーバル両方もしくは片方を相手にあわせて適切に使いこなすことができ、その結果相手に主張を理解させることができることです。

以下は、とても失礼なことを言います。不快に思う方がいましたら、本当に申し訳ございません。ですが、言わせていただきます。
コミュニケーション能力がそのように定義されなければ、もし障害があることで話せなくなった方、耳が聞こえなくなった方はコミュニケーション能力を絶対に持てないことになります。
また、お酒が飲めない方、無趣味の方は相当な努力が必要になってしまいます。
元々の先天的、後天的な状況をもってしてコミュニケーション能力の有無を語ることは、本来の意味の達成とは異なるのではないかと考えました。

私はコミュニケーション能力とは、相手の理解のために努力すること、そのために言葉や表情、仕草、資料等をどこまで相手の理解のために用意でき、その用意を相手のために奉仕できるかではないのかという、思いやりの能力だと思いたいのです。
その結果、営業的に成約できるのは、誠意と信用が生まれた結果であって、決してコミュニケーション能力の有無とはまたこれらは関係ないとも思いたいのです。


最初の多くの主張である飲みニケーションはchatやconversationであって、communicationではないと思います。どこかでうまく、相手の中に信用を得ることができたり、探り探り相手の考えをくみとることができたり、もしくは本当にcommunicationが部分的に発揮できた結果、飲みニケーションで成果が得られ、それがいつの間にかコミュニケーション能力の一部と勘違いされたのではないかと思いたいのです。


コミュニケーション能力とはつまり、誰かが一部の人間のための能力ではないということを言いたく、また、有無について語ることは無意味だと思います。無いのではなく、思いやりや相手の理解への配慮が足りないだけだと考えたいと思うのです。


これらは完全に私の個人的な意見です。人の考え方についてどうこう言うつもりもありません。
ただ、よく言われる「あいつはコミュニケーション能力がない」というのは、もっと考えて私も発言したいと反省しました。これは、それ自体が相手とのコミュニケーション、つまり相手の状態への配慮が欠けた状態だからです。これは、そもそもの人間関係を醸成する行為の否定であって、自らアンテナを閉じた状態なのかと考えました。
ここから色々と考えて上述の思考にたどり着きました。

勝手ながら、きっと私たちは思いやりという面で、何か重要なものを忘れてしまったような、そういうことが感じられることが多く、私はもっと反省すべきと気づきました。という告白です。


余談ですが、社内で飲みニケーションが推奨される会社もあります。ポイントが発行されたりというところもあるそうです。それはコミュニケーションとは別としてもおもしろいと思いました。

2012年07月01日

JSF実装のELライブラリをスタンドアロン・プログラムの中で利用する

Javaによる画面アプリケーションでは、EL式と呼ばれるものがJSPやJSFに組み込まれて利用されます。
そのEL式は、やっぱり基本的にはWebアプリケーションサーバー上で利用することが前提でよく記述されています。一応EL式のライブラリ自体は切りだされていますが、いまいち使い方が分からないです。

例えばスタンドアロンアプリケーションを作り、その中で便利だからELだけ使いたいという場合。
そういう場合でもELのためだけにWebアプリケーションサーバーを導入したり、もしくはそのためにJSFライブラリ全体を持ってきたりするのは面倒です。
ApacheのJEXLApache Commons EL等のライブラリでも良いのですが、ELはGlassFish(mojarra)の実装がやはり一番速度が速いようなので、こちらを何とかして使いたいというかたも多いでしょう。でも、簡単に何もせず、APIだけで組み込むことができなくて苦労します。また調べても、すぐには何も見つかりませんでした(英語でも調べたんですが。。。)

なので、どうやったら簡単に自分のアプリケーションにEL式を組み込めないかなと考えていました。
(考えていただけで、家でのプログラムではEL式を利用するつもりは今のところないのですが)
色々と試してみましたが、スタンドアプリケーション用のELContextとELResolverを実装するしかないのかなぁという結論に至りました。
もっといい方法があるかもしれません。。。

参考までにソースを紹介しますので、ご自由にご利用くださいませ。Javadocコメントは若干適当です。

LocalELContext.java (ELContextと中で利用するELResolver実装です。)

import java.beans.FeatureDescriptor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.el.ArrayELResolver;
import javax.el.BeanELResolver;
import javax.el.CompositeELResolver;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.FunctionMapper;
import javax.el.ListELResolver;
import javax.el.MapELResolver;
import javax.el.VariableMapper;

import com.sun.el.lang.FunctionMapperImpl;
import com.sun.el.lang.VariableMapperImpl;
import com.sun.faces.el.PropertyResolverChainWrapper;
import com.sun.faces.el.PropertyResolverImpl;

/**
* ローカル変数を起点としてELを実行するためのELコンテキスト
*
* @author Kiruah
*/
public class LocalELContext extends ELContext {

/** ELContext初期化済みかどうかを指定する */
protected static Boolean initialized = Boolean.FALSE;

/** ローカルEL解決者 */
protected static LocalELResolver resolver = null;

/** メソッド呼び出しマッパー */
protected static FunctionMapper functionMapper = null;

/** 変数取得マッパー */
protected static VariableMapper variableMapper = null;

/**
* 初期化処理
*
* @param object 取得対象のオブジェクト
*/
public LocalELContext(
Object object) {

if (initialized == false) {
initialize();
}

if (resolver == null) {
resolver = new LocalELResolver(object);
}
}

/**
* 初期化処理
*/
protected void initialize() {

synchronized (initialized) {

if (initialized == false) {
if (functionMapper == null) {
functionMapper = new FunctionMapperImpl();
}

if (variableMapper == null) {
variableMapper = new VariableMapperImpl();
}

if (LocalELResolver.compositeResolver == null) {
CompositeELResolver elResolver = new CompositeELResolver();

elResolver.add(new ListELResolver());
elResolver.add(new MapELResolver());
elResolver.add(new ArrayELResolver());
elResolver.add(new BeanELResolver());
elResolver.add(new PropertyResolverChainWrapper(new PropertyResolverImpl()));

LocalELResolver.compositeResolver = elResolver;
}

initialized = Boolean.TRUE;
}
}
}

/**
* EL解決者を取得する
*

*

(オーバーライドメソッド)


* @return EL解決者
* @see javax.el.ELContext#getELResolver()
*/
public ELResolver getELResolver() {

return resolver;
}

/**
* メソッド呼び出しマッパーを取得する
*

*

(オーバーライドメソッド)


* @return メソッド呼び出しマッパー
* @see javax.el.ELContext#getFunctionMapper()
*/
public FunctionMapper getFunctionMapper() {

return functionMapper;
}

/**
* 変数取得マッパーを取得する。
*

*

(オーバーライドメソッド)


* @return 変数取得マッパー
* @see javax.el.ELContext#getVariableMapper()
*/
public VariableMapper getVariableMapper() {

return variableMapper;
}

/**
* ローカルEL解決者
*
* @author Kiruah
*/
protected static class LocalELResolver extends ELResolver {

/** ネストされたEL解決者 */
protected static CompositeELResolver compositeResolver = null;

/** 探索対象のオブジェクト */
protected Object object = null;

/**
* コンストラクタ
*
* @param object EL実行対象のオブジェクト
*/
public LocalELResolver(
Object object) {

this.object = object;
}

/**
* 値を取得する
*

*

(オーバーライドメソッド)


* @param context ELコンテキスト
* @param base 探索対象
* @param property EL式
* @return 取得結果
* @see javax.el.ELResolver#getValue(javax.el.ELContext, java.lang.Object, java.lang.Object)
*/
@Override
public Object getValue(
ELContext context,
Object base,
Object property) {

if (base == null) {
return compositeResolver.getValue(
context,
object,
property);
} else {
return compositeResolver.getValue(
context,
base,
property);
}
}

/**
* 型を取得する
*

*

(オーバーライドメソッド)


* @param context ELコンテキスト
* @param base 探索対象
* @param property EL式
* @return 型
* @see javax.el.ELResolver#getType(javax.el.ELContext, java.lang.Object, java.lang.Object)
*/
@Override
public Class getType(
ELContext context,
Object base,
Object property) {

if (base == null) {
return compositeResolver.getType(
context,
object,
property);
} else {
return compositeResolver.getType(
context,
base,
property);
}
}

/**
* 値を設定する
*

*

(オーバーライドメソッド)


* @param context ELコンテキスト
* @param base 探索対象
* @param property EL式
* @param value 設定値
* @see javax.el.ELResolver#setValue(javax.el.ELContext, java.lang.Object, java.lang.Object, java.lang.Object)
*/
@Override
public void setValue(
ELContext context,
Object base,
Object property,
Object value) {

if (base == null) {
compositeResolver.setValue(
context,
object,
property,
value);
} else {
compositeResolver.setValue(
context,
base,
property,
value);
}
}

/**
* 読み取り専用か取得する
*

*

(オーバーライドメソッド)


* @param context ELコンテキスト
* @param base 探索対象
* @param property EL式
* @return 読み取り専用かどうか
* @see javax.el.ELResolver#isReadOnly(javax.el.ELContext, java.lang.Object, java.lang.Object)
*/
@Override
public boolean isReadOnly(
ELContext context,
Object base,
Object property) {

if (base == null) {
return compositeResolver.isReadOnly(
context,
object,
property);
} else {
return compositeResolver.isReadOnly(
context,
base,
property);
}
}

/**
* 特徴の説明情報を取得する
*

*

(オーバーライドメソッド)


* @param context ELコンテキスト
* @param base 探索対象
* @return 特徴の説明情報
* @see javax.el.ELResolver#getFeatureDescriptors(javax.el.ELContext, java.lang.Object)
*/
@Override
public Iterator getFeatureDescriptors(
ELContext context,
Object base) {

if (base == null) {
return compositeResolver.getFeatureDescriptors(
context,
object);
} else {
return compositeResolver.getFeatureDescriptors(
context,
base);
}
}

/**
* 共通のプロパティタイプを取得する
*

*

(オーバーライドメソッド)


*
* @param context ELコンテキスト
* @param base 探索対象
* @return 共通のプロパティタイプ
* @see javax.el.ELResolver#getCommonPropertyType(javax.el.ELContext, java.lang.Object)
*/
@Override
public Class getCommonPropertyType(
ELContext context,
Object base) {

if (base == null) {
return compositeResolver.getCommonPropertyType(
context,
object);
} else {
return compositeResolver.getCommonPropertyType(
context,
base);
}
}
}
}


この中では、ELライブラリで標準で実装されている
・ListELResolver
・MapELResolver
・ArrayELResolver
・BeanELResolver
・PropertResolver
のみCompositeELResolverにセットし包含しています。
ELはトップノードのアクセス時のみgetValueのbaseがnullとなりますので、その場合のみ指定のオブジェクトを探索するようにし、それ以外はbaseを利用するようにするという程度のものです。
初期化処理は冗長です。static {} を使えばいいのですが嫌いなのでこういう感じになっています。

利用する場合は以下の様な実装となります。

Main.java

import java.util.HashMap;
import java.util.Map;

import javax.el.ELContext;
import javax.el.ExpressionFactory;

import com.sun.el.ExpressionFactoryImpl;
import com.sun.el.ValueExpressionImpl;

/**
* EL組み込みのサンプル
*
* @author Kiruah
*/
public class Main {

/**
* メイン
*
* @param args コマンドライン引数
*/
public static void main(
String[] args) {

Map container = new HashMap();
container.put(
"hoge1",
"hogehoge1");
container.put(
"hoge2",
"hogehoge2");

String el = "${hoge1}";
Object value = get(
container,
el);

System.out.println(value);
}

/**
* EL式を利用して取得対象から値を取得します。
*
* @param target 取得対象
* @param el EL式
* @return 取得結果
*/
public static Object get(
Object target,
String el) {

ELContext context = new LocalELContext(target);
ExpressionFactory ef = ExpressionFactoryImpl.newInstance();
ValueExpression ve = (ValueExpression) ef.createValueExpression(
context,
el,
Object.class);

Object value = ve.getValue(context);

return value;
}
}


こうすることで、自前で用意しているコンテナがあれば、そこからEL式を利用して値を取得することができます。

ちょっと実装しなければならないとできなかったのが、自分の調査・スキル不足ならば、もっと勉強や自己研鑚が必要です。
頑張らねば。
posted by Kiruahさん at 01:00| Comment(0) | TrackBack(0) | ノウハウ

2012年06月30日

Eclipseのマニュアルを書くつもりが。。。

ずっとEclipseの使い方マニュアルを書こう書こうと思っていたのですが、結局かけずじまい。そうこうしているうちに新しい4.2 Junoがリリースされてしまいました。

うーん、私も作業が遅いなと思います。反省すべきです。
今年はより計画的に作業を進めたいと思う次第です。
posted by Kiruahさん at 14:11| Comment(0) | TrackBack(0) | 日記

2012年06月16日

JSP/JSFでの項目をフォーマッティングするタグをできる限りやめてみる

JSPやJSFの魅力の一つにカスタムタグがあります。タイトルはこのカスタムタグを否定しています。
カスタムタグを利用することで、モデル層・コントロール層でいちいち画面に表示する内容を整形する必要はありません。これらは全てどのように表示するかをビュー層に任せることができ、MVC構造上分かりやすい(責任境界が明確)と言えます。

例えば仕様変更によって、画面上の日付をyyyyMMddからyy/MM/ddに変更する必要が発生した場合、カスタムタグ(これぐらいならJSPの標準タグでできそうですが)を用いれば、ビュー層まではDateやTimestamp型で送られてきているため修正は不要です。結果、JSPのその出力タグのどのように表示するかを指定する属性を変更するのみで、修正は終了です。

ポイントは、修正はこれで終了である、という点です。

テストはというと、画面を実際に表示する必要があります。
さて、ここでこのカスタムタグが十分にテストされていることを前提としている場合でも、本当に問題がないのかを確認するには、JSPを表示してみる必要があります。これで実はMMの部分が月ではなく、分を指定していたとしても、たまたま12分までの間にテストをしていたら、修正ミスに気付けません。よって、テストでは12分以上をしっかりと確認する必要があります。
現状の開発では、Seleniumを使わず結局目視で確認しています。また、目視でもしっかりとしたテストケースをあげているケースもレアです。こういう場合は、しっかりと最小桁、最大桁のテストとして、00と12はテストする必要があります。仕様をしっかり確認し、分のところの00は0になるのか00のままなのか、分になっていないのかを確認する必要があります。

さて、seleniumを使っていたとしても、仕様変更のためにシナリオを変更してここまで確認するのは面倒です。seleniumはやっぱり目視での確認後に、デグレが発生していないかを確認するためのものとして現場では利用されているのでしょうか?

弊社では、seleniumすら利用しようという空気はないため、目視1ケースのみで終了となり、同時に回帰テストは二度と行われません。
よくあるのが、ここで結局ミスをしていたというのも多発しています。


カスタムタグが十分にテストされているケースであればまだ良しと言えます。このカスタムタグが弊社自作の場合で、かつ、十分なテストが実施されていない場合は、このカスタムタグをテストしているのか分からない状況になることもあります。


最近のWebアプリケーションの見栄えはとてもよく、例えば長い文字列を表示する場合は、"..."と省略形に自動的になり、マウスを近づけるとチップ形式で全文が表示されます。
業務アプリケーションにおいては、技術が時代に取り残されているのもあります(枯れたものを好んでいると理解しておきましょう)が、業務では一覧性が重要視されるために、文字列が省略されることなど滅多にありません。
つまり、表示したい内容はまさに、そのまま書式化されたものを単純に表示すれば事足ります。


カスタムタグにあるような、書式を自由に変換できるタグは一切利用せず、これらは全てビュー層の前、ビジネスロジックで実施すべきです。そして、ビュー層ではその値がそのまま表示されるかどうかだけを確認します。

こうすることによって、ビュー層とビジネスロジック層のテストを分離しやすくしたいと考えています。

・ビュー層
ビュー層では、ビジネスロジック層のモックがフル桁および、最小桁のデータを渡すようにしておきます。
これがレイアウト上崩れないことを確認するのみのテストとすることで完結させます。
よって、ビュー層のみの単体テストを実施します。

・ビジネスロジック層
こちらはビュー層に渡すデータを出力として、JUnitでアサートするテストとなります。
つまり、日付であれば、テストケースとして正しくビュー層に表示すべき内容を変換してから渡しているか網羅的にテストすることとなります。こうすることによって、単純な書式の変更や変換の不具合の確認は、ビュー層で確認するよりもはるかに回帰テストしやすいものにできます。
ビジネスロジック層はそれ単体のみの単体テストを実施します。

・ビュー層とビジネスロジック層の橋渡しを行うBean
これはフレームワークにもよりますが、正しくビュー層・ビジネスロジック層で利用されているか、確認しやすいよう、それぞれ分かりやすい命名規約を用いることを推奨します。

・結合テスト
こちらはレイアウトや表示内容に関する網羅的な結合テストは実施しません。あくまで機能に特化したテストを実施し、ビューとビジネスロジックで正しい業務処理が行われるかの確認を行います。
ページ遷移はやむをえないでしょうが、フル桁はどうか、フォーマットはどうかなどの確認は不要です。そのままビジネスロジック層のデータが出ているかを確認します。
(当然、各項目ごとに値を変えて、出すべき変数名を間違えていないかを確認するのは言うまでもありません。こればかりはJSPやJSFでは確認しようがないでしょう。)


まとめると、私は、ビジネスロジック層で画面に表示する全項目の書式変換を行うべきだと考えています。


これはメリット・デメリット両方あります。
メリットは、Seleniumのシナリオで網羅性はあまり考えなくて良いでしょうし、JUnit/TestNGを利用するのでJenkins/Hudsonでバックグラウンドでテストさせておくと良いでしょう。また、カスタムタグだけでは表現しきれないものは、工数見合いで結局ビジネスロジック層に実装することが多いため、ビジネスロジックに集約することでライブラリ化が容易になります。

デメリットは、JSPの修正だけであれば、JSPを置き直すだけでリコンパイルされるのですが、ビジネスロジックを修正する場合はアプリケーションサーバーのホットデプロイか、サーバーの再起動が必要なのが面倒でしょう。
もとから変更はサーバーを止めてしっかり検証するでしょうが、緊急対応には向かないかもしれません。
posted by Kiruahさん at 18:09| Comment(0) | TrackBack(0) | ノウハウ

2012年06月14日

これから始めるSubversionの使い方

弊社では、未だにSubversion(svn)を利用してソースやドキュメントのバージョン管理をしています。
まだ、ドキュメントをバージョン管理している案件はましなのですが、未だに全部を共有ファイルサーバー上で管理して、編集前にバックアップフォルダに日付を付けて移動。。。ということをやっている方々も多いです。

Subversionですら、浸透するまでに4年近くかかりました。本当はMercurialかGitにしたいのですが、TortoiseSVNから離れられない人が多いのと、新しいことを覚えたくない人と、分散バージョン管理を理解できない人のいずれかが多く、Subversionでうまいこと競合等を管理する必要があると考えていました。

「うまいことやる」ということは、よろしくない状況が発生しているということです。
具体的には以下の様なことが多発しています。

・複数人で開発していると誰かがソースを上書きしてコミットしてしまう(確認不足)
・エラーが発生したままでソースをコミットし、全員がエラー発生状態になる
・そして、エラーが発生していても本人はなかなか修正しない。。。
・動かない設定や自分ローカルで勝手に変更した設定をコミットする
・コミットとバックアップを勘違いしている
・複数人がtrunkで開発するので、どうしても仕方なく構成を変更したい場合、全員一時的にコミットさせ、構成変更後に全員チェックアウト/更新しなおし
あとは個人的な話ですが。
・svn:needs-lockがかかっていると、ちょっと面倒臭い。。。
・svn:needs-lockをかけていると、たまに削除も何もできないファイルがリポジトリサーバに取り残させる。。。
・結局ロックは奪えてしまうので、誰でも変更できる

リポジトリの管理やユーザー管理については、Windows限定ですが、VisualSVNという素晴らしいソフトウェアが無料で提供されており、大変重宝しています。


すでに構築されてしまっているsvnは仕方なしとして、これから新規に始める案件で、svnも新規に作れる案件ではこうしようと考えています。


1. ディレクトリ構成
従来までは以下の様な構成でした。
-+branches
+tags
+trunk

これをこのように変更します。

-+branches
+tags
+releases
+trunk
+groups
+users

・branches
個別の仕様変更ごとにディレクトリ名をつけてtrunkの内容をコピーします。
フォルダ名は案件にもよりますが、通常は以下のいずれかようになると考えています。
1) 日付-内容
2) 案件管理番号-内容
3) 案件管理番号-日付-内容
4) 顧客名/日付-内容
5) 顧客名/案件管理番号-内容
6) 顧客名/案件管理番号-日付-内容
(/はディレクトリをさらに作ることを意味しています。)

・tags
プロジェクト内マイルストーン単位でディレクトリ名をつけてtrunkの内容をコピーします。
フォルダ名は案件にもよりますが、こちらも通常は以下のいずれかようになると考えています。
1) 日付-内容(理由)
2) マイルストーン名-内容(理由)
3) マイルストーン名-日付-内容(理由)

・releases
通常は顧客には複数の環境が用意されています。例えば、顧客検証用、顧客受入用、顧客内ベンダー開発機、リリース検証機、本番機、災対機(待機系)。さらには自社の開発環境、テスト環境(単体/結合/総合等)があります。
それぞれ、どのパッチをどこまで適用するか異なる場合があります。それが順次段階を経て適用されるのであれば良いのですが、これまで数回、緊急のためにすぐにリリース検証機で簡単な検証後、本番に適用し、数日後に他のサーバーに適用ということがありました。
そして、運が悪いことに顧客都合によってそのスケジュールが延びることもあります。これらをどこまで適用したか管理するためにExcel管理台帳とか、共有フォルダにおいていたりしましたが、これをsvnのreleasesにディレクトリ単位で管理したいと考えています。

同時に、パッケージやそのカスタマイズ結果など、複数の顧客を管理する必要がある場合にも利用します。

具体的には以下のディレクトリ構成を採用します。

releases/顧客名/No-環境名
Noは適用順序を示します。二桁で統一します。(1なら01とする)

・trunk
trunkはこれまで通りの利用方法に近いです。安定版の最新を入れる形になります。
が、こちらもディレクトリ構成を分ける方が良いでしょう。

1) trunk/stable
2) trunk/develop
3) trunk/チーム名/
4) trunk/顧客名/

などです。

・groups
こちらは用意するかどうかは案件の規模によります。
大きい場合はグループごとにディレクトリを分けます。

groups/グループ名/

このグループの下は、グループ単位で成果物を取りまとめる場合に利用します。
つまり、グループ管理者が一度ここにユーザーの成果物をとりまとめ、問題がなければtrunkにマージします。

・users
こちらは開発者単位でディレクトリを作成します。

users/ユーザー名/
ユーザーが自由にコミットしてよいディレクトリとなります。

groupがある場合はユーザーはgroupにのみマージできます。また、groupがない場合はtrunkのdevelopにのみ、ユーザーはソースをマージできます。


2. ユーザー
ユーザーとグループの管理をきっちりと行います。
一般ユーザーはusers/配下の自分のディレクトリにしかコミットできません。よって、チェックアウトもそこから行います。案件に参画したタイミングで、trunkの必要な情報を自分でコピーします。
また、場合によってはgroupsに自分のコミット分をマージできます。groupsがある場合は一度groupsにコミットし、trunkの反映はそのグループの管理者のみが行えます。逆にgroupsがない場合はユーザーはtrunk/developにマージできますが、trunk/stableへのマージは案件のライブラリ管理者がチェック後、行います。


3. ライブラリアンをたてる
ライブラリアンしか、ユーザーの管理、グループの管理が行えません。通常最大でも3名とします。
さらにグループ毎に1名をグループのサブライブラリアンとし、trunk/developにコミットする権限を有します。
ですが、trunk/developからtrunk/stableやbranches、tagsにはライブラリアンしか変更できません。


4. 個別要件(ブランチやタグ)の管理
ライブラリアンは案件上ブランチやタグに直接コミットできるユーザーを指定し、個別機能の修正を許可することができます。


5. needs-lockは使わない
ロック機能は使わないこととします。また、ライブラリアンも直接stableを変更せず、自分のユーザーディレクトリの中で変更後、trunk側にマージすることとします。


6. ライブラリアンはtrunk/stableを変更した場合、ユーザーは任意のタイミングでtrunk/stableをマージできる


7. できる限り、グループの管理者、ライブラリアンが修正結果の連絡を受け取りマージする。つまり、ユーザーには本体のtrunk等には変更権限を与えない


まだまだやり方や構成については検討の余地があると思います。それは管理がまだ面倒そうだというところです。
ですが、これでかなり管理者の自由度が上がるのではないかと考えています。
もう少しドキュメント化したり、実際にやってみてブラッシュアップしたいと考えています。
posted by Kiruahさん at 20:00| Comment(0) | TrackBack(0) | ノウハウ

2012年05月01日

弊社で叫ばれている内容を聞いて感じたこと

これから書く内容は、たくさん失礼な内容が記載されています。
気分を害された方は無視して下さいませ。

私自身、SIerで働いています。その中でも色々とやはり議論を重ねているのですが、どうやってもみんなの考え方が分からない面があります。
それが標準化というものです。
設計を標準化する、製造を標準化する、そのために評価方法、分析方法を定量的にし、フレームワークを当て、誰も自由な設計や製造ができないように当てはめていこうとする考え方です。
これは別に間違えではないと思っています。それが、SI業界でなければです。
まずそもそも、品質に問題があって炎上したプロジェクトにおいて、炎上した原因は2つのどちらか、もしくは両方しかないと思います。

1) そもそも達成できない予算のプロジェクトで、お金がない
2) 参画している人間のスキルがない

よって、なぜ失敗したかなんて分析するまでもないと思っているのですが、会社ではバグの内容は何だったのか、それによってどれだけの影響がどうでたか?
そういったことを分析したり、収集したりしています。そして、ずっと分析結果は出なかったりしています。。。
対策方法もありません。予算を増やすか、参画している人間のスキルがあがらなければ、どんなに一番簡単で泥臭いやり方であるチェックリストを作ろうともチェックするのが人間なのだから、抜け道ができてしまいます。

まぁ、それでも標準化したら、スキルのない人間でも、それしか設計できない、それしか実装できないようになるのだから、品質はあがるだろうという認識のようです。
そもそもソフトウェアにおける品質なんて、要件通りに作るのが品質の基本であって要件通りでなければ品質は満たしていない、それ以上は品質の向上ではなく、満足度の向上でしかないという事実は無視されています。

もしも、もしも本当にそんなことができるなら、きっとSAPやOracleはもっと日本市場に力を入れてもいいと思うでしょうね。
それぐらい日本の商習慣や各社の文化はかなり違い、また、パッケージがあるべき姿をある程度投影しているのに、業務をパッケージに合わせるのではなく、パッケージを業務に合わせて、カスタマイズと言う名前のスクラッチ開発をしたりもしていますよね。


簡単な例でいえば、ナンプレが作らないといけないシステム、その上で答えようとしているのが幼稚園児レベルのスキルの人間なのが、現在のSIerの状況です。
ナンプレの問題を作るのは顧客の要件がポイントです。ナンプレであれば、これだけ揃えばかなり簡単になるとか分かるでしょうが、顧客の出す要件はそもそもそのナンプレの問題にすらなっていないことがあります。だから、せめて目的だけでも要件定義しなさいとは思うのですが。。。
でも、なんとかナンプレの問題になるレベルが出たとしても、それを解くのは幼稚園児レベルです。もし、幼稚園児が解けるのであれば、その分野においてはその幼稚園児は中学生レベルですね、きっと。でも、幼稚園児ではなく、幼稚園児レベル。。。

そして、SIerではPMOが幼稚園児レベルの人に、「何で間違えたんだ?」とか、「何で答えがあっているか確認しなかったんだ?」とか叱っている風景ばかりです。
その中で優秀なSIerの社員は、標準化を掲げて、設計や製造の自由度を下げて、幼稚園児レベルでも解けるよう、正確には考えなくてもいつかはあてはまるように、考えてあげているわけです。
それは少しシステム化され、ナンプレの問題が本ではなくExcel上で書かれていて、一箇所数値を埋めると、自動的にその数値は他の箇所では使えないように選択肢が選択できなくなるレベルのもの。それでもないよりはマシかなというレベル。
もしくは、事前に答えのチェックができるのかもしれないですが、そんなに柔軟に判定できるシステムを作れるなら、最初から不具合のないシステムを作れるのでは?

そして、そんなにすごいもの、当然優秀な社員でも作れないのです。

時間も工数もなければ予算すら割り当てられず、というか、優秀な社員でも一人で何か一つのアプリケーションを作ることができないのですから、、、そんなすごいシステムを作ることは難しいです。
せめて10万ステップのプログラムを一人で作ったりとかできればまた違うのでしょうが、そんなスキルのある社員はSIerにはほぼいません。


余談ですが、SIerの社員で最も求められていると勘違いされていることの一つにコミュニケーション能力があります。でも、コミュニケーション能力は話がおもしろいとか、そういうことではなく、いかに相手に要点を理解させるか等の、その方法論であることは気づかれていないところが面白いです。よって、ノンバーバルコミュニケーション能力が無視されています。本当のコミュニケーション能力について理解されないまま、あの人はコミュニケーション能力があるとかないとか話されているが面白いです。話が面白いのはコミュニケーション能力の一つではなく、一部でもなく、要素に過ぎないのであって、他で補間できるのであれば必須ではないというのも事実です。


話がそれましたね。。。もう少しついでにそらすと。。。
ミスに気づかない人間は、何度やっても何年やっても、それをミスだと知らされても、そうならないよう努力してミスの根本を理解し、なぜそれがダメなのか理解できるまで、何回でもミスに気づかないままです。


弊社は1960年代に設立された比較的古い大手のSIerです。でも、人材確保に難点があります。それは上記の考え方があるから、幼稚園児レベルでも人間を集めて、人数で工数を出せば儲けられるという商売の仕方が根底にあります。
対して例えばGoogleやMicrosoft。Microsoftはそれでも古い方ですが、Googleは1998年設立です。それでも弊社はすでに企業規模で負けています。名前でも負けています。
Googleには比較的高いスキルレベルの人間が集まりますし、集めてもいます。誰でも入れる会社ではなく、また入ってからも生き残りが大変です。

あえてこれ以上は言わないでおきます。優秀な幼稚園児に申し訳ないので。。。

今、SIerは先に何をすべきか。業務を拡大するのもいいでしょう、標準化して幼稚園児レベルでも少しでもパズルが解けるよう手助けするのもいいでしょう。人それぞれの考え方はあるので、それをやめろとは言いません。
でも、前提を間違えていると思います。SIerは頭脳労働がメインの業種です。
思考レベルを高めない、高くなくてもいいという方向で、結局間違えることをする人間ばかりで、チェックする、答え合わせするだけのシステムでは、根本的な対策になっていません。
とはいえ、そんなことを言っても、それに賛同する人間が少ないので方向性は変わらないでしょう。

今後、少なくとも弊社は生き残れないかもしれませんね。。。

2012年04月30日

Excelキャプチャツール Ver 2.0のリリース

以前、バージョン1.2としてリリースする予定であったExcelキャプチャツールを、バージョン2.0としてリリースしました。

1.1をベースにしながらも、大幅に実装を共通化したり、Windows 7でも満足する結果(GetDCExでは半透明部分が黒くなるのでやめた)になるよう、変更しました。

使い勝手が変わってしまいましたが、それでも便利ではなかろうかと思いますので、もし利用したい方は、このページからダウンロードください。

ライセンスはいつもどおり、Apache License 2.0です。
posted by Kiruahさん at 15:03| Comment(0) | TrackBack(0) | アナウンス

2012年04月09日

InternetExplorerの古いバージョン(6とか7)から9へそのままHTMLを移行した場合の差異

分かっていた以上に、InternetExplorerのバージョンの違いによって挙動が変わってきており、少々びっくりしました。
まず6と7ではタブが追加されましたので、単純に同一ウィンドウのタブではセッションが共有されてしまうことがあるのもびっくりした記憶があります。
理由はタブが違うだけではクッキーは共有され、クエリ文字列ではなくセッションキーをクッキーに持たせたためだからなのですが。。。
私がまだまだ絶賛開発中のjcwebの中ではセッション情報はページ単位にJavascriptに持たせるようにしようとしています。
そして、毎回セッションキーは使い捨てです。つまり、毎回サーバー側でセッションキーをアクセスさせるたびにワンタイムパスワードのように発行します。
初回はサーバから送られてきたセッションキーをクライアントはそれをAjaxのPOSTパラメータに詰めないといけないという仕様です。
そして帰ってきたレスポンスに新しいセッションキーがあり、次はそれをPOSTパラメータに詰めるということを繰り返します。

この話はまぁ、置いておいて。
ここではよくあるような違いではなく、あまり気づきにくい所を紹介したいと思います。

スタイルシートを利用していない箇所にて、以下のような状況が発生しています。

1. font-sizeを指定しており、互換モード以外の場合、フォントサイズがIE9では大きくなっています。
font-size: small; と指定していた場合、これはIE9では、IE6のfont-size: medium; と同程度の大きさで表示されます。
よって、文字サイズが大きく表示されます。smallやmedium、bigなどで指定している場合は順次大きさがずれています。

2. 行間が小さくなっています。
これはフォントサイズが大きくなっているため、あまり感じにくい面もありますが、特に指定していない場合

3. legendタグのデフォルト色が水色から黒色になっています。

4. 文字の大きさの変更の影響を受けてか、テキストボックスの大きさ、余白も少し変わっています。
これは気づきにくいですが、比べてみると全体的に前よりもアンバランスな見た目に見えます。

また、別途気付いた点があれば随時追加していきたいと思います。
posted by Kiruahさん at 21:00| Comment(0) | TrackBack(0) | ノウハウ

2012年04月08日

相手を思いやることが重要なのではなく、相手の立場になることが重要なのです

新しい年度、今年も新人も会社にたくさんきたようです。
素直におめでとうと思います。

さて、少し関係がないのですが、新人にもやっぱり、優秀な新人、そうでない新人といたりします。
ましてやコンピュータ業界では、できる新人の中にもいくつか分類があります。

・話が得意で営業向きな方(こういう方は後からコミュニケーションで悩むことも多いようですが)
・技術だけが得意な方(こういう方も後から悩むことも多いです)
・どっちも得意な方(こういう方は両方評価されないか、どちらかしか評価されません)
・うまく立ちまわるのが得意な方(こういう人が出世します。が、下から使えないと言われる率も)

ここで一つ、こういう会話があったとします。

Aさん「Bさんはコンピュータに詳しくて本当にすごいよね」
Bさん「そんなことないよ〜」
Aさん「Bさんはだって、コンピュータに詳しいから、勉強しなくても研修の内容ができるから羨ましい。私はついていくだけで精一杯」
Bさん「私はたまたま知ってただけだよ。皆もすぐに頑張れば追いついちゃうと思うよ」
Aさん「スタートからこんなに差がついてたら、ずっと負けちゃうよ。これからもずっと教えてね」
Bさん「そんなことないと思うよ、勉強すれば。でも了解」
Aさん「勉強はやってるんだけどね〜。今週も土日は飲み会なんだ」
Bさん「へぇ〜、友達多くて羨ましいね。いいなぁ。私は今週も家でパソコンで遊ぶだけだからね」
Aさん「パソコンが趣味っていいよね」
Bさん「いいでしょ〜」

どちらがどちらとは言いませんが、実はこれはある一方からもう片方への嫌味の言葉です。
また、突っ込みどころ満載なのは、私の語り方が下手だということでご了承くださいませ。
さらに言えば、私の卑屈感も出ていますが、こちらもご容赦くださいませ。


言いたいことはそんなことではなく、上の「実はこれはある一方からもう片方への嫌味の言葉です。」に対して、何も思わなかった方もいるでしょう。。。

人はそんなに表面だけでは分からないものです。心情、その時の心境、状況、ましてや過去、それが例え10年以上もの友人関係で会ってもわからないことが多いです。それだけ人間は嘘ではなく、隠しているのでもなく、伝わらないものがあります。

これは、状況によっては両方共嫌味を言っています。

片方は、
「何もしないでもコンピュータが最初からできて、研修もできて、きっと仕事ができるんだろうね。あなたにはどうせ、研修が分からない私の苦労は分からないくせに。最初からできる人は苦労がなくていいね。仕事も楽で。でも、コンピュータばっかりで私生活つまらなそう。まぁ、オタクだからコミュニケーション能力はない人だよね。」と思っているかもしれません。

もう片方は、
「幼い時から頭が悪い子と言われ、何も認められず、そう言われ続けてきた。毎日少しでもその状況を変えたいと、努力して、何でもなぜなのかを考えて、教えてもらわずに生きてきた。やっとその中で少しは自分でも好きなものを見つけて、頭が悪い中でもじっくり時間をかけて理解してきた。だから、私ほどに努力しなくても、簡単に同じステージに今いるあなたが私にはとっても羨ましい。遊んでなければすぐに負けるし、遊ばなければいいのに。」と思っているかもしれません。

どっちもどっちです。
そして、どっちの状況も変わるものでしょう。未来もまた分からないものです。


これだけでも人間関係なんて、推して知るべしなんて簡単に言えないぐらい複雑なもので、分かり合えないことも多いです。それが例え、「こいつはいいやつだ」なんて思える人間どうしてあったとしてもです。

余談です。プロジェクト管理なんかは特にそう。今の管理は人はあくまで頭数。工数だけがモノを言う。誰が作るか関係ない。作る人が決まった後で倍率を単純に決める。そんな程度です。
そこには、どういう手順で、またどういう人を割り当てて、何を知ってもらいたいか、どういう教育を裏でやっていくかは作戦としては全くないのが、IT業界の今のプロジェクト管理に見えます。
できればいい、たしかにそのとおりです。でも、何ができればいいのかは、もっと考えたいと思います。そう、人とはそんなに簡単なものではないのだから。何をやりたいのかをきき、それにできればあわせて、考えたりチャレンジする場面も用意したWBSを作ってあげたい。
いつも、WBSを作る前に色々な人に何を考えているか聴いてまわります。それでもうまくいかないぐらい、何でも難しい。


いつもですが、言いたいことが感情的すぎてまとまりがないのですが、人は相手の立場も状況も過去も何も分かっているわけではないのです。
相手を思いやっている、相手に優しくしてあげるのではなく、それでも私はできるだけ、相手になったつもりで行動できるよう、これからも切磋琢磨していきたいと、改めて考えました。

HUNTER☓HUNTERで素敵な言葉があります。「その人を知りたければ、その人が何に対して怒りを感じるかを知れ。」

これも同じ事を言いたいのかなぁとか、勝手ながらに解釈したりしています。
posted by Kiruahさん at 09:00| Comment(0) | TrackBack(0) | 日記

2012年04月05日

フレームワークが提供するロギング機能について

特にJavaについてですが、フレームワークが例えあったとしてもパフォーマンス上もしくはコーディング上、さらにはこういうものだという思い込みもあって、各クラスにログ初期化コードをそれぞれ記述しているのではないでしょうか。

例えば、Apache commons-loggingであれば、

public class Sample {

private static final Log LOG = LogFactory.getLog(Sample.class);

/**
* 業務処理
*
* @throws Exception システム例外
*/
public void process() throw Exception {

}
}


これはとても最適なコードのように見えます。初めてSampleクラスが初期化された際に、たった一度だけログ出力用のインスタンスが生成されます。

ですが、これらが各業務プログラムに乱立すると、どのクラスだけをログ出力したいか、簡単かつ詳細に定義できないことが多いのです。
例えばこのクラスが共通クラスであり、APサーバ上の共通libに配置しなければならない場合、このクラスは全てのWebアプリケーションから透過的に扱われることになります。
では、AというWebアプリケーションサーバではこの機能はログ出力したいけれど、BというWebアプリケーションではこの機能はログ出力したくない場合はどうしましょうか?

そもそもそんな需要はない?
性能を測定したいとか、障害が発生したとか、そういうこともないシステムならいいのでしょうが、実際にはそんなことはありません。

ログの制御は、log4jやLogBackを普通に使うのではなく、多少コストがかかったとしてもフレームワークが担い、ログインスタンスを業務処理に引き渡すべきです。
そして、フレームワークはシステムをわざわざ停止させなくとも、あるタイミングから業務処理を呼び出す時に引き渡すロガーの内容を、性能計測用、障害検出用、通常運用用と動的に切り替えられる仕組みを持つべきです。

ある1プロセスで、EAIアプリケーションのように複数のデータ転送を行う場合、例えば複数のサイトにFTPやDB、MQに接続する複雑なシステムの場合、縮退運転でサービスを停止させられない場合、これらにおいて、フレームワークがログ出力を動的に制御する機構を備えていることはとても保守運用者を安心させます。

残念ながら、未だにログ運用まで考慮できたフレームワークは見たことがありません。あくまで作る側の視点での出力です。それは、NTTデータのフレームワークですらできていないと言えることなので、絵に描いた餅という意見と言われても仕方ないのかもしれません。。。

少なくとも私は過去の案件において、フレームワークでログ制御を実施したことがあります。その際は通常何も問題がなければ実は動作しているかどうかも分からないぐらい何もログを出力しないシステムでした。つまり、起動しましたというログしかでません。

でも、実行中フレームワークが呼び出した第一階層の業務プログラムはフレームワークがログ機能を完全に制御し、まだ業務プログラムが扱う値はセッションのように値を保存することを前提とさせたため、障害が発生した場合(つまり例外が発生した場合)、拡張したロガーがどのプログラムで、どこまで処理してどういう異常終了したか、またその時の持ち回り変数の値は何だったかを全てダンプ出力するようにしました。

通常、障害がなければ何も出ませんが、障害があるときだけ、メモリの内容をほぼ吐き出し、ロジック上のスタックトレースや例外メッセージだけでなく、フレームワークがどこまで制御していたかまで出力することを実装したことがあります。

これは有識者が見れば、すぐに原因が分かるレベルでしたが、さすがに運用保守の人間では難しすぎたため、今では反省しています。(とはいえ、運用保守の人間が見るログと解析する人間が見るログ、統合運用監視システムが見るログはそれぞれ別で、それぞれに応じて出力内容を制御したりしましたが。。。あと、出力順にも優先度があったりなど)

そして、フレームワークでログが出せない場合(OutOfMemoryなど)は、APサーバがログ出力します。よって、アプリ用の通知ログ、APサーバのログ、APサーバ自体のプロセス監視、あとは、JMXよりももっと簡単にHTTPでシステムやスレッド(スレッド名を機能名に変更し、問い合わせしやすくしたり)の状態を確認できるようにし、運用監視できるようにしたことがあります(もう2年も前か。。。)。

昨今、正常実行中に無駄にログが出る割に、障害では必要なログが出ないシステムが多いと思います。少しでもそのような状況を改善できないか、模索中です。