目次
  • 背景
  • 会社としての方法論
  • 開発手法って何だ?
  • ソフトウェア・ライブラリ
  • MID2PRNの例

  • 背景

    かつてプログラマは30歳限界説があった。
    ところが、あろうことか40歳を超えても現役を続けている。
    そろそろ人生の纏めに入るべく、ノウハウを公開しておこうと思う。
    MS-DOS版のMID2PRNが、Windows3.0〜WindowsXP、MacOSX、WindowMobile5.0と 同じソースコードで続いてきた技術は(少しは)役に立つだろうし。
    別に、一子相伝にする技術でもないし・・・^^;

    会社としての方法論

    100人規模の会社があったとする。
    メンバー構成比を以下のように仮定しよう。
    優秀な人10人本当に優秀であること、出世のうまい人ではNG
    並な人20人
    乞うご期待!な人30人若手、主にコーディング
    外部の人40人主にテスト要員
    全員が係われるような大きなプロジェクトがあればいいけど(リスクは別として)、 1プロジェクト5人くらいの規模のものが20テーマある場合を考える。

    優秀な人と並の人が分担して各プロジェクトを推進することになると思うが、
  • 予定通り進捗する10テーマ
  • 常に不安な10テーマ
  • 管理される立場な並の10人はストレスが溜まりがち

  • なのは目に見えている。

    また、複数のテーマがあると、
  • ターゲットとなるOSがWindowsだったり、Linuxだったり、Macだったり、・・・
  • アプリケーション開発だったり、デバイスドライバだったり、WEB関連だったり、・・・
  • 開発言語がC、C++、C++/CLI、C#、JAVA、Ruby、・・・
  • クラスライブラリ(パッケージ)は・・・(以下略)

  • なんてこともあって社内で人を移動させるのも容易ではない。
    この状態では、単に「独立した複数グループがある会社」でしかない。
    品質はバラバラで、統制がなく、常にあちこちで問題が発生することになる。

    優秀な人を有効活用しよう!
  • 優秀な人は社内の全プロジェクトを把握するスーパーバイザーに
    ⇒上流工程(基本設計〜機能仕様)と技術課題の解決
  • 並の人がプロジェクト管理
    ⇒工数管理可能な作業を担当する
  • 社内ライブラリの整備(次項)
    ⇒ノウハウはソースコードとして社内ライブラリに残す


  • 以下のようなメリットがあるはず。
  • 社内の火種はスーパーバイザーチームが解決(その会社としてはベストな解決になる)
  • 誰かが抜けた時のリスクが少ない
    ⇒スーパーバイザーチームは10人なので影響は1/10
    ⇒プロジェクト管理者の代理はスーパーバイザーが可能
  • 社内ライブラリを作成することにより、人的リソースの移動コストが削減できる
    ⇒他人のノウハウを無意識に活用できるので、品質も安定する

  • 開発手法って何だ?

    プロトタイピング・リファクタリング・アジャイル・・・

    いろいろと提唱される開発手法。

    でも、よくよく理解してみると、以前から行っていた方法に名前を付けただけだ。
    アジャイル(繰り返す事)プロトタイピング実際に動くものを作ってみること
    リファクタリング次の修正に向けて、機能を変更しないで、中身を整理すること
    機能追加(プロトタイピング)&リファクタリングバージョンアップ
    ・・・

    ウォーターフォール・モデルに当てはめてみると、
    基本設計プロトタイピング&リファクタリング全体の流れやUIを作ってみる
    詳細設計プロトタイピング&リファクタリング難しそうな機能を組み込んで確かめてみる
    コーディング&デバッグアジャイル個々の機能を追加しながら動作確認

    何も変わってないじゃない!!!

    ソフトウェア・ライブラリ

    オブジェクト指向を使っても、再利用できなければ意味がない。
    プログラムの主要部分はメモリ上の操作のみにする必要がある。
    ファイルの入出力を例に説明しよう。
    ファイルfnをpBufferにlenバイトを読み込むとする(エラー処理無し)。
    1. C on MS-DOS/Linux
      // fn : c string(Shift-JIS)
      #include <stdio.h>
      FILE *fh;
      fh = fopen(fn,"rb");
      fseek(fh,0,SEEK_SET);
      fread(pBuffer,sizeof(char),len,fh);
      fclose(fh);
    2. C on MacOS9
      流石に誰も使わないとは思うけど...

      // fn : pascal string
      #include <stdio.h>
      OSErr Status;
      short srcFile;
      long countbytes = len;
      Status = FSOpen(fn, 0, &srcFile);
      countbytes = len;
      SetFPos(srcFile,fsFromStart,0);
      FSRead( srcFile, &countbytes, pBuffer );
      FSClose(srcFile);
    3. C++ on Windows
      // fn : c string(Shift-JIS)
      #include "stdafx.h"
      HANDLE hFile = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
      DWORD dwSize = 0;
      ReadFile(hFile,pBuffer,len,&dwSize,NULL);
      CloseHandle(hFile);
    4. C++ on Windows Mobile
      // fn : c string(Shift-JIS)
      #include "stdafx.h"
      // Shift-JISのファイル名をUNICODEに変換する(sprintf(buf,"%s or %S",mojiretu)を使った方が簡単
      char fn_unicode[MAX_PATH*2];
      memset(fn_unicode,0,sizeof(fn_unicode));
      DWORD dwFlags = MB_PRECOMPOSED | MB_USEGLYPHCHARS;
      int iReq = MultiByteToWideChar(CP_ACP,dwFlags,fn,strlen(fn),fn_unicode,0) * 2;
      MultiByteToWideChar(CP_ACP,dwFlags,fn,strlen(fn),fn_unicode,iReq);

      HANDLE hFile = CreateFile(fn_unicode,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
      DWORD dwSize = 0;
      ReadFile(hFile,pBuffer,len,&dwSize,NULL);
      CloseHandle(hFile);
    5. C++(with Borland VCL) on Windows
      // fn : c string(Shift-JIS)
      #include <vcl¥vcl.h>
      TFileStream *fs;
      fs = new TFileStream(fn,fmOpenRead | fmShareDenyWrite);
      fs->Seek(0,soFromBeginning);
      fs->Read(pBuffer,len);
      delete fs;
    6. C++(Carbon) on MacOSX
      // fn : c string(Shift-JIS)
      #include <Carbon/Carbon.h>
      #define MAXPATH 512
      // Shift-JISのファイル名をUTF-8に変換する
      UInt8 fn_utf8[MAX_PATH];
      ConstTextPtr strSJIS = (ConstTextPtr)fn;
      TextPtr strUTF8 = (TextPtr)&fn_utf8[0];
      int oLen = sizeof(data)/sizeof(UInt8);
      TECObjectRef ec;
      ByteCount ail, aol = 0;
      TextEncoding hfsplusEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0, kUnicodeCanonicalDecompVariant, kUnicodeUTF8Format);
      TextEncoding hfsEncoding = CreateTextEncoding(kTextEncodingMacJapanese, kMacJapaneseStandardVariant, kTextEncodingDefaultFormat);
      OSStatus status = TECCreateConverter(&ec, hfsEncoding, hfsplusEncoding);
      status = TECConvertText(ec, (ConstTextPtr)strSJIS, strlen(strSJIS), &ail, (TextPtr)strUTF8, oLen, &aol);
      strUTF8[aol] = 0;
      status = TECDisposeConverter(ec);

      FILE *fh;
      fh = fopen(fn_utf8,"rb");
      fseek(fh,0,SEEK_SET);
      fread(pBuffer,sizeof(char),len,fh);
      fclose(fh);
    7. JAVA
      // fn : String(多分 UTF8)
      import java.io.*;
      private FileInputStream fis;
      private BufferedInputStream bis;
      fis = new FileInputStream(fn);
      bis = new BufferedInputStream(fis);
      ret = bis.read(pBuffer,0,len);
      bis.close();
      fis.close();
    8. C++/CLI on Windows.NET
      // fn : String^
      System::IO::StreamReader^ reader = gcnew System::IO::StreamReader(fn,System::Text::Encoding::Default);
      String^ text = reader->Read(pBuffer,0,len);
      reader = nullptr;
    9. C# on Windows.NET
      // fn : string(多分 UTF8)
      System.IO.StreamReader reader = new System.IO.StreamReader(fn, true);
      reader.Read(pBuffer,0,len);
      reader.Close();
    主要部分を抜粋してみたが、コンパイルが通るかどうか自分でもわからない。
    こんなものを「ノウハウとして全プログラマーが覚えましょう」なんて非現実的な話だし、かつて経験したことなのに数ヶ月も経てば忘れてしまう。
    企業のノウハウは使える形で残ってなければ、無いに等しい。

    次のように対応すれば、ノウハウは資産として残り、設計が効率化されるはずだ。

    開発担当者ファイルオープン
    #define WINDOWS_CPP
    #include <my_company.h>
    fileopen(fn, "rb");
    #define MACOSX_CPP
    #include <my_company.h>
    fileopen(fn, "rb");
    import my_company.*;
    io f = new io();
    f.fileopen(fn, "rb");
    ・・・
    社内ライブラリ層fileopen(char *filename, char *open_mode)
    WINDOWS用処理
    CreateFile(・・・)
    MACOSX用処理
    fopen(・・・)
    JAVA用処理
    new BufferedInputStream(new FileInputStream(・・・))
    ・・・

    つまり、
    1. 本当にオブジェクト化すべきは開発環境自体
    2. 機能実装はメモリ上での処理を基本とする
    3. 開発者が使用するI/Fの形(名前や引数)を統一する
    4. 切り替えはマクロ定義とかコンパイルオプションで行う
    5. ライブラリ側はスーパーバイザーが管理&提供する


    MID2PRNの例

    構成はこんな感じ。
    ソースコードはMS-DOS時代からの試行錯誤が堆積していてますが、ご理解を(鋭意リファクタリング中)。
    Windows用UI
    (OSバージョンの違いはBorlandが頑張ってくれている)
    Windows Mobile用UI
    (機能不足のため非公開)
    MacOSX用UI
    (Carbon)
    Android版
    (検討中)

    MID2PRNの処理

    Javaに移植しなきゃ
    OS共通化I/F
    機能分類関数名機能概要
    ファイルyocreadファイルをメモリ上に読み込む。MIDIファイル程度のサイズなら全部読み込んだ方が何かと便利。
    yfsizeファイルのサイズを返す。
    yocwriteメモリ内容をファイルに書き出す。
    メモリーYAllocMemメモリー領域の確保
    YFreeMemメモリー領域の解放
    フォント  
    描画  
    印刷  
    演奏  
    Windows用処理 WindowsCE用処理
    (印刷機能が無い)
    MacOSX用処理 Java用処理
    • ocread
    • ocwrite

    これだけでもファイルを書き換えるプログラムの共通化が可能かと...

    C++とJavaのソースコードに互換性が無いのが当面の課題。


    Copyright(C) 2008 Y.Yonemura All rights reserved.