かつてプログラマは30歳限界説があった。
ところが、あろうことか40歳を超えても現役を続けている。
そろそろ人生の纏めに入るべく、ノウハウを公開しておこうと思う。
MS-DOS版のMID2PRNが、Windows3.0〜WindowsXP、MacOSX、WindowMobile5.0と 同じソースコードで続いてきた技術は(少しは)役に立つだろうし。
別に、一子相伝にする技術でもないし・・・^^;
100人規模の会社があったとする。
メンバー構成比を以下のように仮定しよう。
全員が係われるような大きなプロジェクトがあればいいけど(リスクは別として)、 1プロジェクト5人くらいの規模のものが20テーマある場合を考える。
優秀な人 10人 本当に優秀であること、出世のうまい人ではNG 並な人 20人 乞うご期待!な人 30人 若手、主にコーディング 外部の人 40人 主にテスト要員
優秀な人と並の人が分担して各プロジェクトを推進することになると思うが、
予定通り進捗する10テーマ 常に不安な10テーマ 管理される立場な並の10人はストレスが溜まりがち
なのは目に見えている。
また、複数のテーマがあると、
ターゲットとなるOSがWindowsだったり、Linuxだったり、Macだったり、・・・ アプリケーション開発だったり、デバイスドライバだったり、WEB関連だったり、・・・ 開発言語がC、C++、C++/CLI、C#、JAVA、Ruby、・・・ クラスライブラリ(パッケージ)は・・・(以下略)
なんてこともあって社内で人を移動させるのも容易ではない。
この状態では、単に「独立した複数グループがある会社」でしかない。
品質はバラバラで、統制がなく、常にあちこちで問題が発生することになる。
優秀な人を有効活用しよう!
優秀な人は社内の全プロジェクトを把握するスーパーバイザーに
⇒上流工程(基本設計〜機能仕様)と技術課題の解決並の人がプロジェクト管理
⇒工数管理可能な作業を担当する社内ライブラリの整備(次項)
⇒ノウハウはソースコードとして社内ライブラリに残す
以下のようなメリットがあるはず。
社内の火種はスーパーバイザーチームが解決(その会社としてはベストな解決になる) 誰かが抜けた時のリスクが少ない
⇒スーパーバイザーチームは10人なので影響は1/10
⇒プロジェクト管理者の代理はスーパーバイザーが可能社内ライブラリを作成することにより、人的リソースの移動コストが削減できる
⇒他人のノウハウを無意識に活用できるので、品質も安定する
プロトタイピング・リファクタリング・アジャイル・・・
いろいろと提唱される開発手法。
でも、よくよく理解してみると、以前から行っていた方法に名前を付けただけだ。
アジャイル(繰り返す事) プロトタイピング 実際に動くものを作ってみること リファクタリング 次の修正に向けて、機能を変更しないで、中身を整理すること 機能追加(プロトタイピング)&リファクタリング バージョンアップ ・・・
ウォーターフォール・モデルに当てはめてみると、
基本設計 プロトタイピング&リファクタリング 全体の流れやUIを作ってみる 詳細設計 プロトタイピング&リファクタリング 難しそうな機能を組み込んで確かめてみる コーディング&デバッグ アジャイル 個々の機能を追加しながら動作確認
何も変わってないじゃない!!!
オブジェクト指向を使っても、再利用できなければ意味がない。
プログラムの主要部分はメモリ上の操作のみにする必要がある。
ファイルの入出力を例に説明しよう。
ファイルfnをpBufferにlenバイトを読み込むとする(エラー処理無し)。
主要部分を抜粋してみたが、コンパイルが通るかどうか自分でもわからない。
- 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);
- 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);
- 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);
- 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);
- 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;
- 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);
- 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();
- 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;
- 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(・・・))・・・
つまり、
- 本当にオブジェクト化すべきは開発環境自体
- 機能実装はメモリ上での処理を基本とする
- 開発者が使用するI/Fの形(名前や引数)を統一する
- 切り替えはマクロ定義とかコンパイルオプションで行う
- ライブラリ側はスーパーバイザーが管理&提供する
構成はこんな感じ。
ソースコードは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.