iOS の UDID 廃止問題は誰にとっての問題なのか

ごぶさたしております。もはや境界どころかデザインともプログラムとも距離が出てきている今日この頃、すっかりこのブログの存在を忘れていました。

すでにネタの旬は過ぎていますが、Apple の UDID 廃止問題について触れておこうかと。事実関係や最もらしい憶測は、以下の記事を参照。

アップル、iOS端末ユーザーのプライバシー保護で方針変更 - 「iOS 5」ではUDIDの利用を推奨せず

あくまで UIDevice クラスの uniqueIdentifier メソッドが deprecated でマークされただけであって、iOS 5.0 で今すぐ廃止されるという話ではない点に注意。各所予想を取りまとめると、iOS 5.0 では現状どおり使用できる(コンパイル時に Warning が出る)が、iOS 5.1 で廃止されるのではないかという話。ちなみに iOS 4.0 から 4.1 のアップデートまでの期間は3ヶ月ほどだったことを鑑みると、本件 UDID の廃止も年内目処でしょうか。

今日明日の話ではないですが、可及的速やかに対策が必要な話ではあります。

影響範囲

個体識別番号というのは、ガラケー時代からもセキュリティ問題を指摘されてきたポイントであって、今回の Apple による UDID 廃止アナウンスを歓迎する向きもあるようです。しかし大半にとってはネガティブ・インパクトであって、特にアプリ・デベロッパーにとっては痛い仕打ちでした。影響範囲は以下のブログが網羅的です。

なぜiOSでUDIDが必要とされていたのか、メモ

利用ポイントを抜粋させていただくと、

  • アプリケーションのサーバとのセッション保持
  • 行動トラッキングによるターゲティング広告
  • リワード広告

目的は異なるにせよ、デベロッパーにとって容易にユーザを特定するための手段としての UDID というのは、便利な代物です。UDID の万能なところは、ターゲティング広告やリワード広告で使われているように、アプリを横断しても同一ユーザを特定できるところです。その良し悪しは別として、iOS 関連のエコシステムの拡張において、UDIDの果たした役割は小さくなかったと思います。

対応策

各所それぞれと対応策をディスカッションした結果、MACアドレスを使うのだとか、Cookie を絡めてごにょごにょするのだとか、みんな考えていることは同じなのだなーという印象。

自分も ioctl をごにょごにょして MAC アドレスを取得し、UDIDの代わりに使うということを試してみました。そして、これが上手く機能しちゃうわけです。今まで無頓着に UDID を使ってきたのなら、同様に MAC アドレスを使って終わりというスタンスも、正直ありなんじゃないかと思います。

ただ、iOS ビジネス圏で頑張っておられます法人各位においては、『UDIDがダメならMACアドレスだよね』というのは禁断のアプローチであって、話の背景を考えるに、妙なリスクを抱えないように細心の注意を払って、いま一度対応策は検討すべきです。結局 UDID の代わりに UUID を利用するという、Apple が提示している手法に落ち着くでしょう。

じゃあ、アプリ横断のリワード広告とかシングルサインオンとかどうするのよ、という話になります。Apple からしたら『リワードすんじゃねー』とか『GameCenter使えよー』という話なんだと思うので、間違いなくケアはされません。Cookieを組み合わせて頑張るか、scheme のパラメータを使って頑張るとか、諦めるとか、自分で汗かかないといけないんでしょうね。

UDID廃止でワリを食うのは誰か

確実に UDID を使ってきたデベロッパーはワリを食いますが、もう一歩踏み込んで考えてみましょう。

アプリ界隈も最近はプラットフォーム乱立状態ですが、本件は、UDIDの代わりに使えるユーザIDを持っているプラットフォーマーにとっては追い風になりえます。こういう記事もあります。OpenFeint offers its service to replace UDID

広告会社はどうか。そもそも今年4月時点でリワード広告は Apple エコシステムから追い出しを食らっており、すでに業界大手の TapJoy などもビジネスを変えてきています。AdMob などのネットワーク広告への影響も限定的と思われます。一部の属性ターゲティングに対応されているだけで、まだ UDID を効果的に利用したオーディエンス・ターゲティングを武器にできているネットワークはいません。なんだかんだ変わらず。

アナリティクスはどうか。最近、国内でもチラホラ出てきていますが、インストールを計測して分析するような効果測定ツールを提供している企業です。AdMob も提供しているので、広告会社とも重なる領域です。もともと UDID でトラッキングができたのは、アプリからアプリへ遷移するものだけで、すでに業界の興味はブラウザ(Safari)からアプリへの遷移のトラッキングに移っています。そして、ブラウザからアプリへの計測を行う技術が確立されれば、UDIDは不要になります。なので、中長期の影響はありません。

重要なポイントなので繰り返しますが、興味をブラウザに移すとUDIDは不要になります。折しも Facebook のプロジェクト・スパルタンのニュースが増えつつある昨今、UDID問題などから完全フリーなブラウザへの大波が起こる可能性はありえます。

そう考えていくと、実はワリを食うのは Apple なんではないかと。

UDIDが使えないくらいで、アプリを捨ててHTML5にシフトするということは無いとは思いますが、後から振り返って、UDID廃止がターニングポイントだったという話はなくもないと思います。というか、今ユーザはアプリとブラウザを区別せずに使っているという現実は軽視できないです。気付いたら、Apple を中心としていた周辺エコシステムが、丸ごとブラウザ方面へ横シフトしてたりするんでしょうか。怖いです。

結論

UDIDの代わりにMACアドレスを使う前に、各法人担当者のみなさまは韓国の訴訟とか見てから決断をしていただきたく。あと、Android は関係ないから良いやーと言って、IMEI などの端末識別コードを使ってしまうのも問題ありですので、ご注意を。

ちなみに、iOS で言えば脱獄しちゃえばMACアドレスも書き換えられるし、Androidで言えば root でデバイスIDあたりは変えられてしまうわけでして、担当者各位におきましては、不正を見越した仕組みづくりをどうかよろしくお願いします。

SCSK は業界再編のトリガーになるのか

10月1日、SI業界11位の住商情報システム(SCS)と8位のCSKが合併することで、業界4位となるSCSKが誕生することになっている。国内の今後のSIer動向を占う上では、今年最も大きなインパクトになるものではないでしょうか。

前回、「業績回復ストーリーを描けない SIer の悪あがき」というエントリで、震災需要の BCP と国際化としてのグローバル化という、非常に限定的な SIer の悪あがきを取り上げたわけですが、この SCSK というディールがまた不透明感たっぷり。「業界の明日を切り拓くリーディングカンパニーへの飛躍」になるのでしょうか。

経営統合のメリットは出るか

