<feed xmlns='http://www.w3.org/2005/Atom'><id>http://blog.madoro.org/mn/feed/atom</id><title type='text'>Masatomo Nakano Blog - Quipperでの日々</title><updated>2011-06-29T16:46:28Z</updated><link href='http://blog.madoro.org/mn/feed/atom' rel='self' type='application/atom+xml'/><link href='http://blog.madoro.org/mn/' rel='alternate' type='text/html'/><author><name>Masatomo Nakano</name></author><entry><id>http://blog.madoro.org/mn/91</id><title type='text'>Gitをバックエンドに使ったプログラマ向きWiki - Gitit</title><summary type='html'>&lt;p&gt;Wikiというものはとても便利なんだけど、&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;大量の文章を書くにはWebブラウザのインターフェースはまだまだ辛い&lt;/li&gt;
	&lt;li&gt;オフラインで使えない(文章書くのは電車が一番)&lt;/li&gt;
	&lt;li&gt;複数の文章を再構成したり、一括で検索したり、置換したりは、Webだとやっぱりきびしい&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;と言った欠点がある。&lt;/p&gt;
&lt;p&gt;とは言え、誰でも気軽に編集できるWikiの魅力も捨てがたい。&lt;/p&gt;
&lt;p&gt;そこで、「Wikiではあるんだけど、ローカルでも自分の好きなエディタで簡単に編集できるツールないかなー」と探してみたら、 &lt;a href=&quot;https://github.com/jgm/gitit&quot;&gt;Gitit&lt;/a&gt; というWikiを発見した。&lt;/p&gt;
&lt;p&gt;ここ数日、結構な量のドキュメントをGititで書いてみて、わりと満足しているのだけど、検索してもGititの日本語の情報があまり出てこないので紹介してみる。&lt;/p&gt;
&lt;p&gt;Gititの特徴&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;コンテンツをGitのレポジトリに保存する。&lt;/li&gt;
	&lt;li&gt;そのGItレポジトリをcloneして好きなようにいじってからcommit/pushすれば即座にWikiに反映される。&lt;/li&gt;
	&lt;li&gt;Wikiとしてはとても普通。マークアップはmarkdownがデフォルトだけど他にも選べる。各種言語のコードを綺麗に色付きでフォーマットしてくれる。&lt;/li&gt;
	&lt;li&gt;Haskell製でpluginとかもHaskellで書く。&lt;/li&gt;
	&lt;li&gt;Webサーバを内蔵している。&lt;/li&gt;
	&lt;li&gt;独自のメタ情報のようなものを持たずに、Gitレポジトリ内のディレクトリ/ファイル構成がそのままWikiになる。ファイル名がそのままWiki名になる。もしやめたくなった場合に他のツールへの移行も楽。&lt;/li&gt;
	&lt;li&gt;テキスト以外の画像とかもそのままGitレポジトリに入る。もちろん、cloneしたレポジトリに画像を入れてcommit/pushすればアップロードされる。&lt;/li&gt;
	&lt;li&gt;Gitそのままなので分散Wikiみたいのも簡単に作れるし、branchを使ってのドキュメントの管理とかもできる。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Github製の &lt;a href=&quot;https://github.com/github/gollum&quot;&gt;gollum&lt;/a&gt; と似ているが、Gititの方が良さそう。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://gitit.johnmacfarlane.net/&quot;&gt;デモサイトはこちら。&lt;/a&gt; Wikiとしては、普通中の普通なので面白くないけど。&lt;/p&gt;
&lt;p&gt;Haskell製と知って、インストールめんどくさそうだなーと思ったんだけど簡単だった。&lt;/p&gt;
&lt;p&gt;簡単な導入手順 &amp;#8211; Ubuntu編&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sudo apt-get install ghc
$ sudo apt-get install cabal-install&lt;/code&gt;

&lt;code&gt;$ cabal update
$ cabal install pandoc gitit -fhighlighting --reinstall
(pandocとgititを同時にinstallしないとhightlightが有効にならなかった)&lt;/code&gt;

&lt;code&gt;path に ${HOME}/.cabal/bin を追加&lt;/code&gt;

&lt;code&gt;$ mkdir ~/hogehoge
$ cd ~/hogehoge
$ gitit --print-default-config &amp;gt; gitit.conf
$ &amp;lt;editor&amp;gt; gitit.conf
$ gitit -f gitit.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで、port 5001で起動するので、 http://localhost:5001/ とかで。外に公開するなら、apacheとかnginxでreverse proxyすればいいだろう。&lt;/p&gt;
&lt;p&gt;コンテンツを直接いじりたい場合は、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone ssh://example.com:~/hogehoge/wikidata&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;とかで、普通にcloneして後はお好きなエディタでファイルを編集して、commit/push すればその場で反映される。&lt;/p&gt;
&lt;p&gt;こんな感じで、Gititを使うと、gitを使ったプログラミングと同じフロー/リズムでドキュメントを書けるところが気に入ったのでした。&lt;/p&gt;
&lt;p&gt;オススメ。&lt;/p&gt;</summary><updated>2011-05-25T00:19:56Z</updated><link href='http://blog.madoro.org/mn/91' rel='alternate' type='text/html'/></entry><entry><id>http://blog.madoro.org/mn/90</id><title type='text'>Google App Engine / Python 上での開発で最初から知ってればよかった、ってことをいくつか</title><summary type='html'>&lt;p&gt;ここ数ヶ月、Google App Engine/Pythonを使い、初めてちょっとしたものを作ってみているのだけど、開発初期から知っておけばよかったなー、と思うノウハウ/tips的なものをずらずらと書いてみる。&lt;/p&gt;
&lt;p&gt;基本的な環境設定は、 &lt;a href=&quot;http://blog.madoro.org/mn/88&quot;&gt;以前書いた&lt;/a&gt; まま。&lt;/p&gt;
&lt;h3&gt;0. 公式ドキュメントを良く読む&lt;/h3&gt;
&lt;p&gt;言うまでもなく、だけど、 &lt;a href=&quot;http://code.google.com/appengine/docs/python/&quot;&gt;マニュアル&lt;/a&gt; はもちろん、 &lt;a href=&quot;http://code.google.com/appengine/articles/&quot;&gt;この辺&lt;/a&gt; の下の読み物も、流し読みだけでもしておいたほうがいい。&lt;/p&gt;
&lt;h3&gt;datastoreとmodel的なところ&lt;/h3&gt;
&lt;h4&gt;1. key nameを使いこなす&lt;/h4&gt;
&lt;p&gt;key nameは、レコードの作成時に指定できる(RDBでいう)primary keyの別名みたいなもの。primary key自体は自動的で作成されるので開発者が指定できるのはkey nameだけ。&lt;/p&gt;
&lt;p&gt;key nameをうまく使うことで、datastoreを使いやすくすることができる。特にdatastore上で&amp;quot;unique&amp;quot;を表現したいときに活躍する。&lt;/p&gt;
&lt;p&gt;たとえば、 &lt;a href=&quot;http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_get_or_insert&quot;&gt;Modelクラスのget_or_insert&lt;/a&gt; では、key nameを使うことで簡単にuniqueなレコードを作成することができる。get_or_insert()と言う名前通り、 key nameで指定したレコードが存在したらget、しなかったらそのままinsertといういうことができる。この処理はatomicに行われるので、同じkey nameのレコードが複数存在してしまうこともない。&lt;/p&gt;
&lt;p&gt;get_or_insert()の注意点としては、 get時には渡した値ではupdateされない、ということにということがある。そのまんまget or inssert。&lt;/p&gt;
&lt;h4&gt;2. どういうkey nameを使うべきか&lt;/h4&gt;
&lt;ul&gt;
	&lt;li&gt;他システムから取り込んだレコードでuniqueとされている値&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例えば、twitter botとか作るなら(作ってないけど)、twitterのユーザIDとか、tweet毎のIDとかそのまま key nameに入れてしまうのが良さそう。&lt;br /&gt;
