レベル: 中級 Nathan A. Good, Senior Information Engineer, Freelance Developer
2009年 7月 14日 Mate は、UI (User Interface) とサービスを MVC (Model-View-Controller) パターンで作成できる、イベント駆動の軽量なフレームワークです。Eclipse PDT (PHP Development Tools) と Flex SDK (Software Development Kit)、そして Mate フレームワークを使用してアプリケーションを作成する方法を学びましょう。この記事では Mate に関する既存のドキュメントを拡張した内容として、Eclipse PDT をツールとして使う方法に焦点を絞ります。
Adobe® Flash® は RIA (Rich Internet Application) を作成するための魅力的な手段の 1 つです。Flash Player で実行するアプリケーションを作成する方法としては、Eclipse と Adobe Flex SDK を利用して、プロジェクトを作成してコンパイルするという方法を取ることもできます。さらに、イベント駆動の軽量なフレームワークである Mate を利用すると、インボーカーを使ってリモート・オブジェクトを容易に呼び出せる強力な機能を備えているため、PHP で記述されたサービスを呼び出すこともできます。
この記事で紹介するサンプルを実行するためには Eclipse PDT が必要です。それ以外に必要なものについては記事の中で説明します。
Mate と Flex SDK の概要
Flex SDK を利用すると、Adobe Flex アプリケーションを作成することができます。Flex アプリケーションを作成するには XML フォーマットのソース・ファイル (.mxml ファイル) と ActionScript V3.0 を使います。これらの .mxml ファイルと ActionScript ファイルをコンパイラーでコンパイルし、Adobe Flex アプリケーションにすることができます。
ダウンロードできる Flex SDK には次の 2 つのバージョンがあります。
- Free Adobe Flex SDK には、アプリケーションをコンパイルできる Adobe 製品と、Adobe AIR、その他のコンポーネントが含まれています。Free Adobe Flex SDK は Adobe Flex SDK ライセンスの下でライセンスされています (「参考文献」を参照)。
- また Flex SDK には、MPL (Mozilla Public License) の下でライセンスされる、Open Source Flex SDK も用意されています。Open Source Flex SDK には、この記事で紹介する例を実行するために必要な、コンパイラーその他のすべてが含まれています。ただし、MPL ライセンスは皆さんが求める条件とは合わない可能性があります。このライセンスが皆さんにとって有効かどうか、皆さんの法務部門と相談してください。
Adobe はさらに、Eclipse プラグインまたは完全な製品としてダウンロードできる、Flex Builder という製品も提供しています。この記事ではオープンソースの Flex SDK をダウンロードします。ZIP ファイルをダウンロードして覚えやすい場所に解凍したら、その場所を FLEX_HOME と呼ぶことにします。この記事では無料の SDK を使って Eclipse をセットアップする方法を説明します。つまり Eclipse と PDT、そして Flex SDK のみで RIA を作成できるのです。
Mate は MVC パターンに従うアプリケーションの作成を支援するフレームワークです。Mate はイベント駆動であるため、ActionScript のクラスとしてのイベントを作成することができます。これらのイベントはリモート・オブジェクトの呼び出しにマッピングできるため、コードの詳細をビューとモデルと別にすることができます。
プロジェクトの構造を作成する
この記事では、PHP サービスを使って Flex UI を作成する方法を説明するために、単純に時刻を入力する ChronoLog というアプリケーションを使用します。この例では、Eclipse ワークスペースに 2 つのプロジェクトが必要です。1 つはサービスに使用される PHP プロジェクトであり、もう 1 つは、Ant ビルダーとしてセットアップされる Ant ファイルを含む通常のプロジェクトです。Flex UI に使用されるプロジェクトをコンパイルするには、Ant ビルダーを使って Flex コンパイラーを実行します。
サービスとしての PHP プロジェクトを作成するためには、Eclipse のメニューから「File (ファイル)」 > 「New (新規)」 > 「Project (プロジェクト)」の順に選択し、表示される画面から「PHP Project (PHP プロジェクト)」を選択します。次に「Create project from existing source (外部ソースからプロジェクトを作成)」を選択し、ファイル・サーバーのドキュメント・ルート配下の場所を選択します。こうすることによって、これから作成する PHP サービスを素早くテストすることができます。
UI プロジェクトを作成するためには、「File (ファイル)」 > 「New (新規)」 > 「Project (プロジェクト)」の順に選択した後、「Project (プロジェクト)」を選択し、空のプロジェクトを作成します。
UI 用のプロジェクトを作成したら、「src」というフォルダーを作成し、その「src」フォルダーの中に「chronolog」という別のフォルダーを作成します。「chronolog」フォルダーの下に、「events」、「model」、「views」、「maps」というフォルダーを作成します。この構造は下記のようになるはずです。
図 1. UI プロジェクトの構造
Mate のダウンロードとインストール
Mate は .swc という拡張子の付いたコンパイル済みの 1 つのファイルとしてダウンロードすることができます。このファイルをサイトからダウンロードし、それを UI プロジェクトの「libs」フォルダーにインポートしてインストールします。その結果は図 2 のようになるはずです。
図 2. 「libs」フォルダーにインストールされた Mate の .swc ファイル
単純なサービスを作成する
このサービスは PHP で作成されており、2 つのクラスしか持っていません。1 つは、この機能を実行するサービス・クラスであり、もう 1 つは TimeEntry という UI クラスのマッピング先となる PHP のクラスです。
サービス・クラスを作成する前に、必要な AMFPHP ファイルをダウンロードしてインストールします。このサンプルを実行するためには、単純に amfphp フォルダーを PHP プロジェクトにインストールします (図 3)。
図 3. amfphp フォルダー
このサービス・クラスをリスト 1 に示します。このサービス・クラスは、値を簡単な XML ファイルとして一時的な場所に書き出すだけのクラスです。書き出しが適切に行われるように、(太字で記されている) この場所をコンピューター上で変更する必要があるかもしれません。そしてこの場所を、Web ブラウザーが読み書きできるファイルの名前に変更する必要があります。
リスト 1. amfphp/services/ChronoLogManager.php ファイル
<?php
require_once('./vo/TimeEntry.php');
/*
* A service for managing time entries.
*/
class ChronoLogManager
{
public function saveTimeEntry($entry)
{
$myFile = "/tmp/time.xml";
$fh = fopen($myFile, 'w') or die("can't open file");
$stringData = "<projects>";
$stringData .= "<entry project=\"$entry->project\" " .
"time=\"$entry->time\" user=\"$entry->username\" />";
$stringData .= "</projects>";
fwrite($fh, $stringData);
fclose($fh);
}
}
?>
|
サービス・サイドのモデル・オブジェクト、TimeEntry.php をリスト 2 に示します。AMFPHP では Value Object を services/vo フォルダーに保存する必要があります。そのため、この PHP ファイルの (PHP プロジェクトのルートに対する) 相対パス名は、amfphp/service/vo/TimeEntry.php となります。AMFPHP ではクラス名とファイル名が (拡張子を除いて) 一致する必要があります。
リスト 2. amfphp/services/vo/TimeEntry.php ファイル
<?php
class TimeEntry
{
var $_explicitType = 'model.TimeEntry';
public $username;
public $project;
public $time;
}
?>
|
異なるさまざまなパラメーターの代わりに 1 つのクラスをパラメーター・オブジェクトとして使うメリットの 1 つは、時刻を入力するフィールドに新しいフィールドが追加された場合、そのオブジェクトに新しいフィールドを追加するだけですむことです。一方でデメリットとしては、メッセージング用のフレームワークを使用する場合に起こりやすい問題が複合型で起こる可能性があります。場合によると、単純型 (ストリング、整数、ブール値) の方が問題を避けられるため、使いやすいことがあります。
モデル・オブジェクトを使う
モデル・オブジェクトは、アプリケーションの中でデータを保持する ActionScript のクラスであり、PHP サービス階層のリモート・オブジェクト (TimeEntry.php) にマッピングされます。モデル・オブジェクトはメソッドの引数 (またはメソッドの実行結果) として使うことができるため、UI とサービスとの間でデータを渡し合うための配列を作成する必要がありません。
通常、1 つの技術を使用して UI を作成し、別の技術を使用してサービスを作成する場合には、どちらの技術にも理解できる何らかのフォーマットにクラスをシリアライズするフレームワークを作成するか、あるいはそうしたフレームワークを見つけなければなりません。多くの場合は XML が使われますが、それは最近のプログラミング言語には XML を読み書きできるユーティリティーが用意されていることが多いためです。
この記事のアプリケーションでは、AMFPHP を使って Flex オブジェクトをリモートの PHP オブジェクトにマッピングします。AMF (Adobe Message Format) はオブジェクトのシリアライズとデシリアライズのための、Adobe によるフォーマットです。AMF を使うことによる 1 つのメリットは、オブジェクト同士を接続することができ、UI とサービスの間でのシリアライズとデシリアライズのためのコードを独自に作成する必要がないことです。AMF によって Flex を PHP に接続するためのフレームワークには、Zend のフレームワークなど、いくつかあります (「参考文献」を参照)。
TimeEntry 用のモデル・オブジェクトをリスト 3 に示します。このオブジェクトには各時刻入力フィールドに使われる情報が含まれています。このオブジェクトを UI プロジェクトの src/chronolog/model フォルダーに保存します。
リスト 3. src/chronolog/model/TimeEntry.as ファイル
package model
{
[Bindable]
[RemoteClass(alias='TimeEntry')]
public class TimeEntry
{
private var _username : String;
private var _project : String;
private var _time : String;
public function TimeEntry()
{
}
public function get username() : String
{
return _username;
}
public function set username(value : String) : void
{
_username = value;
}
public function get project() : String
{
return _project;
}
public function set project(value : String) : void
{
_project = value;
}
public function get time() : String
{
return _time;
}
public function set time(value : String) : void
{
_time = value;
}
}
}
|
このクラスの中で宣言される RemoteObject 属性を別にすると、このクラスはアプリケーションをサポートするために作成される他の ActionScript のクラスとまったく同じです。
イベントを作成する
Mate はイベント駆動のフレームワークであるため、Mate を使用する際には多くのイベントを作成します。Mate イベントは flash.events.Event という基底クラスを継承する ActionScript のクラスです。ストリング定数によって特定のイベントを識別することができ、また各イベント・クラスの中に 1 つ以上の定数を持つことができます。私はこの機能を利用して、ビジネス・ドメインでの目的ごとにイベントをグループ分けしています。例えば ChronoLog の例には TimeEntryEvent クラスがあります。このクラスは、時刻入力を保存する関数のトリガー・イベントを表現する、SAVE という定数を使っています。プロジェクトを拡張する場合には、この同じクラスのより多くのイベントに GET や DELETE などの定数を使うこともできます。
イベントの名前にはビジネスの用語を使用し、それらのイベントをビジネスの機能にマッピングします。ButtonEvent というイベント・クラスを作成して SAVE_CLICKED という定数を追加する、などということをしてはいけません。それは命名規則として不適切であり、イベントの再利用を暗黙のうちに制限してしまいます。もしユーザーが気分を変え、ボタンをリンクに変更した場合には、イベントと UI とが密結合になりすぎることによる問題が発生します。
TimeEntryEvent という ActionScript のクラスの例をリスト 4 に示します。このクラスでは、SAVE 定数を追加する他に、コンストラクターの bubbles パラメーターのデフォルトが true に変更されています。ここではイベントの引数を TimeEntry 型の public 変数として追加しています。
リスト 4. src/chronolog/events/TimeEntryEvent.as ファイル
package events
{
import flash.events.Event;
import model.TimeEntry;
public class TimeEntryEvent extends Event
{
public static const SAVE : String = 'TimeEntryEvent_SAVE';
public var entry : TimeEntry;
public function TimeEntryEvent(type:String, bubbles:Boolean=true,
cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
|
ビューを作成する
ActionScript のクラスを別にすると、UI プロジェクトの中にある他のファイルは Flex コンポーネントです。これらのコンポーネントは .mxml 拡張子を持つファイルの中に置かれます。MXML ファイルは整形式の XML ファイルなので、ここでは Eclipse の中で MXML ファイルを XML エディターと関連付け、フォーマット設定やタグ閉じといった XML エディターの機能を利用しています。MXML ファイルを作成するためには、「File (ファイル)」 > 「New (新規)」 > 「File (ファイル)」の順に選択し、そのファイルに適切な名前を付けます。
UI に関して、メインのアプリケーション・ファイル (main.mxml) にはメインの EventMap への参照とビューへの参照しか含まれていません。main.mxml ファイルのソースをリスト 5 に示します。main.mxml ファイルは UI プロジェクトの src/chronolog フォルダーに保存されます。
リスト 5. src/chronolog/main.mxml ファイル
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
xmlns:maps="maps.*"
xmlns:views="views.*">
<mx:ViewStack>
<views:DetailView id="detailView" />
</mx:ViewStack>
</mx:Application>
|
detailView というビューは Flex の Panel オブジェクトを継承する Flex コンポーネントです。このビュー全体の内容を示したものが下記です。
リスト 6. src/chronolog/views/DetailView.mxml ファイル
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal"
width="100%"
height="100%"
xmlns:mate="http://mate.asfusion.com/">
<mx:Script>
<![CDATA[
import com.asfusion.mate.events.ResponseEvent;
import mx.controls.Alert;
import model.TimeEntry;
import events.TimeEntryEvent;
[Bindable]
public var entry : TimeEntry;
private function save() : void
{
entry = new TimeEntry();
entry.username = 'jdoe';
entry.project = projectInput.text;
entry.time = timeInput.text;
}
private function handleResult(event : ResponseEvent) : void
{
Alert.show('Success!');
}
private function handleFault(event : ResponseEvent) : void
{
Alert.show(event.fault.toString());
}
]]>
</mx:Script>
<mx:HBox>
<mx:FormItem label="Project Number">
<mx:TextInput id="projectInput" />
</mx:FormItem>
<mx:FormItem label="Time">
<mx:TextInput id="timeInput" />
</mx:FormItem>
<mx:Button label="Save" click="save()" />
</mx:HBox>
</mx:Panel>
|
このビューには 2 つのフィールドと 1 つのボタンが含まれています。フィールドには、プロジェクト番号と、作業した時間を表す値が入ります。同じく時間入力フィールドに使われるユーザー名はハードコーディングされています。将来的には、このユーザー名には、ユーザーがアプリケーションにログインする際に取得されるデータを使用するようにします。このビューを DetailView.mxml という MXML ファイルとして views フォルダーに保存します。
EventMap を作成する
Mate の EventMap を継承するコンポーネントを使ってイベントをアクションにマッピングします。このマッピングによって、イベントがリモート・オブジェクトに「接続」されます。また EventMap を使うことで、イベント終了時にそのイベントが他のイベントを呼び出すようにしたり、ローカル・オブジェクトに値を設定したり、ローカルでメソッドを起動することもできます。
特に、イベントのチェーン機能は強力です。イベントをチェーンすることによって、イベント間のやりとりの多くをハードコーディングする必要がなくなり、変化するビジネスのニーズにプロジェクトを柔軟に対応させることができます。例えば、データの保存に成功した後の画面を別のビューに変更したいとユーザーが望んだ場合には、この変更を実現するための NavigateEvent を作成し、TimeEntry.SAVE イベントが NavigateEvent をディスパッチするようにします。このように、後になってユーザーの考えが変わった場合には、その新しい要件を反映するように EventMap を更新するだけでよいのです。
リスト 7 は MainEventMap の一例です。これは maps フォルダーの中に作成された単なる .mxml ファイルです。
リスト 7. src/chronolog/maps/MainEventMap.mxml ファイル
<?xml version="1.0" encoding="utf-8"?>
<mate:EventMap
xmlns:mate="http://mate.asfusion.com/"
xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import events.TimeEntryEvent;
]]>
</mx:Script>
<mate:EventHandlers type="{TimeEntryEvent.SAVE}">
<mate:RemoteObjectInvoker destination="amfphp"
source="ChronoLogManager"
method="saveTimeEntry"
arguments="{event.entry}">
<mate:resultHandlers>
<mate:ServiceResponseAnnouncer type="result" />
</mate:resultHandlers>
<mate:faultHandlers>
<mate:ServiceResponseAnnouncer type="fault" />
</mate:faultHandlers>
</mate:RemoteObjectInvoker>
</mate:EventHandlers>
</mate:EventMap>
|
EventMap の中で、RemoteObjectInvoker は、TimeEntryEvent.SAVE 型のイベントをリモート・オブジェクト (ChronoLogManger) の適切なメソッド (saveTimeEntry) にマッピングするための情報を含んでいます。また RemoteObjectInvoker エントリーは、引数としてイベントのエントリー・フィールド {event.entry} を指定しています。呼び出し先 (amfphp) は services-config.xml ファイルの中で指定される呼び出し先の ID です。
EventMap を作成したら、下記のようにメインのアプリケーションに EventMap を含めます。
リスト 8. main.mxml ファイルの中の MainEventMap
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
xmlns:maps="maps.*"
xmlns:views="views.*">
<maps:MainEventMap id="eventMap" />
<mx:ViewStack>
<views:DetailView id="detailView" />
</mx:ViewStack>
</mx:Application>
|
ビューの中でイベントをディスパッチする
Mate を使うと、さまざまな方法でイベントをディスパッチすることができます。各コンポーネントに付属しているディスパッチャーを使うことができますが、Mate の Dispatcher を使うこともできます。ChronoLog アプリケーションでは Mate の Dispatcher を使っています。この Dispatcher を使うと、イベントのパラメーターをテキスト入力などのローカル値に設定するのが容易になり、そのためのコードを ActionScript で作成する必要がないというメリットがあります。また Dispatcher を使うと、イベントが完了した時に実行されるようにメソッドを設定することができます。
下記では Dispatcher を太字で示しています。
リスト 9. src/chronolog/views/DetailView.mxml ファイルの中の Dispatcher
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal"
width="100%"
height="100%"
xmlns:mate="http://mate.asfusion.com/">
<mx:Script>
<![CDATA[
import com.asfusion.mate.events.ResponseEvent;
import mx.controls.Alert;
import model.TimeEntry;
import events.TimeEntryEvent;
[Bindable]
public var entry : TimeEntry;
private function save() : void
{
entry = new TimeEntry();
entry.username = 'jdoe';
entry.project = projectInput.text;
entry.time = timeInput.text;
saveDispatcher.generateEvent();
}
private function handleResult(event : ResponseEvent) : void
{
Alert.show('Success!');
}
private function handleFault(event : ResponseEvent) : void
{
Alert.show(event.fault.toString());
}
]]>
</mx:Script>
<mx:HBox>
<mx:FormItem label="Project Number">
<mx:TextInput id="projectInput" />
</mx:FormItem>
<mx:FormItem label="Time">
<mx:TextInput id="timeInput" />
</mx:FormItem>
<mx:Button label="Save" click="save()" />
</mx:HBox>
<mate:Dispatcher id="saveDispatcher" generator="{TimeEntryEvent}"
type="{TimeEntryEvent.SAVE}">
<mate:eventProperties>
<mate:EventProperties entry="{entry}" />
</mate:eventProperties>
<mate:ServiceResponseHandler result="handleResult(event)"
fault="handleFault(event)" />
</mate:Dispatcher>
</mx:Panel>
|

 |
サービスを呼び出す
サービスを呼び出すためには、AMFPHP サービス構成ファイルの PHP のクラスを services-config.xml ファイルの中でセットアップする必要があります。services-config.xml ファイルは、AMF をサポートするフレームワークに有効な、サービスのエンドポイントの URL を含んでいます。下記はservices-config.xml ファイルの例です。
リスト 10. src/services-config.xml ファイル
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="amfphp-flashremoting-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="amfphp">
<channels>
<channel ref="my-amfphp" />
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition id="my-amfphp"
class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://localhost/chronolog/amfphp/gateway.php"
class="flex.messaging.endpoints.AMFEndpoint" />
</channel-definition>
</channels>
</services-config>
|
AMFPHP が使用するゲートウェイの URL を皆さんの環境の場合に該当する URL に変更する必要があることに注意してください。
プロジェクトを作成する
すべての Flex ファイルがセットアップできると、Ant ビルダーは Flex SDK に含まれている mxml.jar を使ってプロジェクトをコンパイルします。下記は Ant ファイルです。
リスト 11. build.xml ファイル
<?xml version="1.0"?>
<project name="chronologUI" basedir="." default="build">
<property name="flex.home" value="/home/ngood/bin/flex3-sdk" />
<property name="mxmlc.jar" value="${flex.home}/lib/mxmlc.jar" />
<property name="project.home" value="${basedir}" />
<property name="project.src" value="${project.home}/src" />
<property name="build.out" value="${project.home}/bin" />
<target name="build">
<java jar="${mxmlc.jar}" fork="true" failonerror="true">
<jvmarg value="-Xms256m"/>
<jvmarg value="-Xmx256m"/>
<arg value="-compiler.source-path=${project.src}" />
<arg value="+flexlib=${flex.home}/frameworks" />
<arg value="-compiler.library-path+=${project.home}/libs/Mate_08_8_1.swc" />
<arg value="-file-specs=${project.src}/chronolog/main.mxml" />
<arg value="-locale=en_US" />
<arg value="-services=${project.src}/services-config.xml" />
<arg value="-compiler.strict=true" />
<arg value="-warnings=false" />
<arg value="-output=${build.out}/chronolog.swf" />
</java>
</target>
</project>
|
プロジェクトに「build.xml」ファイルが追加されたら、「Ant Builder」を追加します (「Project Explorer (プロジェクト・エクスプローラー)」で「chronologUI」を選択してから、「Project (プロジェクト)」 > 「Properties (プロパティー)」の順に選択し、「Properties (プロパティー)」ウィンドウで「New (新規)」をクリックし、表示される一覧から「Ant Builder」を選択します)。次の画面 (図 4) に進んで「Browse Workspace (ワークスペースを参照)」をクリックし、「build.xml」ファイルを見つけて選択します。ビルダーのセットアップでは自動的にデフォルトのターゲットを使用するため、「Finish (完了)」をクリックしてブラウザーを閉じます。プロジェクトに対して独自のビルダーを作成する方法の詳細は「参考文献」を参照してください。
図 4. Ant ビルダーを作成する
これでプロジェクトにビルダーが追加されたので、Eclipse のメニューで「Project (プロジェクト)」 > 「Build (ビルド)」の順に選択すると、このビルダーが実行されます。
この例では AMFPHP を使用しているので、AMFPHP フレームワークをサポートするAMF ディレクトリーが存在している必要があります。AMFPHP のセットアップ方法とインストール方法の詳細については「参考文献」を参照してください。
サンプル・アプリケーションを実行する
UI プロジェクトを作成したら、Web ブラウザーのドキュメント・ルートの配下に chronolog.swf ファイルを置いて、ブラウザーでそこまでナビゲートします。するとブラウザーには下記のような画面が表示されるはずです。
図 5. 完成したアプリケーションが実行されている様子
データを入力して「Save」をクリックすると、サービス・レイヤーによって、サービスで指定された場所にある小さな XML ファイルにデータが書き込まれます。
まとめ
Flex SDK、Mate、PHP を利用すると、リッチな Web アプリケーションを作成することができます。Eclipse プロジェクトのセットアップをいくつか変更し、Flex Builder を使うことで、Eclipse の中で Flex SDK を使って Flex アプリケーションを作成することができます。しかも Flex Builder では UI の編集とデバッグを WYSIWYG で行えるため、Flex アプリケーションの作成がはるかに容易になります。
Eclipse PDT と AMFPHP を利用すると、Flex アプリケーションで利用できるサービスを作成することができます。また、(AMF を使った) リモーティングによって、Flex からリモート・オブジェクトのメソッドを呼び出すイベントを素早く作成することができます。
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | 
|  | Nathan A. Good はミネソタ州の Twin Cities エリアに住んでいます。彼はプロとしてソフトウェア開発やソフトウェア・アーキテクチャー、システム管理などを行っています。彼はソフトウェアを書いている時以外は、PC やサーバーを構築したり、新しい技術について資料を読んだり、そうした技術に取り組んだり、彼の友人達をオープソース・ソフトウェアに移行させようとしたりしています。彼は数多くの本や記事を執筆、あるいは共同で執筆しており、その中には『Professional Red Hat Enterprise Linux 3』や『Regular Expression Recipes: A Problem-Solution Approach』、『Foundations of PEAR: Rapid PHP Development』などがあります。 |
記事の評価
|