経営統合の理由は、その発表時に「IT業界が右肩上がりに成長しなくなった今、どうやって生き残っていくかを考えた結果だ」との発言が出ています。飽和した国内市場において一社が成長をこなすには、シェア率を向上させるほかありません。SIer にとってそれは顧客企業を増やすということであり、そのための近道は M&A でしょう。

SCSがそのソリューションを、CSKの既存顧客に売れるであれば、短期的な効果も期待できそうです。ただし両社でカニバっている領域も多く、そもそも元々SCSのソリューションが売れてなかったところに、そうそう簡単に入っていけるもんでもないのではないかと。そのため、顧客基盤の拡大という点でのメリットで言えば、一企業としての規模拡大によってプライムを取れる確率が高まるかもしれないところではないでしょうか。もしこれが真なれば、SI業界での合従連衡による再編が加速するでしょう。

経営統合によって規模の経済性が高まることから、ハード関連やクラウドサービスでのコスト効率・事業効率アップによるメリット享受も挙げられるかもしれません。サプライチェーンをいじるのも時間がかかりますし、クラウドなどは経営判断と実効性の間に乖離があって単純にメリットを得られるものでない可能性もあります。

ほかにも国際競争力が高まるという話がありましたが、SCSの希望としてはそうなんでしょうけれども、なぜCSKと経営統合するとグローバル化の推進が加速するのか、私にとっては不明です。海外展開でレバレッジ利くような企業だったっけ。

他業界の事例を引いてみる

国内市場が飽和してシェア率を高めるために経営統合を目指すというパターンは、家電業界や百貨店業界、ゲーム業界などにおいてすでに起こって一巡しています。

家電業界の場合は、サプライヤーに対する価格交渉力が値下げに直結し、売上高に跳ね返るモデルです。交渉は当然規模の大きい企業が有利です。つまり規模の経済性がはたらくため、家電業界は熾烈な M&A が繰り広げられてきました。

一方、百貨店業界はおもむきが異なります。高島屋以外の大手百貨店はいずれも統合を経験していますが、規模の経済性のために経営統合するというより、店舗やブランドを活かして効率的に利益を上げるために合併や提携が組まれているようです。例えば、伊勢丹の最先端のマーケティング力を老舗三越に適用するやり方がそうでしょう。

市場飽和後に合併などによって業界再編が進んでいくのは、他業界にも見られるパターンですが、その業界の事情によって再編の KSF は変わります。私は、SI業界では上記ふたつの観点が共に必要になるのではないかと思います。

SIerのバリュエーション指標は従業員数だという話もありますが、従業員数だけが売上の増減に寄与しているわけではありません。規模が増せば、競合優位性も増すというシンプルな世界ではありません。ましてグローバル化を戦うために、いま各企業に必要なのは、人数でないことは感覚的にも共有できるものではないでしょうか。

なんで SCS は CSK を選んだのか

SCS は過去にも住商グループ内でのIT部門を統合してきており、今回のような経営統合策が取りやすい体質であったということは言えると思いますが、ではなぜ CSK を選んだのでしょうか。

かつて KDD と DDI が合わさって KDDI になったように、名前が近い企業同士は引かれ合う性質でもあるんでしょうか、という話はさておき。

財務的に見ると、不良債権を抱えて自己資本がマイナスにあり財務状況が極めて悪い CSK を吸収合併することで、健全性がかなり高い SCS の財務体質は、大きく悪化します。合併発表後すぐに話題になりましたが、のれん代もハンパないです。(詳しくはみんかぶの記事を参照)

本業でない不動産事業の失敗で会社が傾いており、システム部門は健在とは言え、のれん代を償却しても上回るほどのパワーが CSK にあるでしょうか。単体での企業規模で言えば、確かに SCS よりも CSK の方が上ですが、あまりにリスキー。とても背景の政治経済的理由を知らなければ、理解できないディールだと思います。なぜでしょうか、脳裏に「子供に売春させる親」とか「政略結婚」とかいうキーワードが浮かびます。私、おかしくなってしまいました。

経営統合に関する説明会が延期されたまま開催されていないとか、株主総会が大紛糾するとか、ポジティブなディールに思えないのは、やはり私の頭がおかしくなってしまったからでしょうね。

まとめ

経緯はさておき、SCSKの誕生によって生まれるシナジーはゼロではないでしょう。それが投資対効果を上回ってSCSKの時代が訪れるかどうかは難しい問題だとしても、そのシナジーのアウトプットいかんでは、他 SI 企業が親やユーザーの枠を飛び越えて、合従連衡の動きに入っていく可能性もなきにしもあらずです。個人的には SCSK のディールの重さを横目に見て、領域を絞って業界横断で提携が進むとかいうのが現実ラインな気もしますが。

次の SIer 動向を見極めるために、親会社が住友金属との合併を模索している NSSOL の動きと合わせて、SCSK の経営統合の行方はウォッチしていく必要がありそうです。

業績回復ストーリーを描けない SIer の悪あがき

ここ数年来の SIer の冴えなさっぷりは異常です。

主要各社の決算も出て株主総会も終えたところで、今年も例によって低迷する SI 業界に一言もの申していきたいと思います。昨年は、「SIer が業績悪化しているのに何も変わらない」ということで、思考停止した SIer に言及しました。既存ソリューションをクラウドという新出用語でラッピングしたところで、売上拡大するわけないんですが、各社そろいもそろってクラウド押しだったのが悪印象でした。

直近決算を読み解く

上場大手 SIer 各社の直近の状況を見てみます。アレが入ってないとか、コレが入ってないとかいうのは無粋ですので、そこのところ、ひとつよろしくお願いします。

企業名 売上高 前年比 営業利益 前年比 来期予測 今年比
NTTデータ 1,161,962 101.7% 78,306 95.9% 1,200,000 103.3%
野村総合研究所 326,328 96.4% 38,426 95.9% 330,000 101.1%
伊藤忠テクノソリューションズ 283,068 97.5% 21,316 98.8% 280,000 98.9%
日本ユニシス 252,989 93.3% 6,527 91.9% 255,000 100.8%
CSKホールディングス 140,387 82.8% 7,005 167.7% 142,000 101.1%
住商情報システム 132,840 104.3% 7,076 110.2% 134,000 100.9%
新日鉄ソリューション 159,697 105.0% 11,076 102.7% 160,000 100.2%
富士ソフト 134,745 95.1% 3,793 115.2% 134,000 100.6%
日本システムディベロップメント 33,334 95.4% 3,582 84.3% 36,000 108.0%
SRAホールディングス 33,164 97.4% 2,238 112.1% 33,500 101.0%