今作っているシステムでは、別システムのMongoDB上で作ったデータをそのまま取り込んでいる部分がある。そういうデータは &lt;a href=&quot;http://www.mongodb.org/display/DOCS/Object+IDs&quot;&gt;MongoDBのBSON ID&lt;/a&gt; を文字列にしたのをそのまま key nameにしている。なかなかいい感じ。&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;クライアント側で生成されたデータ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;クライアント側で生成されるようなデータをdatastoreに格納する場合、クライアント側でUUIDみたいのを作成し、それをそのままkey nameにするのもなかなかよさそう。&lt;/p&gt;
&lt;p&gt;このUUIDをkey nameにしてget_or_insert()することで、クライアント端末やネットワークの不調等で同一データが2回POSTされたりしても、データが二重になったりしないのがなかなか気に入っている。もちろんUUIDを偽造されても問題ないような作りにしておく必要はあるけど。&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;複合キー&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;key nameは一つしか設定できないのだけど、ただの文字列なので上記の値を結合して関連テーブルを作成したりできる。これは場合によってはなかなか便利。&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;その他&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;uniqueっぽいものがないモデルの場合でも、とりあえずランダムで長めの文字列を指定しておくとよいかも。後からは指定できない。&lt;/p&gt;
&lt;h4&gt;3. GQLで key nameで検索&lt;/h4&gt;
&lt;p&gt;key nameでのオブジェクトの取得は、基本的には、 &lt;a href=&quot;http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_get_by_key_name&quot; title=&quot;&quot;&gt;get_by_key_name&lt;/a&gt; を使えばいいのだけど、WebのadminコンソールとかGQLしか使えないようなところでは、こんな感じに書ける。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WHERE __key__ = KEY(&apos;FooModel&apos;, &apos;cff0611529520910195ed357dd69f908&apos;)&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4. get_or_insert() でgetされたかinsertされたかを知る&lt;/h4&gt;
&lt;p&gt;get_or_insert() を実行した結果、getされたかinsertされたかがそのままでは簡単にはわからないのが、これを知りたいときがある。例えば「get_or_insert()してgetだった場合には〜する」みたいなとき。&lt;/p&gt;
&lt;p&gt;こういうときのために、次のようなclass methodを作っている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@classmethod
def get_or_insert2(cls, key_name, **kwds):
  def txn():
    entity = cls.get_by_key_name(key_name, parent=kwds.get(&apos;parent&apos;))
    if entity is None:
      entity = cls(key_name=key_name, **kwds)
      entity.put()
      return (True,entity)
    return (False,entity)
  return run_in_transaction(txn)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;または、 insertに成功した場合だけオブジェクトを返し、既に存在する場合はNoneを返す処理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@classmethod
def insert_or_fail(cls, key_name, **kwds):
  def txn():
    entity = cls.get_by_key_name(key_name, parent=kwds.get(&apos;parent&apos;))
    if entity is None:
      entity = cls(key_name=key_name, **kwds)
      entity.put()
      return entity
    return None
  return run_in_transaction(txn)&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;5. unique制約&lt;/h4&gt;