2010年度決算に比べると、売上高や営業利益が伸長している企業がポロポロと見えるのが特徴です。トレンドとして、リーマンショック以後の不況については、前年度で底を打った感が出ているように見えます。ただ、FSI や SRA は実は前年度に営業利益率が半減していたりするので、そこから10ポイントちょっと改善したからといって、V字回復ということではありません。むしろ大きく伸ばしているところがなく、減収減益で着地している企業も多いため、依然として SI 業界全体に停滞感が漂っていると見るのが正しいでしょう。

昨年度下半期あたりから、ようやく企業の IT 投資意欲も復活してきたと言われていましたが、そこに来ての東日本大震災。実際に震災そのもので実害を受けたところは無く、各社ともに震災影響は不透明だがそこまで大きくないという見方をしているものの、プロジェクトの延期や案件の縮小などといった具体的な話もすでに聞こえており、各社読み切れていないというのが実情ではないかと推測しています。

ちなみに、増収増益を果たしている SCS と NSSOL については、親会社や楽天などのクライアントに恵まれたということもありますが、製造業での負けに対して、何とかプロジェクト生産性向上施策や販管費抑制で反発した結果であって、やはり市場環境がプラスに向いて利益確保できたということではないようです。この2社とも、11年度に継続して成長できるかは不透明です。NSSOL など、親会社の住友金属との統合案件がプロジェクト化されなかった場合、厳しい決算を迎える可能性があります。

SIer の悪あがき

そのような厳しい環境下にあって、一部すでに成長を諦めてしまっている SIer もいるものの、多くが業績予想として数パーセントの成長を見込んでいます。

データのように「前年度の目標と変わってねーじゃねーか」とか、「そんなのマシで NSD や SRA なんかは前年度の業績予測のだいぶ下を来期予想に置いていて、ついに現実を悟ってしまったか」とかいう話があるものの、今期決算より上向けるために各社尽力していくということは変わりません。

では、どうやって業績を回復させるというのでしょう。

個社別に多少の色の違いはありますが、前年度から継続されるクラウドや IFRS 関連での売上拡大とコスト削減施策に加えて、「BCP」と「グローバル化」が今年度のキーワードとして強調されたように感じられました。

既存のソリューションを、震災を機にリパッケージして需要喚起する SIer 根性には、惚れ惚れします。今回の件はさすがに、各社とも現実問題として考えねばならないことだけに、実際その提案に乗ってしまうところが少なくなかったのでしょう。DR対策や防災需要、グリーンIT、スマートグリッドなど、震災や原発に関連したサービス提供で、震災で低下したIT投資分も挽回可能というのが SIer の見方になっています。

国内 SI 市場の飽和に対して、不採算プロジェクトを減らすことで、なんとか利益を出し続けようという、後ろ向きな努力に比べると、震災に端を発する需要へのサービス供給というのは筋が良いように見えます。個人的には、震災による需要増加でカバーできる投資減少分は限定的だと思っているので、これで伸びるとは思えませんが。まあ、悪あがきだと思います。

業績回復の鍵を握るのは、グローバル化になるでしょう。

SIer はグローバル化するのか?

SIer が自らソリューションを創造して国内の新規マーケットを開拓できない以上、彼らが海外指向を持つのは当然の流れです。国内市場の飽和と、親会社やクライアント企業の海外進出という2つの理由から、国外で悪あがきをできないか模索するわけです。

しかしながら、現状で私が見ている限り SIer のグローバル化というのは、次の2点を指しているようです。

・親会社の海外進出に係るシステム構築
・クライアント日系企業の現地子会社へのシステム適応

グローバル化というと新興国の現地企業向けのソリューションを、ローカライズしながら提供したりすることかと思いきや、そういうのはインドや中国とのコスト競争に適わないので、既存のクライアントソースを最大限に活躍していくということをもって、グローバル化と言っているようです。アホか。取引は国際化しているけれども、それはグローバル化とは言わないでしょう。

これまで国内で蓄積してきた高度なノウハウを、新興国マーケットに適するようにアジャストさせて、ひとつひとつソリューションを組み上げていけるかどうか。新興国とのコスト競争に巻き込まれず、真に日本の SIer がグローバル化するためには、このような視点が欠かせないでしょう。

結局、言いたかったこと

SIer がソリューション創造企業として本質的に変化しない限り、国内だろうが海外だろうが、長期的な業績回復を遂げることは難しいのではないでしょうか。自社の強みを活かしつつ、各国・各地域に横たわる課題を解決することのできるラインを構築しなければならないのではないでしょうか。

事業継続性や単なる国際化としてのグローバル化というのは、そのような視点を持てず長期の業績回復ストーリーを描けない SIer の悪あがきです。それで業績予想を上回れるかというと、私は懐疑的です。

そんなわけで、合併しただけで国際競争力アップとかおめでたいトーク満載で話題の SCSK については、また次回。SCSK の合併の意味合いと、今後このような合従連衡の流れはムーブメントになるのか、きちんと整理をして見たいと思います。

iPhoneアプリ開発時にハマる色んなエラー

iPhoneアプリを開発して AppStore に上げるたびに、その過程で様々なエラーが出てハマるので解決策をメモしておきます。

Couldn't register xxxxx.debug with the bootstrap server. Error: unknown error code. This generally means that another instance of this process was already running or is hung in the debugger.Program received signal: "SIGABRT".

実機でテストしようと思ったら、main.m でこんなエラーを吐いてコケる。原因不明ですが、電源 OFF-ON で実機を再起動したらエラーが出なくなりました。なんなんでしょうか。

Code Sign error: The default keychain doesn't have an identity matching the profile 'xxxxx profile' and identity 'iPhone Developer'

AppStore 申請時にアーカイブのバリデーションを行ったら、このエラーが発生。きちんと証明書もインストールしているし、配布用のプロビジョニングファイルもオーガナイザにインストールしています。

これは読んで字のごとく、ビルド設定のコード書名IDの設定が誤っていました。Debug は iPhone Developer を、Release は iPhone Distribution を指定しないとダメですね。アーカイブ作成時点ではビルドが成功するので、分かりにくいです。

com.apple.transporter.util.StreamUtil.readBytes(Ljava/io/InputStream;)[B

アーカイブしたファイルを、オーガナイザから AppStore に転送しようと思ったら、こんなエラーが出ました。意味が分かりません。どうも Xcode4 のバグが原因のようです。Xcode3 にダウングレードして、そのオーガナイザから転送したら上手くいきました。

ちなみに、Xcode3 と Xcode4 は共存可能です。私は、/Xcode3 というディレクトリを作ってそこにインストールしました。Xcode4 が枯れてきたらそちらに移るつもりなので、一時的にこのような構成にしました。

Objective-C コードのビルド時にエラーが起こるものは、プログラムのバグ、もしくはビルド設定の誤りが原因なので、解決のアプローチが簡単です。Google 先生に聞いても、多くのケースで答えが返ってきます。それ以外の、上記のようなエラーは、なかなか答えが見当たらないのが厄介です。

今後、他にもハマったら更新します。

UIWebView で history.back が使えないケース

このたびの東北太平洋沖地震で被災されているみなさん、ご家族、ご友人のみなさんに、心からお見舞い申し上げます。

非常に月並みな言葉ではありますが、私も、被災地で生まれ育った関係者のひとりとして、今はもう感情に訴えるべきでないという思いがあるので、このくらいにさせてください。ただ、ひとりのエンジニアとして、ひとりのビジネスマンとして、ひとりの日本人として、被災地の社会・経済の復興に役立つような、実利ある行動を取っていきたいと思っています。

さて。

『実利ある行動』とか銘打ったあとにやりづらいですが、小さい話をします。iPhone の UIWebView で表示したサイトで、 javascript:history.back() が動かないケースがあってハマりました。

結論から言うと、UIWebView クラスに loadData:MIMEType:textEncodingName:baseURL: や loadHTMLString:baseURL: でロードした HTML ページは、javascript の履歴スタックに載らないようです。

これらのメソッドでロードしたページから次のページに遷移したあと、そこで history.back() を動かしても、うんともすんとも言いません。UIWebView には、canGoBack というブラウザの戻る機能が使えるかどうかを判別するプロパティや、goBack というブラウザの戻る機能そのものとなるメソッドもあるのですが、これらも効きませんでした。とにかく、UIWebView が直接 HTTP 経由で受信したデータ以外は、履歴をたどれません。

細かい通信制御がしたかったため、NSURLConnection でデータを取得して、それを UIWebView の loadData:MIMEType:textEncodingName:baseURL: に食わせるようにしていたのですが、この設計だと history.back() が使えないわけです。分かるか、そんなもん。

ということで、UIWebView で history.back() を使いたい場合は、loadRequest: メソッドで HTML を読み出しましょう。細かい制御は、UIWebViewDelegate でごにょりましょう。

1時間以上ハマりました。相変わらず Cocoa に慣れない。

View+Navigation based iOS アプリの作り方

Xcodeで iOS アプリの新規プロジェクトを作成する際、Navigation-based ApplicationやView-based Applicationといったテンプレートを選択することができますが、その両方の機能性を持たせたいということがあると思います。というか、さっきそういう境遇に陥って困ったので、メモです。

今回は、アプリのトップ画面は View-based Application だけれども、そこからメニューを選んだときには NavigationController のスタックに積んで、Navigation Bar 付きのページに遷移していくというもの。うむ、説明が難しい。平たく言うと、トップ画面は Navigation Bar がなくて、2階層目の画面は Navigation Bar があってトップに戻れる感じです。

さっそく作ります。ここでは、Sampleというアプリを考えます。

まず、View-based Application テンプレートを使ってプロジェクトを作成します。これに NavigationController の機能を追加していきます。

はじめに SampleAppDelegate.h を開いて、UINavigationController を追加します。1行追加するだけ。

@interface SampleAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    UINavigationController *navigationController;
    SampleViewController *viewController;
}

次に SampleAppDelegate.m を開いて、application:didFinishLaunchingWithOptions: と dealloc を以下のように修正します。NavigationController の rootViewController に、デフォルトの UIViewController をセットして、その view を window のサブビューに追加して表示させるようにしているのがポイントでしょうか。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
	navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
    
    // Add the view controller's view to the window and display.
    [window addSubview:navigationController.view];
    [window makeKeyAndVisible];
    
return YES; }
- (void)dealloc { [viewController release]; [navigationController release]; [window release]; [super dealloc]; }

続いて、トップ画面では NavigationBar を隠し、2階層目以降は表示するようにします。ここでは next: が、2階層目を開く処理として、ボタンか何かに紐付けた IBAction 的なメソッドということにします。

SampleViewController.m を開いて、以下のような感じにします。

#import "SampleViewController.h"
#import "NextViewController.h"
    
@implementation SampleViewController
    
- (void)viewWillAppear:(BOOL)animated {
	self.navigationController.navigationBarHidden = YES;
}
    
- (void)hoge:(id)sender {
	NextViewController *next = [[NextViewController alloc] init];
	[self.navigationController pushViewController:next animated:YES];
 	[next release];
	self.navigationController.navigationBarHidden = NO;
}

// 以下略

ここでのポイントは、 navigationBarHidden に BOOL オブジェクトをセットするタイミングです。pushViewController:animated: する前に NavigationBar を表示しようとすると、画面遷移前ににょきっと NavigationBar が現れてくるので、あんまり心地良くありません。いろいろ試してみていただければと思いますが、コードを書く位置で、目に見える違いがあるのが GUI 開発の面白いところですね。

これで目的達成です。おつかれさまでした。大したことないですが、そのうち github にでも上げときます。

UIModalTransitionStyleCoverVertical のようなアニメーション

UIViewController でモーダルビューを表示するメソッド presentModalViewController:animated: の画面遷移アニメーションのスタイルは、デフォルトだと画面下からビューがせせり出てくる UIModalTransitionStyleCoverVertical になっています。結構気持ち良いので、これと同じアニメーションを、自分の UIView でも実装してみるテスト。というか、大人の事情により途中まで書いていてボツになったので、もったいなので、ここで書き上げてみます。

UIViewController内で UIView をモーダルで表示させたいメソッド内で、次のようなアニメーションを組めばOKのはず。

UIView *myView = [[UIView alloc] init];
/*
  View 生成する処理むにゃむにゃ
 */

// 初期位置を決める CGPoint p; if (self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) { p = CGPointMake(0.0, CGRectGetHeight([[UIScreen mainScreen] applicationFrame])); } else { p = CGPointMake(0.0, CGRectGetWidth([[UIScreen mainScreen] applicationFrame])); } CGRect r = myView.frame; r.origin = p; [myView setFrame:r];
// Animation CGContextRef context = UIGraphicsGetCurrentContext(); [UIView beginAnimations:nil context:context]; [UIView setAnimationDuration:0.5]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; CGRect newRect = myView.frame; newRect.origin = CGPointMake(0, 0); [myView setFrame:newRect]; [UIView commitAnimations];
[self.view addSubview:myView]; [myView release];

ちなみに、UIModalTransitionStyleCoverVertical の animationCurve は UIViewAnimationCurveLinear かもしれません。個人的には EaseInOut が一番気持ちいいのでそれにしているだけです。

Perl で加重ラウンドロビン

あけましておめでとうございます。

さて、ラウンドロビンというのは、主に負荷分散のため使われる手法で、複数のリソースに対して順番に処理を割り当てるためのアルゴリズムです。さらに、各リソースの処理性能であるとか、状況に応じて割り当てる確率を変えるために、それぞれに重み付けを行うケースがあります。その際に使われるのが、加重ラウンドロビンというアルゴリズムです。