&lt;p&gt;datastore上で、unique制約を作るのはちょっと大変。ユーザ情報を格納するUserモデル内でemailアドレスをuniqueにしたい、とか非常にありがちなことが簡単にはできない。&lt;/p&gt;
&lt;p&gt;こういう場合にも、key nameがうまく使える。unique制約を保持するためのモデルを別に作って、uniqueにしたいデータ(この場合emailアドレス)をkey nameにしてしまうのがいい感じ。上記の、insert_or_fail で作成してみて、作成できたらそのemailアドレスは使える、という感じ。(何か他に定石がありそうなんだけど。)&lt;/p&gt;
&lt;h4&gt;6. データの一括更新&lt;/h4&gt;
&lt;p&gt;システムのアップグレード時など、データを一括で更新したくなるときがある。SQLだとUPDATE一発みたいな更新でも、datastoreだとちょっと大変。こういうときは &lt;a href=&quot;http://code.google.com/p/appengine-mapreduce/&quot;&gt;map/reduce&lt;/a&gt; を使うと素早く簡単に全件の更新ができてよい感じ。(件数多いと、CPU時間==お金を一気に消費しちゃうけど)&lt;/p&gt;
&lt;p&gt;(このappengine-mapreduceはmap/reduceってか、単に全レコードに対して並列で何かができるだけなんだけど。本当のmap/reduceはそのうち導入されるらしいので楽しみ。)&lt;/p&gt;
&lt;h4&gt;7. ランキング&lt;/h4&gt;
&lt;p&gt;ちょっとしたゲームっぽいものを作ると「スコアランキング」みたいなものが必要になったりするものだけど、このランキングってのはRDBでもそれなりに厄介なもので、何も考えないで作ると、大量のアクセスが発生してしまい使いものにならなくなる。その結果、バッチ処理で静的なランキングを作成するとかちょっとダサい感じになってしまいがち。&lt;/p&gt;
&lt;p&gt;で、ちょっと自分で色々なアルゴリズムで実装してみたりしてたのだけど、便利なライブラリを見つけてしまったのでそれを使っている。 &lt;a href=&quot;http://googleappengine.blogspot.com/2009/01/google-code-jams-ranking-library.html&quot;&gt;このライブラリ。&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;8. 複数レコードの保存/削除は db.put() / db.delete() を使って一括で行う&lt;/h4&gt;
&lt;p&gt;スピードが全然違う。db.delete() はクエリをそのまま突っ込んだりもできる。&lt;/p&gt;
&lt;h4&gt;9. 全文検索&lt;/h4&gt;
&lt;p&gt;全文検索は、現在の Google App Engine ではまともに実装されていないらしい。(Googleのくせに! 近い将来実装されると発表されたが)&lt;/p&gt;
&lt;p&gt;ただ、簡易的には SearchableModel が使える。使い方は、 &lt;a href=&quot;http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/search/__init__.py&quot;&gt;コードの中のコメント&lt;/a&gt; が一番詳しいような気がする。&lt;/p&gt;
&lt;p&gt;そのコメントにあるように、かなり低機能で日本語も使えない。 ただ、とりあえずそれっぽく動かすだけなら簡単に使える。&lt;/p&gt;
&lt;h3&gt;ログ関連&lt;/h3&gt;
&lt;h4&gt;10. loggingを使ってログを取る&lt;/h4&gt;
&lt;p&gt;logging moduleを使うことで、実行時に色々なログを取れる。Google App Engineともうまく統合されていて、Web上のadminインタフェースで、httpアクセス毎に参照できてとても便利。&lt;/p&gt;
&lt;h4&gt;11. POSTされたデータとそれに対応するresponse bodyをすべてログに&lt;/h4&gt;
&lt;p&gt;loggingを使ってPOSTの中身とresponseをそのままログに取っておくとデバッグ時に便利。Google App Engineの管理画面からアクセス毎にPOSTとそれに対応するresponseの内容を見ることができる。&lt;/p&gt;
&lt;p&gt;これをするためのMiddlewareを書いた。(実際には &lt;a href=&quot;http://blog.madoro.org/mn/88&quot;&gt;前回&lt;/a&gt; 書いたようにセッション管理用の SessionMiddleware も挟んでいる。)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class PostLoggerMiddleware(object):
  def __init__(self, app):
      self.app = app&lt;/code&gt;
  
&lt;code&gt;  def __call__(self, env, start_response):
      request = webapp.Request(env)
      if request.body:
          logging.info(&quot;request: &quot; + str(request.body))&lt;/code&gt;
      
&lt;code&gt;      def my_start_response(status, response_headers, exc_info=None):
        write = start_response(status, response_headers, exc_info)
        def my_write(body):
          logging.info(&quot;response: &quot; + str(body))
          write(body)
        return my_write&lt;/code&gt;
      
&lt;code&gt;      return self.app(env, my_start_response)&lt;/code&gt;
  
&lt;code&gt;  application = PostLoggerMiddleware(webapp.WSGIApplication([
  ...&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;12. exceptionをtrackback付きでログに&lt;/h3&gt;
&lt;p&gt;基本的に何もしなければ、Traceback付きでログに乗る。しかし、コード側で、 &lt;a href=&quot;http://code.google.com/appengine/docs/python/tools/webapp/requesthandlerclass.html#RequestHandler_handle_exception&quot; title=&quot;&quot;&gt;handle_exception&lt;/a&gt; を定義してexceptionをすべてcatchして処理を続けたいときもある。&lt;/p&gt;
&lt;p&gt;たとえば、現在JSON APIをGoogle App Engine上で作っているのだけど、例外が起きた時もJSONでエラーを返すことにしている。&lt;/p&gt;
&lt;p&gt;こういう場合には、その中で JSONを返す処理を書きつつ、logging.exception(exception) と書いておくと、admin画面上では普通にTraceback付きでエラーが見える。&lt;/p&gt;
&lt;h3&gt;その他&lt;/h3&gt;
&lt;h4&gt;13. 自分のアプリを複数バージョン同時に持てる。ただし datastore は共通。&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://code.google.com/appengine/docs/python/config/appconfig.html&quot;&gt;app.yaml で指定する。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;最初知ったときは、datastore共通で何に使うんだよ、と思ったんだけど色々便利なこともあった。&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;新バージョンのテスト。わりとメインの使い方か。でも、datastoreは一個なのであまり思い切ったことはできない。&lt;/li&gt;
	&lt;li&gt;バージョン毎にログが別になる。Google App Engineのadmin画面はバージョン毎なので、ログも別々になる。map/reduceとかを同じバージョンでやるとログがそれで溢れてしまってうざいことがあるんだけど、それも別にしておくといいかもしれない。&lt;/li&gt;
	&lt;li&gt;propertyの型を変えるとかちょっとしたmigrationをするときに別のバージョンでやるのがいい(下記参照)。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;14. 非同期でいい処理にはできる限り Task Queue を使う&lt;/h4&gt;
&lt;p&gt;リアルタイムでなくていい処理は全部 &lt;a href=&quot;http://code.google.com/appengine/docs/python/taskqueue/&quot;&gt;Task Queue&lt;/a&gt; に回してしまってもいいぐらいかも。&lt;/p&gt;
&lt;p&gt;主な理由は二つ。&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;HTTPアクセスの処理を早く終わらせるため&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これはもちろんユーザのために、という意味もあるが、Google App Engineの設計ではとにかく早く処理を返すことがスケール面でも有効らしいので大事。&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;リトライしてくれる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Google App Engineはそれなりに不安定なので、Google App Engineの都合でエラーがそれなりの頻度で起こる。そのさい task queue に入れておけばGoogle App Engineが直るまでretryしてくれる。&lt;/p&gt;
&lt;p&gt;特に、mail送信などのAPIはしばしばtimeout (例えばこんなエラー: &amp;#8220;DeadlineExceededError: The &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; call mail.Send() took too long to respond and was cancelled&amp;#8221;) とかするので、これは必ず task queue に入れておいたほうがよさそう。メールは元々非同期で問題ないので相性もいい。&lt;/p&gt;
&lt;h4&gt;15. Modelのpropertyの型の変更&lt;/h4&gt;
&lt;p&gt;datastore自体はどんな型でもレコード毎に柔軟に持てるのだけど、その上で動くModelクラスは型にとても厳しくなっている。floatからintegerへなどの型も自動的には変換してくれない。その上read時にexceptionを出してくれてしまうので、結構厄介。&lt;/p&gt;
&lt;p&gt;運用を初めてから型を変更する必要がでてきた場合には、以下の方法がいいみたい。&lt;/p&gt;
&lt;p&gt;db.Expando クラスを使って値を更新する。db.Expandoクラスは、Modelのサブクラスなんだけど、設定していないpropertyも読み書きができる。また、システムを止めずに更新したい場合には、アプリの別バージョンを作成し、その上で行うと影響をあまり与えずにできる。&lt;/p&gt;
&lt;p&gt;例:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class HogeUser(db.Model):
  foo = db.StringProperty()
  bar = db.StringProperty()
  score = db.FloatProperty()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;このscoreをfloatからintegerに変更したくなったとする。&lt;/p&gt;
&lt;p&gt;こういう場合には、このクラスを一時的にdb.Expandoから継承するようにして、かつscoreを削除してしまう(データ自体は消えない)。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class HogeUser(db.Expando):
  foo = db.StringProperty()
  bar = db.StringProperty()
  # score = db.FloatProperty()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;そして、以下のようなmap/reduceを走らせる。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def alter_score_to_int(hoge_user):
  if &quot;score&quot; in hoge_user.dynamic_properties() and type(hoge_user.score) is float:
    hoge_user.score = int(hoge_user.score)
    hoge_user.put()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;終わったら、元に戻して Int に変更する&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class HogeUser(db.Model):
  foo = db.StringProperty()
  bar = db.StringProperty()
  score = db.IntegerProperty()&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;16. エラーをメール通知&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://code.google.com/appengine/articles/python/recording_exceptions_with_ereporter.html&quot;&gt;http://code.google.com/appengine/articles/python/recording_exceptions_with_ereporter.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;標準で入っているこのライブラリを使うと、発生したエラーをdailyでまとめてメールしてくれる。それほど高機能ではないが、同じようなエラーはまとめるという最低限なことはしてくれる。自分でメールの内容をカスタマイズもできるみたい。&lt;/p&gt;
&lt;p&gt;こんな感じで最初の方に書いている。ローカルでのSDK環境の場合、エラーになってしまうのでスキップしている。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;in_local_sdk = (os.environ.get(&quot;SERVER_SOFTWARE&quot;) == &quot;Development/1.0&quot;) or os.environ.get(&quot;TERM&quot;)
if not in_local_sdk:
    from google.appengine.ext import ereporter
    ereporter.register_logger()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;その他の設定は、上のリンク先のまま。&lt;/p&gt;
&lt;h4&gt;17. 死活監視&lt;/h4&gt;
&lt;p&gt;Google App Engine上のアプリの死活監視をする場合の注意点として、Google App Engineが不安定になっている場合、readはokで、writeだけがエラーになるケースがあるようなので、writeが発生するような処理で監視をしたほうがよさそう。&lt;/p&gt;
&lt;h3&gt;参考にしたところ&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.mail-archive.com/google-appengine@googlegroups.com/msg20008.html&quot;&gt;http://www.mail-archive.com/google-appengine@googlegroups.com/msg20008.html&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://stackoverflow.com/questions/4742875/change-integerproperty-to-floatproperty-of-existing-appengine-datastore&quot;&gt;http://stackoverflow.com/questions/4742875/change-integerproperty-to-floatproperty-of-existing-appengine-datastore&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://devblog.miumeet.com/2011/02/schedule-mapreduce-daily-on-appengine.html&quot;&gt;http://devblog.miumeet.com/2011/02/schedule-mapreduce-daily-on-appengine.html&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://googleappengine.blogspot.com/2009/06/10-things-you-probably-didnt-know-about.html&quot;&gt;http://googleappengine.blogspot.com/2009/06/10-things-you-probably-didnt-know-about.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;他多数、だが忘れた。&lt;/p&gt;</summary><updated>2011-06-29T16:46:28Z</updated><link href='http://blog.madoro.org/mn/90' rel='alternate' type='text/html'/></entry><entry><id>http://blog.madoro.org/mn/89</id><title type='text'>退職しました</title><summary type='html'>&lt;p&gt;やめちゃった。&lt;/p&gt;
&lt;p&gt;8年半前に創業直後だったこの会社に入って、ほぼ0から色々なものを作り、動かし、それなりに会社は大きくなり、立場的にもそれなりに偉くなり、給料もそれなりに貰って、居心地は悪くなくて、そうなんだけど、その一方で、自分にとって刺激は少なくなり、なんとなく楽しさが減っていた、という感じ。自分自身なんとなく安定してしまっている、という状況自体がなんとなく怖かったりもした。&lt;/p&gt;
&lt;p&gt;それでも、暇なら色々と遊べるのだけど、日々やらないといけないことは全然減らなくて、忙しいんだけど何か刺激がない、みたいな悪い状態に陥っていた。&lt;/p&gt;
&lt;p&gt;会社のことを考えてみても、多少老害になりそうな自分が辞めることで、新陳代謝したほうがいいのかなー、というのもある。よく知っているだけに思い切ったことができなくなっていることも多いし、なんとなく偉そうにしている自分も嫌だったりした。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.madoro.org/mn/84&quot;&gt;前にも少し書いた&lt;/a&gt; ように基本的にいい会社になっているとは思うんだけど、悪い文化もできてしまっている。その悪い文化を作ることになってしまった一端は、長いこといる自分にもあるわけで、その自分が存在しつつ、その悪い文化を変えていくのはなかなか難しい、と感じているのもある。&lt;/p&gt;
&lt;p&gt;まあ、上記すべて本音のつもりだけど微妙に嘘っぽく、後付けの理由っぽくもある。単に、色々なことに飽きてしまったのかも！&lt;/p&gt;
&lt;p&gt;家族もいるし、常に崖っぷちを楽しむわけにもいかないけど、それなりの逃げ道を残しつつも新しいことドキドキしながらしたいとか思ってしまう。こんな時代だし、飽きちゃったとか、新しいことしたい、とかいう理由でやめちゃうのは甘っちょろいな、とも思うんだけど、まあやめちゃいました。&lt;/p&gt;
&lt;p&gt;なんだかんだで8年半在籍したわけだけど、8年半ってのは結構長いよなあ。自分の中でも、人生で所属した組織で一番長いものになってしまった。2位が小学校で、3位が最初に入った会社かな。そういう組織を離れるのはなかなか寂しいものはあるのだけど、別れはいつか来るということで。&lt;/p&gt;
&lt;p&gt;それにしても、この会社では本当に、大きなことから小さなことまで色々な新しい経験をさせてもらったなー。外国文化に触れることもできたし、とても人生にとってプラスになるものだったと思う。感謝でいっぱい。&lt;/p&gt;
&lt;p&gt;で、何するの？ ってことだけど、まだ内緒！ ということで。もう少しロンドンにいる予定です。&lt;/p&gt;</summary><updated>2011-04-02T12:25:22Z</updated><link href='http://blog.madoro.org/mn/89' rel='alternate' type='text/html'/></entry><entry><id>http://blog.madoro.org/mn/88</id><title type='text'>Google App EngineとPythonでの素直な開発環境の構築(TDDができるように)</title><summary type='html'>&lt;p&gt;追記: &lt;a href=&quot;http://blog.madoro.org/mn/90&quot;&gt;続編的なものを書いた。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;今年は色々なことに手を出してみよう、ってことで少し前からGoogle App Engine(以下GAE)で、あるモノを作っている。モノ自体は近いうちに公表できると思う。&lt;/p&gt;
&lt;p&gt;基本的に、Pythonと標準っぽいフレームワークだけでやってみている。作っているものがそれなりにシンプルなのと(だからこそGAE!)、GAEでそれなりの規模の開発をするのが自分自身初めてということもあり、あまり色々なレイヤーを重ねて手こずりたくなかった、ってのがその理由。&lt;/p&gt;
&lt;p&gt;ただ、GAE初心者なので、「いやいやそれは今時ないよ」「XXの方が100倍いい」とかあったら教えてくれると嬉しいので今のところの環境を書いておくことにした。今ならスイッチ可能。&lt;/p&gt;
&lt;p&gt;今作っているものがJSONファイルを入出力するだけのものなので、HTML生成パートみたいのはない。&lt;/p&gt;
&lt;h3&gt;1. フレームワーク&lt;/h3&gt;
&lt;p&gt;上にも書いたように、今回は、わりと単純なアプリケーションの作成なので、Google App Engine (Python)で提供されている最小限のフレームワークだけを使っている。&lt;/p&gt;
&lt;h3&gt;2. Pythonのバージョンは2.5&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://code.google.com/appengine/docs/python/gettingstarted/devenvironment.html&quot;&gt;Google App Engineは2.5が前提&lt;/a&gt; らしい。&lt;/p&gt;
&lt;p&gt;Mac (Snow Leopard) だと、2.6と2.5の両方が入っていて、デフォルト(/usr/bin/python)のバージョンは2.6。そのため普通にGoogle App Engineの開発環境をインストールすると2.6が使われてしまっていて、最初の数時間無駄にした。&lt;/p&gt;
&lt;p&gt;defaultコマンドで /usr/bin/python の指すバージョンを変えられるようだけど、他に影響を与えたくなかったので、今回は、&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;コマンドラインから実行するpython関連のコマンドは2.5を付けて実行(例: easy_install-2.5)&lt;/li&gt;
	&lt;li&gt;GoogleAppEngineLauncherで、 /usr/bin/python2.5 を指定&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;で、なんとかなっている。&lt;/p&gt;
&lt;h3&gt;3. ディレクトリ構成&lt;/h3&gt;
&lt;p&gt;「GAE/Pythonスタンダードなディレクトリ構成」みたいのはないようなので、いろいろな公開されているプロジェクトを参考にして以下のような配置にしてみた。最初はもうちょっと深い構成にしていたのだけど、これぐらいで十分かも。今のところModelは1ファイルにまとめてるがだいぶ増えてきたので、近い将来分離する予定。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;application dir/
  models.py
  handlers/foo_handler.py
  handlers/bar_handler.py
  tests/test_foo_handler.py
  tests/bar_foo_handler.py
  main.py
  app.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;controller的なものをhandlerと呼ぶみたいなのでそうしてる。&lt;/p&gt;
&lt;h3&gt;4. テスティング環境&lt;/h3&gt;
&lt;p&gt;もう当然TDDだよね、ということで最初に手をつけたのがテスト環境の構築。&lt;/p&gt;
&lt;p&gt;まず、ここしばらくWeb開発でRuby on Rails + rspecメインな生活をしていることもあり、GAE/Python上でもそれっぽいのを探してみたところ、いくつかそれっぽいのはあったのだけど、「開発が活発ではない」「使いづらそう」という感じがしたのでその方向は諦めて、普通にUnitTestでいくことにした。マイナーなものを使うよりも、自分以外の人が触ることになったときのことを考えて、ふつーなものにしておいたほうがいいかな、という判断もある。&lt;/p&gt;
&lt;p&gt;素のUnitTestだけだといろいろいまいちなので、以下の物を入れた。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo easy_install-2.5 nose
sudo easy_install-2.5 nosegae
sudo easy_install-2.5 gaetestbed
sudo easy_install-2.5 webtest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使い方等は、その中のgaetestbedの &lt;a href=&quot;https://github.com/jgeewax/gaetestbed/blob/master/README.markdown&quot;&gt;&lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt;&lt;/a&gt; 読めばなんとなく使い方はわかるので省略。&lt;/p&gt;
&lt;h3&gt;5. doctest併用&lt;/h3&gt;
&lt;p&gt;UnitTestの他に、コードの中にテストを書ける &lt;a href=&quot;http://docs.python.org/library/doctest.html&quot;&gt;doctest&lt;/a&gt; も使っている。基本的にhandlerのテストはUnitTestで、modelのテストはdoctestで書いている。&lt;/p&gt;
&lt;p&gt;併用している理由としては、長い間うっすらと「なんかdoctestいいなー、いつか使ってみたい」と思っていたのと、今回はそれほど複雑なmodelがないというのがある。&lt;/p&gt;
&lt;p&gt;nosegaeは、UnitTestとdoctestの両方を同時に扱えるので、この二つを混ぜても素直に全体のテストの実行が1コマンドできる。オプションに&amp;#8212;with-doctest を付けて、&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; nosetests --with-gae --with-doctest &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;こんな感じ。CIでもほぼこれと同じコマンドを実行している。&lt;/p&gt;
&lt;h3&gt;6. セッション管理&lt;/h3&gt;
&lt;p&gt;GAEでは、Googleアカウントと連動したセッション+アカウント管理は標準で提供されているようだけど、今回は自前でセッション/アカウント管理をしたかったので、それは使わずに、セッション管理には &lt;a href=&quot;https://github.com/dound/gae-sessions&quot;&gt;gae-sessions&lt;/a&gt; を使ってみた。他にも色々あるのだけど、単純で軽そうだったのでこれにした。&lt;/p&gt;
&lt;p&gt;そのライブラリの作者が作った他のライブラリとの &lt;a href=&quot;https://github.com/dound/gae-sessions/wiki/comparison-with-alternative-libraries&quot;&gt;比較表&lt;/a&gt; が参考になる。完全勝利になってるのは若干あやしいが。&lt;/p&gt;
&lt;p&gt;このライブラリで作成したセッションに、自分で作ったユーザ用のモデルを入れるという簡単実装にした(gae-sessionsのセッションの実装自体は普通にCookieを使ったものなのでデバッグ等も簡単)。&lt;/p&gt;
&lt;p&gt;一つ躓いた点として、gae-sessionsの導入手順をREADMEに従うと、 appengine_config.py を作ってそこでmiddlewareをセットする、となっている。ただ、ローカルの開発環境でnosegaeを使いunit testを流すと、 appengine_config.py は読んでくれないので、main.py の中で直接読み込んでごまかしてる。こんな感じ。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;application = SessionMiddleware(
    webapp.WSGIApplication([....],
                           debug=True),
    cookie_key=&quot;hogehogehogehogehogehogehogehogehogehogehogehogehogehoge&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7. 本: Code in the Cloud&lt;/h3&gt;
&lt;p&gt;とりあえずGoogle App Engineを始めるにあたって何冊か読んだ本の中でそれなりに良かった奴。JavaとPython両方が書いてあるのが微妙に読みづらいが、最初に読む本、としてはそこそこいい本だと思う。テスト関係のことはほとんど載ってないけど。&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;nou=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=wkjza-22&amp;o=9&amp;p=8&amp;l=as1&amp;m=amazon&amp;f=ifr&amp;asins=1934356638&quot; style=&quot;width:120px;height:240px;&quot; scrolling=&quot;no&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;h3&gt;8. まとめ&lt;/h3&gt;
&lt;p&gt;以上の環境で、ぼちぼちコードを書いているけど、気持ち良くTDDができている。GAE自体は思ってたよりも(話に聞いていたよりは)複雑でも難しくもなく素直だなーって印象。ドキュメントもわかりやすい。まあ、後発組は楽だなあ、と。&lt;/p&gt;
&lt;p&gt;とは言え、もうちょっとやると壁にあたりそうなので、そのときまた何か書きたいと思う。&lt;/p&gt;
&lt;h3&gt;9. 参考にしたもの&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.cuberick.com/2008/11/unit-test-your-google-app-engine-models.html&quot;&gt;http://www.cuberick.com/2008/11/unit-test-your-google-app-engine-models.html&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/jgeewax/gaetestbed/&quot;&gt;https://github.com/jgeewax/gaetestbed/&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.slideshare.net/adeoshineye/test-driven-development-on-google-app-engine&quot;&gt;http://www.slideshare.net/adeoshineye/test-driven-development-on-google-app-engine&lt;/a&gt;&lt;/p&gt;</summary><updated>2011-05-23T00:53:28Z</updated><link href='http://blog.madoro.org/mn/88' rel='alternate' type='text/html'/></entry><entry><id>http://blog.madoro.org/mn/87</id><title type='text'>2010年を振り返っちゃう</title><summary type='html'>&lt;p&gt;全体的になかなかいい年だったかな。Web開発に関係するところを挙げてみると、&lt;/p&gt;
&lt;h3&gt;このブログを始めた&lt;/h3&gt;
&lt;p&gt;どうもヒキコモリ過ぎてるなと感じていたので、ブログを始めてみた。3日坊主にならずにそれなりに続いたのは良かった。やっぱり、自分を外に出すことは自分を客観的に見るためにも大切だ。&lt;/p&gt;
&lt;p&gt;おかげさまで、そこそこの反応を頂けたりと、なかなか楽しいです。&lt;/p&gt;
&lt;h3&gt;技術面&lt;/h3&gt;
&lt;p&gt;Rubyを始めて2年目にしてRubyとRailsが身についた、って感じかなー。自分の学習曲線の中のいいタイミングで、 &lt;a href=&quot;http://blog.madoro.org/mn/65&quot;&gt;Metaprogramming Ruby&lt;/a&gt; という良本に出会えたのが良かった。&lt;/p&gt;
&lt;p&gt;また、去年の後半くらいからMongoDBを追いかけていたのだけど、今年の後半、実際のシステムで少し使うことができて手応えを得ている。今後は、もうちょっと大きいところでも使ってみるつもり。MongoDBいいですよ。&lt;/p&gt;
&lt;p&gt;スクラム初体験してみたのも今年だったかな。これは正直、完全に自分の武器になったか、と言うと微妙なところ。もうちょっと実戦で勉強。&lt;/p&gt;
&lt;h3&gt;来年&lt;/h3&gt;
&lt;p&gt;来年は、仕事面でちょっと変化の年にしたい。ここ数年、いい面でも悪い意味でも安定してしまっているので、少しかき混ぜたい感じ。&lt;/p&gt;
&lt;p&gt;流行に乗り、スマートフォンやGoogle App Engineなどにも急激に興味が出てきたので(やらなきゃまずいかな、というのもある)、そっち方面を攻めるのが濃厚。流されやすいんです！&lt;/p&gt;
&lt;p&gt;そんなわけで、来年もよろしくー！&lt;/p&gt;</summary><updated>2011-01-05T11:18:40Z</updated><link href='http://blog.madoro.org/mn/87' rel='alternate' type='text/html'/></entry><entry><id>http://blog.madoro.org/mn/86</id><title type='text'>Heroku + MongoHQ が素晴らしい</title><summary type='html'>&lt;p&gt;前から気になっていた &lt;a href=&quot;http://heroku.com/&quot;&gt;Heroku&lt;/a&gt; + &lt;a href=&quot;http://mongohq.com/&quot;&gt;MongoHQ&lt;/a&gt; を試してみた。HerokuはRubyアプリケーションを走らせるホスティングサービスで、MongoHQはMongoDBのホスティングサービスだ。この二つを組み合わせることで、MongoDBを使ったRubyアプリケーションを一瞬で運用開始することができる。&lt;/p&gt;
&lt;p&gt;あまりにも簡単に使えてあまり書くこともないんだけどメモ。&lt;/p&gt;
&lt;p&gt;まず、両方とも最低限の環境は無料で使用できる(ただしHerokuからMongoHQを使うためにはクレジットカードの登録は必要っぽい)。&lt;/p&gt;
&lt;p&gt;今回は Ruby on Rails 3 + &lt;a href=&quot;http://mongoid.org/&quot;&gt;Mongoid&lt;/a&gt; で作ったアプリを置いてみた。&lt;/p&gt;
&lt;h3&gt;手順&lt;/h3&gt;
&lt;p&gt;1. まず、普通に RoR + Mongoid のアプリケーションを作る&lt;/p&gt;
&lt;p&gt;2. Herokuにアカウントを作りアプリケーションを登録する (&lt;a href=&quot;http://docs.heroku.com/quickstart&quot;&gt;http://docs.heroku.com/quickstart&lt;/a&gt; )&lt;/p&gt;
&lt;p&gt;3. HerokuでMongoHQを有効にする (&lt;a href=&quot;http://docs.heroku.com/mongohq&quot;&gt;http://docs.heroku.com/mongohq&lt;/a&gt; )&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ heroku addons:add mongohq:free&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4. Mongoidの接続情報であるconfig/mongoid.ymlのproduction環境のところを以下のように書き換える。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;production:
  uri: &amp;lt;%= ENV[&apos;MONGOHQ_URL&apos;] %&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;追記: もしくは、 config/initializers/mongohq.rb のようなファイルを作り、 そこで指定する。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if ENV[&apos;MONGOHQ_URL&apos;]
  # For Heroku (See: http://docs.heroku.com/mongohq)
  Mongoid::Config.instance.from_hash({&quot;uri&quot;=&amp;gt; ENV[&apos;MONGOHQ_URL&apos;]})
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;5. 普通にHerokuへdeployする (具体的には、gitでHerokuにpushする)&lt;/p&gt;
&lt;p&gt;これだけで、MongoHQのMongoDBを使うようになる。超簡単。&lt;/p&gt;
&lt;p&gt;(ちなみに、ここ最近、RubyとMongoDB間のORMはMongoidしか使っていない。一時期、 &lt;a href=&quot;http://mongomapper.com/&quot;&gt;MongoMapper&lt;/a&gt; を使っていたのだけど、Mongoid の使いやすさに負けた。機能的には大きく変わらないのだけど、ちょっとした細かいところとか、センスの良さが全然違う。)&lt;/p&gt;
&lt;h3&gt;気付いたところ&lt;/h3&gt;
&lt;p&gt;1. Heroku経由でMongoHQを使うとMongoHQにログインできない？&lt;/p&gt;
&lt;p&gt;MongoHQにも管理画面的なのがあるっぽいのでこれはちょっと嫌だ。(何か方法ありそうだが)&lt;/p&gt;
&lt;p&gt;2. &lt;a href=&quot;http://support.mongohq.com/discussions/community-tips/2-logging-in-to-mongohq-for-heroku-users&quot;&gt;ここ&lt;/a&gt; にあるように、MongoDBの接続情報を取得し、自分の環境からHerokuを通さずに直接接続も可能。&lt;/p&gt;
&lt;p&gt;バックアップもmongodumpコマンドで普通に取れるし、 &lt;a href=&quot;http://www.mongodb.org/pages/viewpage.action?pageId=5537856&quot;&gt;Mongoシェル&lt;/a&gt; でアクセスするのも問題ない。これは便利。&lt;/p&gt;
&lt;p&gt;ただ、便利なのだけど、つまりMongoHQのMongoDBは全世界から接続可能なので、接続情報や、ID/パスワードの管理は慎重にする必要があるのがちょっと厳しい。例えば、Rubyアプリ側では、 &lt;span class=&quot;caps&quot;&gt;ENV&lt;/span&gt;[&amp;#8220;MONGOHQ_URL&amp;#8221;] にID/パスワード含む接続情報がすべて入っているので、デバッグ目的などでENVを間違えて表示しちゃったりすると大惨事になりそう(これはHerokuのMySQLとかPostgreSQLとかも同じっぽいが)。&lt;/p&gt;
&lt;p&gt;3. HerokuからMongoHQまでのlatencyは一桁ミリ秒だった。&lt;/p&gt;
&lt;p&gt;なんとなく不安だったのだけど問題なさそう。&lt;/p&gt;
&lt;h3&gt;まとめ&lt;/h3&gt;
&lt;p&gt;RoRとMongoDB(Mongoid)のスキーマレスでの素早い開発と、簡単にデプロイできるHeroku+MongoHQの相性がとてもよい。ちょっとしたアプリケーションを作ったり、プロトタイプを作って色々な人に見せたい場合にとても向いていると感じた。もちろん、アクセス数やデータベース容量にあわせて、Heroku/MongoHQともに有料コースに切り替えて本番環境として使い続けるのも問題ないだろう。&lt;/p&gt;
&lt;p&gt;また、「Heroku+MongoHQで動かす」と言っても、アプリケーション自体はもちろん普通のRuby(Rails)とMongoDBなので、Heroku/MongoHQが嫌になったら、他へ移ることも、自分で運用するのにも何の問題もない。「とりあえず作ってHeroku+MongoHQで動かしてある程度軌道に乗ったところ次を考える」というのが可能だ。これはかなり魅力的(今、世の中はロックインが流行ってるようだし！)。&lt;/p&gt;</summary><updated>2011-01-05T11:18:40Z</updated><link href='http://blog.madoro.org/mn/86' rel='alternate' type='text/html'/></entry><entry><id>http://blog.madoro.org/mn/85</id><title type='text'>1356 はてブ、761 ツイートのパワー</title><summary type='html'>&lt;p&gt;&lt;img src=&quot;http://blog.madoro.org/mn/images/mn/tt_0013/google_analytics.png&quot; class=&quot;attach_img&quot;&gt;&lt;/img&gt;&lt;/p&gt;
&lt;p&gt;このブログは「何か書きたい」というのと「色々試したい」という欲求を満たすために今年の一月に始めたわけだけど、その「試したい」ことの一つが「はてなブックマーク(以下はてブ)」だった。&lt;/p&gt;
&lt;p&gt;自分自身はブックマークとしては  &lt;a href=&quot;http://www.delicious.com/masatomo&quot;&gt;delicious&lt;/a&gt; を使っているのだけど、はてブもRSSで人気エントリのものはなんとなく読んでいるし、twitterでも、はてブが元の話題がそれなりに流れているし、影響力がそれなりに強いように思う。&lt;/p&gt;
&lt;p&gt;それで、 &lt;a href=&quot;http://blog.madoro.org/mn/84&quot;&gt;前回の記事&lt;/a&gt; に、たくさんのはてブを頂いたので、ちょっとアクセス数を出してみる。&lt;/p&gt;
&lt;p&gt;また、同じように、今、旬なtwitterからのアクセス数も出してみる。タイトルの&amp;quot;761 ツイート&amp;quot;ってのは、twitter公式の &lt;a href=&quot;http://twitter.com/goodies/tweetbutton&quot;&gt;Tweet Button&lt;/a&gt; で表示されてる数。&lt;/p&gt;
&lt;p&gt;visitor数 (Google Analytics調べ)&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;td&gt;  &lt;/td&gt;
		&lt;th&gt;トータル &lt;/th&gt;
		&lt;th&gt;&lt;a href=&quot;http://b.hatena.ne.jp/&quot;&gt;はてなブックマーク経由&lt;/a&gt; &lt;/th&gt;
		&lt;th&gt;&lt;a href=&quot;http://www.hatena.ne.jp/&quot;&gt;はてなトップ経由&lt;/a&gt; &lt;/th&gt;
		&lt;th&gt;twitter経由 &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;th&gt;19日  &lt;/th&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;12,261     &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;3,059 &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;1,336 &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;710 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;th&gt;20日  &lt;/th&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;7,465      &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;2,497 &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;51    &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;395 &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;th&gt;21日  &lt;/th&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;1,670      &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;234   &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;18    &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;96  &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;th&gt;22日  &lt;/th&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;704        &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;90    &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;0     &lt;/td&gt;
		&lt;td style=&quot;text-align:right;&quot;&gt;32  &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;記事を投稿したのが19日で、普段のvisitor数が数百なので、どかーんと増えてだいたい丸3日で正常運転に戻ったようだ。ほとんどが、はてなブックマークのトップページ(人気エントリ)と、はてなのトップという掲載期間のあるものだから当然か。&lt;/p&gt;
&lt;p&gt;twitterは自分が想像していたよりも息が短く、同じように丸3日ぐらいでブログへのアクセスもほとんどなくなり、自分宛のmentionもほとんどなくなった。もちろん、記事の内容や質によってはもっと後を引くこともあるんだろう。&lt;/p&gt;
&lt;p&gt;もちろん、リファラーからの分析なので、専用クライントとか、RSSリーダからのものは入ってない。特にtwitterはそういうのが多そうだなあ、と想像はできる。&lt;/p&gt;
&lt;p&gt;数字的には、正直なところ、まあこんなものか、という感じ。もう数倍くらい多いのかなと勝手に妄想していた。&lt;/p&gt;
&lt;p&gt;ええ、普段はB2BのWebのお仕事なのであまりこの辺の分析をしたことがない。そろそろ勉強しないとね。&lt;/p&gt;
&lt;h3&gt;おまけ &amp;#8211; そのアクセスによって：&lt;/h3&gt;
&lt;h4&gt;followers/subscribersの増加&lt;/h4&gt;
&lt;ul&gt;
	&lt;li&gt;twitterのfollowerが+100&lt;/li&gt;
	&lt;li&gt;Google Readerのsubscribersが+116&lt;/li&gt;
	&lt;li&gt;livedoor Readerのsubscribersが+53&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;ネットワーク使用量: 1.85GB&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.madoro.org/mn/3&quot;&gt;このブログで使ってるVPS&lt;/a&gt; の契約は月間100GBなんでしばらく平気そう。&lt;/p&gt;
&lt;h4&gt;はてブのコメントへの感想&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://b.hatena.ne.jp/entry/blog.madoro.org/mn/84&quot;&gt;コメント&lt;/a&gt; は基本的に「共感できる」と「勉強になる」とが大部分だった。感想文/反省文なんで、あんまり叩かれることもなく静かだった。&lt;/p&gt;
&lt;h4&gt;IE6だと化けるよ、について&lt;/h4&gt;
&lt;p&gt;直した。content-typeのヘッダーにtypoがあったorz&lt;/p&gt;
&lt;p&gt;IE/Firefox/Chrome/Safari/Opera/w3m 辺りの最新版ではたまに確認しているのだけど、IE6とかもう仕事だけで勘弁してよ！ ってのはある。&lt;/p&gt;
&lt;p&gt;また、このブログでのIE6は、通常時で0.7%くらい。今回の一時的にアクセスが多かったときで1%ぐらい。こういうブログでまだ1%弱いるってのはほんと驚き。&lt;/p&gt;
&lt;p&gt;それでは、静かに戻ったこのブログを今後もよろしくー。&lt;/p&gt;</summary><updated>2010-10-25T00:30:39Z</updated><link href='http://blog.madoro.org/mn/85' rel='alternate' type='text/html'/></entry><entry><id>http://blog.madoro.org/mn/84</id><title type='text'>スタートアップ企業で8年間Webの開発をしてみての反省点いろいろ</title><summary type='html'>&lt;p&gt;2002年、当時設立したばかりの会社に入り、何もない状態から、コンテンツとシステムを作り続け8年が経った。日々、試行錯誤しながら、それなりに会社も大きくなり、まだ、大成功とは言えないけど、それなりにうまくやってきたつもりだ。&lt;/p&gt;
&lt;p&gt;しかしながら、その8年という短くはない時間の中で、色々な課題や問題が発生し、その時々正しい選択をしてきたつもりだったけど、反省点も多い。もう一度スタートアップに参加するとしたら、やり直したいところや、もっと早くこうしていれば良かったというところがたくさんある。&lt;/p&gt;
&lt;p&gt;そんなわけで、次の挑戦のときに忘れないように、また、もしかして誰かの参考くらいになればと思い、メモっておくことにした。&lt;sup class=&quot;footnote&quot; id=&quot;fnr1&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;まず、反省点の前に、何をやっているのかというのを簡単に。&lt;/p&gt;
&lt;p&gt;ビジネスとしては、英語e-learningのWebサービス(ネットを使った英語のお勉強)をASPな形で、企業や大学などに提供している。開発はすべて社内で行ない、データセンタに自前のサーバを持ち運用している。&lt;/p&gt;
&lt;p&gt;Web業界の花形(?)であるB2Cではないので、そっちだと違ってくることも多いかもしれない。近い将来B2Cもやりたいのだけどね。&lt;/p&gt;
&lt;p&gt;社内での自分の役割としては、入社以来、技術的なところを一通り見させてもらっている。開発から保守、運用、ユーザサポートのヘルプといったシステム周りはすべて。もちろん自分でプログラミングもする。また、システム側の人材の確保なども行っている。&lt;/p&gt;
&lt;p&gt;そんなわけで、下記のことも「純粋な一(いち)プログラマ目線」なことや「マネージャ目線」やその他色々な目線が入り交じっているので、その辺はそういうことで。マルチロールで幅広くできるのもスタートアップの楽しさの一つでもある。&lt;/p&gt;
&lt;p&gt;では、以下に反省点と課題をずらずらと挙げてみる。&lt;/p&gt;
&lt;h2&gt;システム開発についての反省点&lt;/h2&gt;
&lt;h3&gt;1. 丁寧に正しく作ろう&lt;/h3&gt;
&lt;p&gt;一つだけ選ぶとしたらこれ。これがすべてにつながってくる。スタートアップ企業にとって、スピードが大切というのは間違いないのだけど、目先のスピードのために、色々なことを犠牲にしてしまっていたことがあった。正しく丁寧に作ることが中長期で考えるとスピードにもつながる、ということを頭で理解しつつも、つい手を抜いてしまっていた。&lt;/p&gt;
&lt;p&gt;まず、「今必要でないことはやらない &amp;#8211; &lt;a href=&quot;http://en.wikipedia.org/wiki/You_ain&amp;#39;t_gonna_need_it&quot;&gt;&lt;span class=&quot;caps&quot;&gt;YAGNI&lt;/span&gt;&lt;/a&gt; 」ということを常に考えよう。そして、その上で「今必要」となったものは全力で丁寧に正しく作ろう。&lt;/p&gt;
&lt;p&gt;丁寧に正しく作られたアプリケーションは拡張がしやすくメンテナンスもしやすく不具合も起きづらい。当然のことを当然のようにやることがとても大切。&lt;/p&gt;
&lt;p&gt;自社で、自社のシステムを作る場合、一度作って終わりというわけではなく&lt;sup class=&quot;footnote&quot; id=&quot;fnr2&quot;&gt;&lt;a href=&quot;#fn2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;、永遠に自分達でメンテナスをしていかないといけない。そういうことも念頭において「未来の自分達のため」にも正しく作ることを意識しよう。&lt;/p&gt;
&lt;h4&gt;「丁寧に正しく作る」例&lt;/h4&gt;
&lt;p&gt;丁寧に正しく作る、というのは、基本の繰り返しでしかない。例えば、&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;RDBを使うなら、
	&lt;ul&gt;
		&lt;li&gt;トランザクションが必要かどうかきっちり判断したか&lt;/li&gt;
		&lt;li&gt;ロックする範囲は最小になってるか。デッドロックは起きないか？&lt;/li&gt;
		&lt;li&gt;正規化、非正規化についてしっかり考えたか&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;富豪的になりすぎてないか&lt;br /&gt;
  ハードウェアは確かに速くなって安くなった。でもあらゆることをを富豪的に作っても吸収してくれるほどではない。&lt;/li&gt;
	&lt;li&gt;WebページのHTTPヘッダーは適切にセットされてるか&lt;/li&gt;
	&lt;li&gt;キャッシュ(しない？ブラウザで？proxyで？)のことは考えたか&lt;/li&gt;
	&lt;li&gt;ログファイルのローテーションは正しくしてるか&lt;/li&gt;
	&lt;li&gt;ログファイルの監視はできているか。ただのディスクの肥やしになっていないか&lt;/li&gt;
	&lt;li&gt;テストは正しく書けているか&lt;/li&gt;
	&lt;li&gt;テストは正しく常に実行されているか&lt;/li&gt;
	&lt;li&gt;サーバの監視や異常の際の通知はできてるか&lt;/li&gt;
	&lt;li&gt;エラー処理が正しく出来ているか&lt;/li&gt;
	&lt;li&gt;人間が同じ作業を繰り返さないでいいような自動化ができているか&lt;/li&gt;
	&lt;li&gt;ドキュメントは必要な粒度でしっかり残っているか。更新されているか&lt;/li&gt;
	&lt;li&gt;無駄なドキュメントを作り過ぎてないか&lt;br /&gt;
  などなど&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一つ一つは「わかってる！」ということでも、つい手を抜いてしまうことも多いので、そこをさぼらないということをチームとしてできることを考える。&lt;/p&gt;
&lt;h3&gt;2. 丁寧に正しく作れないなら既存のプロダクトを使う&lt;/h3&gt;
&lt;p&gt;丁寧に正しく作るのにはしっかりとしたリソースが必要。ただし、人やお金というリソースは常に限られているので自分たちが集中しないといけないところをしっかり決めよう。&lt;/p&gt;
&lt;h4&gt;独自フレームワークはやめよう&lt;/h4&gt;
&lt;p&gt;独自のフレームワークは正しく作れないならやめよう。「正しく作る」というのはメンテナンスとか含めて。もし作るなら専用のリソースを確保するぐらいできないと無理。片手間でフレームワーク作りとか無理。外部に向けて公開しても恥ずかしくないレベルのものを作れるようでない限りはやめたほうがいい。&lt;/p&gt;
&lt;h4&gt;独自なスケーラビリティやパフォーマンス向上は最終手段&lt;/h4&gt;
&lt;p&gt;分散やキャッシュなど、プログラマなら誰もが自分ならもっといいものが書ける、書きたい、となってしまいがちだけど、これもフレームワークと同じでできるだけ既存のプロダクトで行くほうがいい。この辺は本当に難しいので、簡単に手を出してはだめ。&lt;/p&gt;
&lt;h4&gt;もう一つの問題点&lt;/h4&gt;
&lt;p&gt;作るのが難しい、メンテナンスが難しい、ということに加えて、もう一つの問題点は、新しく加わった人の教育コストが高くなるということがある。まず、外の資源(ドキュメント/本/Google検索)が使えないので自前ですべて教育をしなくてはならない。また、独自であるが故に、そのフレームワーク等の経験者を採用することもできない。新しく入った人は常に0からのスタートになる。これは立ち上がりのスピードを重視する環境では難しい。&lt;/p&gt;
&lt;p&gt;また、上述したようにリソースが足りなかったりで、その独自に作ったシステムがいまいちの場合、そのシステムに対する新しく入った人のリスペクトが得られないことにも繋がり、その結果その人のモチベーションの低下にもつながる。&lt;/p&gt;
&lt;p&gt;この辺りをすべて背負ってもでも、本当に自分たちで作ったほうがいいのか考えよう。&lt;/p&gt;
&lt;h3&gt;3. システムのモジュール化/疎結合を考える&lt;/h3&gt;
&lt;p&gt;自社で自社システムを開発していると、わかりやすい「開発の切れ目」のようなものが、なかなかないので、どうしても「拡張、拡張」になってしまい、全体的に見ると継ぎ接ぎのシステムになってしまう。その結果、すべてが一枚のモノリシックなシステムになってしまい、部分的に新しいことを試したりするのが難しくなってくる。&lt;/p&gt;
&lt;p&gt;具体的には、8年の歴史の内、5年くらいは、ほぼPHPとFlashで作ってきて、それを2年ほど前から、全面的にRuby on RailsやJavascript/CSSといったものに移行している。正直なところ、結構辛い。サブシステム毎に、別システムにしておいて、それぞれを疎結合(APIとか/DBレベルで結合)するようにおけばよかったかなー、と思っている。そうすれば、部分的に新しい技術で置き換えるのはもう少し簡単にできたのかもしれない。&lt;/p&gt;
&lt;p&gt;もちろん、そういう作りにするとサブシステムそれぞれに、同じようなものをポーティングする必要が出てきたりとオーバーヘッドも大きくなるので、その辺はよく考える必要があるのだけど。&lt;/p&gt;
&lt;h3&gt;4. 技術的負債はできるだけ早く返そう&lt;/h3&gt;
&lt;p&gt;できるだけ丁寧に作っても、どうしても &lt;a href=&quot;http://ja.wikipedia.org/wiki/%E6%8A%80%E8%A1%93%E7%9A%84%E8%B2%A0%E5%82%B5&quot;&gt;技術的負債&lt;/a&gt; はたまっていく。会社が少しでも落ち着いたら負債の返済について考えよう。&lt;/p&gt;
&lt;p&gt;返済を後回しにすると、負債の利子が貯まるばかり。利子はあちこちで発生する。「運用で回避」のコストで払ったり、顧客対応に取られる時間で払ったり、システムに対する信頼の低下ということで払ったりもする。また、緊急の徹夜作業で払ったり、と言った人に負担をかけることで払うこともあるだろう。&lt;/p&gt;
&lt;p&gt;うちでは、少し前から返済に当てる時間を多くとっているのだけど、今思うと数年前にも大きく返済できるタイミングがあったはず。でも、それをやらずに走り続けてしまった。その結果、利子をずいぶん払ってしまった気がする。&lt;/p&gt;
&lt;p&gt;技術的負債を負いつつ、でも走り続け経営がそれなりに安定する。このときに、最低一回は技術的負債の棚卸が必要だろうと思う。全部返済できなくても、利子の高いもからどんどん返済していくべきだろう。&lt;/p&gt;
&lt;p&gt;どうしても、一度落ち着くと、さらに次へと攻めたくなってしまうのだけど、そこで一度振り返ることがとても重要だと今は思っている。&lt;/p&gt;
&lt;h2&gt;サーバ周りの反省点&lt;/h2&gt;
&lt;p&gt;最初に書いたように、データセンタ内に自社でサーバを運用もしている。これにも色々な反省点がある。&lt;/p&gt;
&lt;h3&gt;5. ハードウェアは正しく適正なものを買おう&lt;/h3&gt;
&lt;p&gt;初めの数年間、知識的なことや時間が足りなかったもあり、サーバを購入してそのまま使って、遅くなったらあまり考えずに新しいサーバを追加していた。今思うともったいないことをしていた。「システムが遅い」となったら、何が「遅い」のかを調べ、それに対する効果の高い投資をしよう。&lt;/p&gt;
&lt;p&gt;それと、自分自身、根がケチな上にソフトウェア側の人間なので「そんな高いマシン買わなくていいよ。遅かったらソフトウェア側で頑張るよ」とか思いがちだったのだけどそれは間違い。ソフトウェアでカバーできないこともたくさんある。ケチって中途半端なサーバを買ってしまい、拡張性(メモリやディスクの増設等)が低く、にっちもさっちもいかなくなる、仕方ないのでまた買う、という悪循環に陥る。&lt;/p&gt;
&lt;p&gt;もちろん、割り切って安いサーバをたくさん買ったりするのは別の話だが。&lt;/p&gt;
&lt;h3&gt;6. サーバ周りの人材をしっかり確保しよう&lt;/h3&gt;
&lt;p&gt;上のことをきっちりやるためには、最初から、少なくとも、お客さんが少しでも着いた後は、専任の人を入れたほうがいい。&lt;/p&gt;
&lt;p&gt;最初のうちは、サーバ周りもプログラマ中心にやっていたのだけど、やはりそれには限界がある。本職の人がやるのは、プログラマが片手間でやるのと比べ、深さも広さも全然違う。&lt;/p&gt;
&lt;p&gt;また、プログラマはシステム開発に集中した方がいい。&lt;/p&gt;
&lt;h3&gt;7. クラウドも検討しよう&lt;/h3&gt;
&lt;p&gt;8年前には、選択肢や自由度がなかったのでどうにもならなかったけど、現在では、場合によってもクラウドも検討すべきだろう。もちろんリスクやコストを正しく判断する必要あるけど。&lt;/p&gt;
&lt;h2&gt;組織についての反省点&lt;/h2&gt;
&lt;p&gt;人が大事。チームワークが大事。本当に大事。ちょっとシステム開発からは離れてしまう部分もあるけど、とても関係するところなので。&lt;/p&gt;
&lt;h3&gt;8. いい文化を作ろう&lt;/h3&gt;
&lt;p&gt;これは本当に難しい。自分の中で全然答えが見えない。&lt;/p&gt;
&lt;p&gt;人々の行動が文化を作っているような気もするし、文化が人を作っているような気もする。まあ、好循環が大事なのだろう。先にいる人やチームの行動や習慣は、いい意味でも悪い意味でも新しい人に伝播してしまうので、そこは常に意識すること。成功している企業にはかならずいい文化があるものだろう。&lt;/p&gt;
&lt;p&gt;一度できた文化は、いい文化も悪い文化も継続しやすいことを常に頭に入れる。&lt;/p&gt;
&lt;h3&gt;9. 途中から入ってきた人&lt;/h3&gt;
&lt;p&gt;こういう小さい会社に途中から入ってくる人というのは「今、会社が直面する課題や問題」を解決するために入ってくることが多い。ミッションが明確なだけに、そのミッションを完遂することがその人のプライオリティになるし、その人ももちろんそのつもりで入ってくる。&lt;/p&gt;
&lt;p&gt;もちろん、会社も周りもそれを一番期待している。しかし、期待しているのだけど、組織で動いていると、そのミッションと前からいた人のミッションがデッドロックすることもある。また、会社のリソースは有限なので、その新しく入った人が完遂するのに必要なリソースを必ずしも割り与えられるとは限らない。&lt;/p&gt;
&lt;p&gt;そういう事態になってしまうと、入ってきた人が腐りがちになってしまう。最初からいる人はその辺の事情を汲みとって、現在できる範囲で実現する方法を探すのだけど、途中から入ってきた人はその方向になるのはとても難しい。この辺のサポートがすごく大事。&lt;/p&gt;
&lt;h3&gt;10. 朝礼？ 日報？ 週報？ 社内勉強会？&lt;/h3&gt;
&lt;p&gt;この手の物には否定的だったのだけど、やる意味が多少はあるのかな、と最近は少し思っている。初期の頃はそういうのがなくても情報は共有されるし、士気も高いんだけど、人が増えてくるとどうしても必要になってくるような気がしている。&lt;/p&gt;
&lt;p&gt;この辺は、完全に否定せず、必要な物はどんどん取り入れていきたい。&lt;/p&gt;
&lt;h3&gt;11. 社内の距離感 / 縦割り&lt;/h3&gt;
&lt;p&gt;「途中から入ってきた人」にも関係することなんだけど、最初のうちは全員が同じ方向を見ているのだが、だんだん社員が増え大きくなるに従って、社内で距離感が出てくる。部署毎の損得、面子、プライド。みたいのが出てくる。「こんな小さな会社でそんなこと発生するのがバカバカしい」とか思ってしまうのだけど、人が増えるとどうしても発生してくるようだ。&lt;/p&gt;
&lt;p&gt;特にうちの場合、オフィスがロンドン(開発)、日本(営業/運用)、中国(営業/運用)と分散しているので、元々物理的な距離感がある上に、だんだんと精神的な距離感も出てきてしまった。&lt;/p&gt;
&lt;p&gt;そして、物理的/精神的に離れていると、ネガティブなことはそれでも伝わるのだけど、ポジティブなことは伝わりにくくなっていく。たとえば「この機能かっこいいね」とか「この前のやつ結構お客さんの評判いいよ」とか、日頃のちょっとしたポジティブの感情がとても伝わりづらい。特にうちは非ITな感じの人も多いので、そうなるとなおさら。そうすると結果的に「いつもあいつらは文句言ってる」ということになってしまう。そうしていると、「共通の目的/ゴール」を持つのが難しくなっていく。&lt;/p&gt;
&lt;p&gt;この辺は早いうちに手を打っておいたほうがいい。もちろん、全員が一箇所でできる方法があるならそれがベスト。&lt;/p&gt;
&lt;h3&gt;12. 採用について&lt;/h3&gt;
&lt;p&gt;こういう小さな企業に入ってくれる優秀な人材はなかなかいない。それでも、最初の小さ過ぎる段階では、勇敢な(無謀な？)チャレンジャーが集まる。しかし、ある程度軌道に乗ってしまうと、外から見ると「ただの中小企業」になってしまい、だんだんと難しくなっていくのを強く感じた。&lt;/p&gt;
&lt;p&gt;基本的に、スタートアップ企業にできる人材確保の路線は2つしかないだろう。一つは既にいる社員の紹介、もう一つは技術者が入って楽しい企業ということを外にアピールすること。うちの場合は前者でそれなりに回ってきているのだけど、後者がほとんどできていなかった。&lt;/p&gt;
&lt;p&gt;また、その上で、常に数カ月先を見越して採用活動をしておくことも大事。人は探してすぐ見つかるものではない。&lt;/p&gt;
&lt;h2&gt;最後に&lt;/h2&gt;
&lt;p&gt;上のことは今現在思うこと。&lt;/p&gt;
&lt;p&gt;ただ、ここまでずらずら書いておいてあれなんだけど、これらのことは全部、条件次第でいくらでも変わる。上のはこの8年間で与えられた条件の中の行動に対しての反省点。今後全く同じ状況が現れることは、結局はその場その場で考えぬいて進んでいくしかないのかな、とも思ったりもする。&lt;/p&gt;
&lt;p&gt;そして、それがスタートアップ企業の楽しみ方でもあるのかな。&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;a href=&quot;#fnr1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; ちなみに、次の挑戦の具体的な予定はないし、というか、まだ今の会社で挑戦中！ でも、正直なところ、もう一度何も無いところから自分の力を試してみたいという願望がないことはない。まあ「すべてをやり直したい症候群」はありがちなので、これもそれかなと思ってもう少し今の会社でまだ何ができるか、というのを考え実践するつもり。&lt;/p&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn2&quot;&gt;&lt;a href=&quot;#fnr2&quot;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; SIer的な開発が、作って終わりと言ってるわけではないですが。&lt;/p&gt;</summary><updated>2010-10-19T01:44:45Z</updated><link href='http://blog.madoro.org/mn/84' rel='alternate' type='text/html'/></entry></feed>