新年早々アプリケーション層でそういうことをやりたい機会があったので、Perl でラウンドロビンを実装しました。いまいち洗練されてないんですが、メモがてら。

まずは、ラウンドロビン。配列で与えられたリソースのから、利用可能なものを順に引いてきます。

#!/usr/bin/perl
my @DATA = ( { name => 'A', available => 1 }, { name => 'B', available => 1 }, { name => 'C', available => 1 }, { name => 'D', available => 0 }, { name => 'E', available => 1 }, );
our $i = -1; # last time index for (1..10) { my $data = select_data(); if (defined $data) { print sprintf("%d\t%s\n", $_, $data->{name}); } else { print sprintf("%d\tAll datas are unavailable\n", $_); } }
sub select_data {
my $j = $i; do { $j = ($j + 1) % scalar(@DATA); if (${DATA[$j]}->{available}) { $i = $j; return ${DATA[$j]}; } } while ($j != $i); return undef; }

実行結果。

1       A
2       B
3       C
4       E
5       A
6       B
7       C
8       E
9       A
10      B

続いて、加重ラウンドロビン。最大公約数や重みの最大値を毎回計算しているのは、利用可能なリソースが動的に変化することを想定していたためです。実際には、最初に計算して memcached に載せたあとは、リソース状況に変化があった際にメモリを上書きするようにしました。

#!/usr/bin/perl
use Math::BigInt qw(bgcd); use List::Util qw(max);
my @DATA = ( { name => 'A', available => 1, weight => 2 }, { name => 'B', available => 1, weight => 3 }, { name => 'C', available => 1, weight => 4 }, { name => 'D', available => 0, weight => 1 }, { name => 'E', available => 1, weight => 1 }, );
our $i = -1; # last time index our $cw = 0; # current weight
for (1..10) { my $data = select_data(); if (defined $data) { print sprintf("%d\t%s\n", $_, $data->{name}); } else { print sprintf("%d\tAll datas are unavailable\n", $_); } }
sub select_data { my @list = grep { $_->{available} } @DATA; my $gcd = bgcd(map { $_->{weight} } @list); my $max = max(map { $_->{weight} } @list);
while (1) { $i = ($i + 1) % scalar(@list); if ($i == 0) { $cw = $cw - $gcd; if ($cw <= 0) { $cw = $max; return undef if ($cw == 0); } } if ($list[$i]->{weight} >= $cw) { return $list[$i]; } } }

実行結果。

1       C
2       B
3       C
4       A
5       B
6       C
7       A
8       B
9       C
10      E

ラウンドロビンは、単純に順番に割当をおこなうアルゴリズムなので、結果には規則性があります。なので、『くじ』のような当たるプログラムには向きません。

複数のなかからひとつを選ぶ場合、バカのひとつ覚えのように、なにかとランダム関数を使ってしまうのですが、目的に応じて戦略は変えるべき、というのを改めて感じたのでした。(ランダムが実はランダムじゃないという話も含めて)

RFPに記載する内容

「RFPって何を書いたら良いの?」という相談をいまだに受けるので、忘れないうちに、ざっとまとめておきます。以外とネットでも、実践的な説明はないらしい。本当だろうか。

そもそも RFP というのは Request For Proposal の略で、日本語にすると「提案依頼書」というらしいんだけれども、名前がバズワードっぽいのがいかんと思うわけです。RFPだとかITベンダーだとか横文字が並ぶと、みんな急に身構えて、何を書いて良いか分からなくなってしまうらしいんですが、普通に社内で稟議通すときと同じようにオリエンすれば十分だったりしますし、最もミニマムなものだと子供の「おつかいリスト」レベルで事足りたりします。

以下に記載すると良いかもしれない項目を箇条書きにしますが、すべてを網羅しなければいけないものではないと、私は考えています。むしろすべて書かないでください。制約条件が増えれば増えるほど、ベンダーからの提案の幅は狭まってしまい、「コンペしたけど、どこも代わり映えしないんだけど、結局どこが良いんですかね?」みたいな話になるし、そんな状態になってから相談されても困るんですよね、という。

RFPに記載すると良さそうな項目

このなかでマストなものと、そうでないものを切り分けて提示することが肝要。マストなものが複数ある場合、そのなかで優先順位を付けてあげるべし。

  • 目的・背景
  • 対象の業務と仕事の規模
  • 必要な機能
  • システム条件
  • 利用環境
  • サービスレベル(SLA)
  • 検収条件
  • 調達先の制約
  • 予算・支払条件
  • 契約・法務関連
  • 納期・スケジュール
  • 運用・保守要件

RFPというのは、発注側にとってはベンダーの提案をいかに引き出すかがかかっているドキュメントで、ベンダー側にとっては発注側が真に求めている価値を図り、提案内容を研ぎすますための材料になるドキュメントであるべきだと思っています。

という点から、個人的には目的と背景が一番重要だと思っていて、なるべくここを丁寧に仕上げて欲しいと思っています。提案の「向こう側」をすり合わせることで、クォリティが変わります。経験則として。

余談ですが、私はまともなRFPをもらったことがありません。やりたいことの方向性だけは決まっていて、あとは予算と納期がかろうじて設定されているのみ。それがA4用紙に5行くらい、申し訳なさそうに書いてある紙だけを渡されて、そこからスタートするみたいな話ばっかりでした。私が中小企業向けのソリューションばっかり担当だったのもあると思いますが。仕方ないので、上記の項目をヒアリングして補っていました。つまり、上記リストは、最初に先方に出してもらっていたらラクできたなーという視点で考えたものです。

上記の RFP に記載すべき目次リストは、システム開発におけるアイテムではあるものの、少しカスタマイズすれば、他用途にもそのまま使えると思います。たとえば、フワッとしがちな、デザイン系の発注に効力を発揮したりします。

ツッコミ大歓迎です。抜け漏れ、教えてください。

iPhone でファイルの追記と上書き

Perl でいうところの ">" や ">>" っぽくファイルの入出力をする方法はないかといじくり回した結果、正攻法か分かりませんが、とりあえず目的は達成できたのでメモ。

既存ファイルへの追記

NSString *path = @"hoge.txt";
NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:path]; [fh seekToEndOfFile]; for (int i = 0; i < 10; i++) { NSString *str = [NSString stringWithFormat:@"test%d\n", i]; NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding]; [fh writeData:data]; } [fh closeFile];

上書き

NSString *path = @"hoge.txt";
NSFileManager *manager = [NSFileManager defaultManager]; if ([manager fileExistsAtPath:path]){ NSError *error = nil; [manager removeItemAtPath:path error:&error]; } [manager createFileAtPath:path contents:[NSData data] attributes:nil];
NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:path]; for (int i = 0; i < 10; i++) { NSString *str = [NSString stringWithFormat:@"test%d\n", i]; NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding]; [fh writeData:data]; } [fh closeFile];

別のより良い方法を見つけたら追記します。

HTTPステータスを判定して UIWebView を生成する

UIWebView はかんたんに HTTP 通信して Web ページを表示することができて便利なのだけれども、HTTP ステータスコードを見ていないため、iPhone 上に "500 Internal Server Error" とか出てくるわけです。これはカッコ悪い。

例えば、次のように UIWebView の loadRequest: を使った場合、通信エラー処理は webView:didFailLoadWithError: に委譲されるものの、HTTPサーバのエラー処理は委譲されず、処理するタイミングがありません。

- (void)viewDidLoad {
    UIWebView *wv = [[UIWebView alloc] initWithFrame: view.frame];
    wv.delegate = self;
    wv.scalesPageToFit = NO;
    [self.view addSubview:wv];
    
    [wv loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.deftrash.com/"]]];
    [wv release];
    
    [super viewDidLoad];
}

#pragma mark UIWebViewDelegate - (void)webView:(UIWebView *)wv didFailLoadWithError:(NSError *)error { NSLog(@"UIWebView::didFailLoadWithError"); }

仕方ないので、 NSURLConnection の delegate で制御します。 _conn と _data はそれぞれ、NSURLConnection と NSMutableData のインスタンス変数です。

- (void)viewDidLoad {
    NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.deftrash.com/"]];
    _conn = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
    if (_conn) {
        _data = [[NSMutableData data] retain];
    }
}

-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSInteger status = [(NSHTTPURLResponse *)response statusCode]; if (status != 200) { [_conn cancel]; // 本当はちゃんと NSError オブジェクトを作って渡すべき [self connection:connection didFailWithError:nil]; } else { [_data setLength:0]; } } -(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data { [_data appendData:data]; } -(void) connection:(NSURLConnection *) connection didFailWithError:(NSError *) error { [_conn release]; _conn = nil; [_data release]; } -(void) connectionDidFinishLoading:(NSURLConnection *) connection { UIWebView *wv = [[UIWebView alloc] initWithFrame: self.view]; wv.scalesPageToFit = NO; [wv loadData:_data MIMEType:@"text/html" textEncodingName:nil baseURL:nil]; [_conn release]; _conn = nil; [_data release]; }

NSURLConnection の initWithRequest:delegate: を使うと TCP 通信のプロセスを委譲できるので、これを利用しています。なぜか delegate のプロトコルはありません。connection:didReceiveResponse: で最初のレスポンスを受けた段階で、ステータス判定して、正常(200) でなければ通信をキャンセルしています。 本来は switch 構文で、もっと細かくステータスごとの処理をするべきでしょう。せめて、400 や 500 番台だったらエラーというぐらいにはすべきでしょうね。

このあたりのコントロールは、実際にやってみると非常に面倒です。こうした非同期通信を複数スレッド走らせる場合は、きちんとキューイングしたり、インスタンスの使い回しをしないようにしたり、気にかけるポイントが多かったです。いやあ、途中でメモリの開放漏れなどで、10回くらいクラッシュしました。

こうして考えると ASIHTTPRequest は超絶便利です。ちょっとした HTTP 通信をするにはライブラリとして大きくなりすぎているのが気になっているものの、BSD ライセンスですし、選択肢として取れるのであれば積極的に使いたいものですね。

おつかれさまでした。

ローカルの html を UIWebView で表示する

iPhone アプリ上で使用許諾文書のような長文を表示させたいとき、View にベタ書きという選択はありませんが、かと言ってわざわざ Web と通信するまでもありません。ということで、プロジェクトに配置しておいた静的 html を読んで表示してあげるテスト。

Xcode を開いて Resources フォルダに、 html ファイルを置いておきます。今回は policy.html というのを置いてみました。あとは、それを表示する ViewController で以下のようにするだけでできました。

- (void)viewDidLoad {
    CGRect frame = [[UIScreen mainScreen] applicationFrame];
    CGRect rect = CGRectMake(0,0,frame.size.width, frame.size.height);
    UIWebView *wv = [[UIWebView alloc] initWithFrame:rect];
    wv.scalesPageToFit = YES;
    [self.view addSubview:wv];
	
    NSString *path = [[NSBundle mainBundle] pathForResource:@"policy" ofType:@"html"];
    [wv loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]];
    [wv release];
    
    [super viewDidLoad];
}

よくよく考えてみれば、これで html5 + javascript を読み込んでしまえば、すぐに簡易 iPhone アプリが作れるんですね。その割には、Xcode の新規プロジェクトのなかには "HTML-based Application" という選択肢がないのが、なんとも考えさせられます。

なぜAdobeは映像系ソフトだけクロスアップグレード可にしたか

今回は、前回の記事「Adobe 製品を Windows と Mac でスイッチする方法」を違う角度から見てみます。

今回の CS5 へのアップグレードポリシーを見ていくと、Premiere をはじめとする映像系ソフトの扱いが特別であることが分かります。Creative Suite 5 アップグレードに関する注意点から引用すると、「Premiere Pro、After Effects、Soundbooth、Production Premium へのアップグレードに関しましては、異なるプラットフォーム (異なる言語は不可) へのアップグレードが可能です。」とあったり、「Adobe Premiere / Premiere Pro については、すべてのバージョンよりアップグレードいただけます。」とあります。

Adobe のマーケティング戦略

これらの特別ルールの目的は、Premiere ユーザの囲い込みを続けることだと推察できます。さらに、新規 Premiere ユーザの獲得も視野に入った施策でしょう。

Adobe はクリエイティブ系ソフトウェアでは市場では寡占的地位を築いてきており、2005 年の Macromedia 買収合併後はさらにその傾向が進み、グラフィック系については揺るぎない絶対的な地位にあるわけです。強力なライバル不在のため、のびのびとした価格設定と、平日の営業時間以外は顧客の相手をしないという強気の姿勢を崩しません。これがリーダー企業の競争戦略なのだと言われればそうなのかもしれませんが、ムカつきますね。

しかし、こと映像系に限ってはそうではありません。かつて Premiere は Final Cut Pro に敗北して Mac 市場から撤退していますし、映像編集系ソフトとしてのマインドシェアは低いです。プロユースでも需要はいまいちで、After Effects を除いて、Adobe の映像ソフトは微妙な立ち位置でしょう。

実際にシェアはどんなもんか

シェアが分かる資料が見つからなかったので、BCNランキングを参照してみます。いずれも 2010年6月のカテゴリ別ランキングです。

まずは、対照としてグラフィック系ソフトの販売ランキング。

順位販売元ソフトウェア
1セルシスIllustStudio パッケージ版
2セルシスComicStudioPro 4.0
3アドビAdobe Illustrator CS5 日本語版 Windows版 学生・教職員個人版
4アドビAdobe Illustrator CS5 日本語版 Windows版
5メガソフト3Dマイホームデザイナー LS3
6メガソフト3Dマイホームデザイナー LS3 間取りがわかる!書籍付
7アドビAdobe Creative Suite 5J Design Standard Mac 学生・教職員個人版
8アドビAdobe Illustrator CS5 日本語版 アップグレード版 Windows版
9アドビAdobe Illustrator CS5 日本語版 Macintosh版
10アドビAdobe Illustrator CS4 日本語版 Windows版

続いて、これまた対照として画像処理系ソフトのランキング。

順位販売元ソフトウェア
1アドビAdobe Photoshop Elements 8.0 日本語版 Windows版
2アドビAdobe Photoshop CS5 日本語版 アップグレード版 Windows版
3エプソンデジカメde!!ムービーシアター3
4アドビAdobe Photoshop Lightroom 3.0J アップグレード版 Win/Mac版
5アドビAdobe Photoshop Elements 8.0 日本語版 乗換え/UPG版 Windows版
6アドビAdobe Photoshop CS5 日本語版 アップグレード版 Macintosh版
7ジャストシステム感動かんたん!フォトムービー2 通常版
8アドビAdobe Photoshop CS5 Extended 日本語版 Win 学生・教職員個人版
9アドビAdobe Photoshop CS5 日本語版 Windows版
10アドビAdobe Photoshop Elements 8.0 日本語版 Win版 学生・教職員個人版

CS5 発表直後とは言え、両分野ともに Adobe のシェアの大きさがうかがえるランキング結果です。

一方、映像編集系ソフトではどうかというと、こんな感じです。

順位販売元ソフトウェア
1サイバーリンクPowerDirector8 Ultra 特別優待版
2コーレルVideoStudio Pro X3 特別優待版
3コーレルVideoStudio Pro X3
4コーレルVideoStudio Pro X3 アカデミック版
5コーレルVideoStudio Ultimate X3 通常版
6コーレルVideoStudio Pro X3 アップグレード版
7ペガシスTMPGEnc Authoring Works 4
8コーレルVideoStudio Ultimate X3 特別優待/アップグレード版
9アドビAdobe Premiere Elements 8.0 日本語版 Windows版
10コーレルVideoStudio Ultimate X3 アカデミック版

9位にギリギリ入っているといった感じです。CS5 発表直後だというのに、それらはトップ10には入ってきていません。まあ、そんなもんですね。


まとめ

Adobe としては、Premiere を再度 Mac 市場に投入したし、Win から Mac への乗り換えユーザが増えているという事実から、この市場のみチャレンジャーとしての戦略に切り替えたのだと思います。こうした背景を考えると、仮にシェア奪回が実現できた場合、この戦略は捨てられる可能性が高そうです。つまり、Premiere はじめ Adobe の映像系ソフトがシェアを伸ばしたとき、またクロスアップデートは認められなくなり、アップグレード対象製品も他製品と同様の縛りにしてしまうでしょう。製品ごとにポリシーが違うのは、内部の管理コストもかかるわけで、変えたがっているに違いないでしょう、と。

しかしながら上で見たようなシェア具合であり、こんな作戦で効果が上がるのかは不透明というか、ぶっちゃけシェアは落とさないけれども伸ばしもできずにハマるんじゃないかと推測しています。その場合は、再度市場から撤退するとか、クローズドでやっていくという流れに行き着くことも考えられるため、やはり今のアップグレードポリシーのままでいることは無いでしょう。

そんなわけで、映像系ソフトのクロスアップデートを考えている方は、今のうちですよ! Adobe 先生の気が変わらないうちに、ぜひ。

続きを読む "なぜAdobeは映像系ソフトだけクロスアップグレード可にしたか"

Adobe 製品を Windows と Mac でスイッチする方法

5月末に発売された Adobe CS5 に遅ればせながらアップグレードしました。今回のポイントは、Windows 版から Mac 版にクロスアップグレード(異なるOS間でのアップグレード)を実現したことです。

数年前から Mac の環境は手元にあるものの、なかなか Windows から移行することができなかった。理由は、高額な Adobe 製品群がすべて Windows 版であり、それらを Mac 版に交換することができなかったから。Adobe に救済を求めて聞いてみたことがあったけれども、「Mac版を新規に購入してください」というけんもほろろな回答しか得られず、結局 Windows 環境でクリエイティブを続けてきました。

こういう同士も少なくないと思いますが、朗報ですよ!

あまり知られていませんが、なんと CS5 ではクロスアップグレードができます。Adobe 製品を Windows 版から Mac 版に切り替えることができます。もちろん逆に Mac 版から Windows 版へのスイッチということもできます。

Adobe 製品は以前からアップグレードポリシーとして、クロスアップグレードを認めてきませんでした。これは CS5 でも同様なのですが、例外的に Premiere Pro、After Effects、Soundbooth、Production Premium へのアップグレードは、異なるプラットフォーム (異なる言語は不可) へのアップグレードが可能 になっています。今回はこの特例を利用するわけです。

このあたりの情報は Web 上に少ないので、一応、自分の例を書いておきますと、CS3 Design Premium Windows 版から、CS5 Production Premium Mac 版へのクロスアップグレードにしました。CS5 のインストール時に、現在利用中のプロダクトのシリアルを入力しろと求められますが、ちゃんと CS3 Windows 版のシリアルでパスできました。

映像系パッケージ群に限られる方法ではありますが、自分と同じようにグラフィックと映像という守備範囲の人ならドンピシャで使えます。

ほかに方法ないの?

あります。

カスタマーサービスに電話すると、何とかしてくれるかもしれないらしいです。上で、以前相談した際には新規購入を薦められた話を書きましたが、ちょっと態度は軟化しているのかもしれません。

ただ、先のパッケージを使ったクロスアップグレードと異なるのは、以前のシリアルを破棄する代わりに新しいプラットフォームでのライセンスを得ることができる点です。つまり、シリアルが破棄されると、やっぱ前のOSに戻りたい、というときの可逆性がない。ここはグレーゾーンなので棒読みしますが、普通にクロスアップグレードすると、Mac では CS5 が使えるし、Windows では以前のパッケージが使えるという状態になりますね。あら、ナニコレ不思議。

もっと、ほかに方法ないの?

あらためて CS5 のアップグレード対象製品を見てみると、そのなかに「Macromedia Studio 8」という文字があるのに気が付きました。私の記憶が確かならば、Studio 8 は Mac と Windows のハイブリッド版として販売されていた気がします。

つまり、Studio 8 さえ手元にあれば、好きな CS5 製品の Windows 版もしくは Mac 版にアップグレードできるということなんじゃないでしょうか。これ、すなわち最強。原理的にはできますよね、普通に。

結論、Macromedia 最高です。溜池山王時代が懐かしく恋しいです。


続きを読む "Adobe 製品を Windows と Mac でスイッチする方法"

SIer が業績悪化しているのに何も変わらない

SIer のなかの人は思考が止まってしまっているんでしょうか。

SIer 各社の業績が軒並み悪化しているにも関わらず、現場では新しい提案があるわけでもなく、それならどうやって業績回復のストーリーを実現するつもりなのかと思わされるような話がチラホラ。あとは、現状理解に乏しく需給関係が崩れつつあるにも関わらず、当然の顔で値上げ交渉をしかけてきたりする。バカなのかな、と思うわけです。

まずは状況整理

上場大手 SIer 各社の直近の状況を見てみます。

企業名 売上高 前年比 営業利益 前年比 来期予測 今年比
NTTデータ 1,142,940 100.3% 81,689 82.9% 1,200,000 105.0%
野村総合研究所 338,629 99.2% 40,077 80.6% 350,000 103.4%
伊藤忠テクノソリューションズ 290,391 94.5% 21,569 99.5% 300,000 103.3%
日本ユニシス 271,084 87.4% 7,105 44.7% 280,000 103.3%
CSKホールディングス 169,518 82.3% 4,176 - 160,000 94.4%
新日鉄ソリューション 152,158 94.2% 10,790 93.8% 156,000 102.5%
富士ソフト 141,682 85.8% 3,293 45.0% 142,000 100.2%
住商情報システム 127,317 94.8% 6,423 71.1% 135,000 106.0%
日本システムディベロップメント 34,933 84.0% 4,248 56.5% 37,400 107.1%
SRAホールディングス 34,053 81.5% 1,997 52.3% 35,500 104.2%

ほぼ減収減益で、営業利益については、富士ソフトを筆頭に半減しているところもあるという悲惨な状態。NTTデータだけは増収減益になっていますが、前年度はゆうちょなど銀行系の大型受注があったので、それでも売上高が横ばいだったということは、他社と傾向が異なるものではありません。

各社がそろって減収の要因に挙げているのが、企業のIT投資抑制にともなう受注減少。加えて、証券業向けのサービスを展開しているところは、業界自体の低迷でダメージが大きかった模様。流通系は堅調だったみたいですね。

インド・中国へのオフショアリングの更なる推進や、経費や外部委託費の圧縮など、ITゼネコンの多重構造を考えるに、涙なしには語れなさそうなコスト削減を行っているのも、各社共通です。敢えてここに関係ない話題を挟みますが、2009年度の全国企業倒産状況にあるとおり、情報通信業の倒産が6.7%増というのはリアルです。さて、そうしたコスト削減活動があるなかで、なお減益となっているのは、受注減少分がコスト削減効果を上回ったということ。いかに市場環境が悪いかが分かります。

SIer は変わらないのか

こうした市況下にあるものの、ほとんどの SIer が今期は 5% 前後の成長を見込んでいるのは、興味深いです。市況が回復し、クラウド関連事業が伸びるという見方なわけです。

確かに、大企業を中心にIT投資は底を打ったという見方もあるし、足元を見るとコスト削減の旗印のもとにプライベート・クラウドを推進し、導入した企業が増えてきているという事実があります。冷えきったIT投資意欲を、バズワードの独自解釈をもとに構築したソリューションで刺激して需要を生み出そうというあたりは、「いつもの感じ」で素晴らしい。この前まで Saas で大騒ぎしていたものを、一気にクラウドという上位概念で包み込んで一掃してしまう手法には惚れ惚れするわけです。そうしたなか、NTTデータがクラウドという単語より BizXaas という固有名詞で押しているのが、なんともクールです。

クラウドを標榜しつつ、SIer 根性はプラットフォーマーは目指さないし目指せない。その妥協点として着地したプライベート・クラウドでは、これまでの業務知識やノウハウは活きるかもしれないが、未来を作るわけではないと思うわけです。コスト削減効果はあるのかもしれませんが、例によってパッケージングを変えただけに過ぎないとも見えるわけです。

本質的な変化を取れないのは、SIer というポジショニングの宿命なんでしょうか。ソリューションのリパッケージングで延命していくやり方では、二番底は超えられないんじゃないかと思います。

稼働率は上げたいけど供給者目線

利益率アップは至上命題とばかり、SIer の外部委託費はさらに大幅削減とかいう話になっています。内製化傾向にあるユーザ企業にやられた仕打ちを、右から左に受けながすカツヤマー流。数年前の偽装請負禁止に次いで、二次請け・三次請けの会社からは、青息吐息が聞こえてきます。

大手 SIer にとっては、コスト削減効果を甘受しながら、受注減で低下している社内のエンジニア稼働率を上げられる施策ではあるものの、空洞化してしまったあとの社内で仕事を回せといっても回せないという、ウソかホントか区別つかない話が聞こえてくるなど、現場の混乱もなかなか。そこで安価なオフショアという選択肢になるのだろうけれども、ようやく落ち着いてきたと言われるオフショア開発も、最終的に下請け会社に回っていって、そこのSEがほとんどを作り直すなんていう、これまたウソかホントか区別つかない話も聞こえてきます。いろいろ心配です。

個人的に衝撃だったのは、そういう環境化にあって供給過剰で稼働率の下がっているエンジニアなのに、なぜか単価を上げようとかいう話が横行しているという話です。これは一次だけでなく二次請けやっているあたりの中堅どころでもそう。需給関係とか経済の仕組みは無視なんでしょうか。システム系は価格弾力性があまりないとは思いますが。

逆に三次・四次くらいをずっとやってきて、もはや売上が地べたを這っているソフトハウスさんなんかだと、びっくりするぐらい低単価で提案してきて、逆の意味で恐いなんて話も聞きます。それは赤字にならなければ良い、という覚悟の現れらしいですが、ぜひ各 SIer にもそういった姿勢を学んでいただきたく。

結局、言いたかったこと

SIer は自分のおかれた立場をちゃんと理解した上で、本質的な戦略を考えて実行して欲しいなと思うわけです。現状認識が甘いまま、サイズオーバーな提案をしようものなら、足元すくわれちゃうと思うんですよね。

プライベート・クラウドや仮想化によるコスト削減ソリューションは売れると思いますが、それはこれまで売れていたところには売れるし、売れていなかったところには売れないという話のような気がします。だから、中小 SIer が色気を出してクラウドサービスに入っても、ほとんど上手くいかないと思うわけです。ましてやグローバル化をや。

ぜひ某社には、きっちり考えてがんばっていただきたいと思います。