AngularJS x Webpack を使った構成の紹介
AngularJSとWebpackを上手いこと連携させてメンテナンスしやそうな構成を試行錯誤したので、 現状の記録と整理を兼ねて記事にしてみる。
結構いいかんじなアプローチなのではないかと思いつつ、まだ詰め切れていないところも多いので今後ブラッシュアップを重ねていきたい。
関連技術
- AngularJS
- AngularUIRouter
- Webpack
- CoffeeScript
要点
- 役割でディレクトリを分ける
- 汎用化出来そうな仕組みはアプリケーションの外に置く
- DDDを意識してビジネスロジックを構築する
- Webpackのローダーを活用する
- Webpackのrequireをそこそこに活用する
- $injectorを活用する
- Angular UI-Routerの設定をもとにViewのディレクトリを作る
役割でディレクトリを分ける
AngularJSだと controller
, service
, config
, directive
のように機能でディレクトリを分けるのがスタンダードのようだけど、メンテナンスをしているとあっちいったりこっちいったりで結構面倒臭かったり、考えをごっちゃにしがちであまり使い勝手がよくなかった。
そんなわけでJSの役割を幾つかに別けて、それごとにディレクトリを切るようにしてみた。
app/config
- アプリケーションの設定
app/domains
app/views
- 見た目に関する部分、
controller
とtemplate
を内包する - view-modelとdomainを
controller
で連携させる
- 見た目に関する部分、
- 汎用モジュール
汎用化出来そうな仕組みはアプリケーションの外に置く
モーダルやローディングなど汎用的に使え、アプリケーションに依存するものを設定に切り出せるようなモジュールは基本的に app
(アプリケーションの本体)とは別のディレクトリにおく。
外出ししやすくなるし、管理を別けれるので一度FIXすれば後は気にしなくていい。
ディレクティブやView周りのproviderはだいたい汎用化出来そうなので、適当なプリフィクスを振って、 xx-modal
みたいな感じでディレクトリを切ってそこに置くようにしている。
DDDを意識してビジネスロジックを組む
DDDというか、意識していることは以下。
- 単一責務の原則
- 一つのクラスが持つ役割はひとつ
- 複数持つようなら分ける
- Aggregateパターン
- 複数のユーザストーリーを一つのクラスに集約することでViewから参照するクラスを制限する
- しかし責務は分かれてるようにしているので相互影響は最小。最悪クラスの差し替えも想定してる
- Repositoryパターン
いままであまりJavaScriptでOOPを意識してこなかったのだけど、単一責務の原則をしっかりまもって、I/Fをある程度制約かければ結構取り回しが効いて良さそうな感じはする。 ただ、どのくらいの規模までハンドルできるかはちょっと見えてないので、今後の発展を見たい。
Webpackのローダーを活用する
CoffeeScriptのコンパイルはもちろんだが、何より嬉しいのはHTMLをJavaScriptの文字列として展開できること。
これによって、 grunt-ng-template
のようなライブラリは不要になったし、遷移のたびにXHRを投げる必要もなくなった。
UI-Routerと連携しつつ、templateファイルを require
することで文字列をそのままわたせる。
ついでに、viewsのディレクトリの中で controller
とtemplate
を並べせることができて、「controller
とtemplate
はセットで編集したいのにディレクトリの移動面倒!」「ディレクトリ構造違くてわけわかんない」みたいな問題から開放された。
HTMLだけでなく、JSONやYAMLのローダーを使うことで設定などの読み込みも容易になるのでなにかと便利になる。
Webpackのrequireをそこそこに活用する
webpackの拡張requireはあんまり使っていない。 index化したり拡張子の省略が主だけど、これが思いの外使い勝手が良かった。
Webpackのextensions
オプションに拡張子を登録しておけば、以下の様に拡張子を省略してかいた場合、 app.(js|coffee)
あるいは app/index.(js|coffee)
を探しにいってくれる。
var app = require("app");
設定的には、extensions: ["", "coffee"]
とか登録しとくとCoffeeScriptも読んでくれるので便利。
index
ファイルはファイルの機能によって何を書くかをわけている。
View系
exportするのはController。ユーザストーリーの入り口的な意味合いを持たせている。 DDDのAggregate的な扱いをしている雰囲気。雰囲気なのであまり厳密にやってない。
例としては、以下の様な感じ。
- ユーザのサマリを出すページは
user/index.js
- ユーザの所持品を出すページは
user/friend.js
- ヘルプのページは
help/index.js
モジュール系
angularの拡張としてproviderやfactoryを提供する場合。 ドメイン系はだいたいproviderとして提供しているし、汎用的なクラスだったりするとfactoryを提供する。
index
ファイルでproviderやfactoryを定義し、別のファイルにクラスの定義をしている。
例として、ユーザクラスと、ユーザが持ってる友達のクラスを書くとしたら以下の様な構成にする。
+- domains/ +- user/ +- index.js +- user.js +- friend.js
$injectorを活用する
domainsなんかはクラスをたくさん作って、providerでインスタンス化している。
愚直にかくと以下のような書き方になる。
angular.module(module.exports = "user-domain", []).provider ()-> User = require "./user" return { '$get': -> new User() }
requireで呼び出すことはできるけど、例えば $resource
や $q
を使いたいときが結構ある。
呼び出すにしても $injector
呼ばなければならない。
$get
でDIして、コンストラクタに渡す?でも無駄なプロパティは抱えたくない。
そこで、$injector.invoke
を採用した。
こいつを使うと、以下のようにかける。
index.js:
angular.module(module.exports = "user-domain", []).provider () -> return { '$get': ($injector) -> new ($injector.invoke(require "./user")) }
user.js:
module.exports = ($resource) -> class User # Userクラスの定義
DIもクラス側に書けてメンテナンスがしやすくなった。
さらに、$injector.instantiate
を使って、パラメータのバリデーションをしつつインスタンスを生成するようにする。
index.js:
angular.module(module.exports = "user-domain", []).provider () -> return { '$get': ($injector) -> $injector.instantiate($injector.invoke(require "./user"), {}) }
$injector.instantiate
を使うとコンストラクタに渡る値が存在しないときにErrorを投げてくれるので、「うっかり引数変え忘れた!」とかに気付ける。
若干鬱陶しいという気はしつつ、たくさんコードを書いているとどうしても漏れがでてくるのでエラーを投げてくれるのはありがたい。
Angular UI-Routerの設定をもとにViewのディレクトリを作る
state
の構造と views
のディレクトリ構造が合致するのが望ましい。
こうするとファイルをソースを見なくても探しにいけるし、なによりファイル名を決めるときに考えることが少ない。
templateとcontrollerを同じディレクトリにおいているので考える手間が一つになる。
$stateProvider .state "app", abstruct: true controller: require "app/views/app/index.coffee" template: require "app/views/app/index.html" .state "app.user", url: "^/user/" controller: require "app/views/app/user/index.coffee" template: require "app/views/app/user/index.html" .state "app.user.friend", url: "^/user/friend" controller: require "app/views/app/user/friend.coffee" template: require "app/views/app/user/friend.html"
ディレクトリ構成
というわけで、大体以下の様な感じにディレクトリが出来上がる。
+- scripts +- xx-modal/ +- xx-loading/ +- xx-preload/ +- app/ +- config | +- router.coffee | +- resource.coffee | +- xx-modal.coffee +- domains/ | +- user/ | | +- user.coffee | | +- index.coffee | +- friend/ +- views/ +- app/ | +- contents/ | | +- header/ | | +- index.coffee | | +- index.html | |+- index.coffee | +- index.html +- index.coffee
まとめ
AngularJS と Webpackを連携させる事例を紹介しました。 組み合わせて色々便利で管理も楽になっていいよ!
NodeJSでSystemJSを使ってES6を試す
SystemJSとは、ES6やAMD等の汎用的なモジュールシステム。 SystemJSを使うとどんなふうにロードされるのかを試した。
インストール
npm install --save systemjs
基本的な使い方
良い感じローディングするためには初期設定が必要。
require
で呼び出すんだけど、うーん・・・ coffee-script.register()だと思えばまぁ・・・
importの返り値はpromiseなので、exportしている場合は、 .then
で受け取れる。
index.js:
var System = require("systemjs"); System.import("./lib/example"); // ./lib/example.js を読んでくれる
ベースのパスを指定して ./lib
の指定をなくす
baseURL
にURLを指定することでそこを基点にファイルを探査してくれるらしい。
windowsではパスの先頭に file:
の指定が必要とのこと。
index.js:
var path = require("path"); var System = require("systemjs"); System.config({ baseURL: path.resolve("./lib"); }); System.import("example");
node_modulesの読み込み
これまじかよって思った。
index.js
var path = require("path"); var System = require("systemjs"); System.config({ baseURL: path.resolve("./lib"); }); System.map['lodash'] = "../node_modules/lodash/index"; // `./lib` からの相対パス System.import("example");
lib/example.js
import _ from "lodash"; // 相対パスを指定するか、mapに登録する必要がある様子 // any script
まとめ
SystemJSを使ったES6の簡単なサンプルの紹介でした。
npmライブラリはおとなしく require
使いつつ自作ライブラリに関してはimport使うとかするのがいいのかな。
issuesとか眺めながら様子みたい。
EC6のimport及びexportを使いたい
jspm関連でEC6を使おうとしたけど、moduleの管理の仕方いろいろあってどうすればいいのかわからなかったので調べた。 SystemJSを使ってブラウザでもEC6のコードを利用できます。
SystemJSのI/Fで利用
ファイルをimportする
<script src="system.js"></script> <script> System.import("runtime-hoge"); </script>
ファイルをimportして処理を行う
<scirpt src="system.js"></script> <script> System.import("promise-hoge").then((hoge) => { // exportした`hoge`が引数に渡される console.log(hoge); }); </script>
pollyfillを使う
<scirpt src="system.js"></script> <script type="module"> import {hoge} from 'hoge'; console.log(hoge); </script>
Polyfillを使ったmoduleシステムの利用
名前付きでエクスポート
fuga.js:
export var fuga = 'hoge';
index.js:
import {fuga} from 'fuga'; console.log(fuga); // hoge
名前付きでエクスポート
fuga.js:
var fuga = 'hoge'; export {fuga};
index.js:
import {fuga} from 'fuga'; console.log(fuga); // hoge
名前を指定しないでエクスポート
fuga.js:
export default var fuga = 'hoge';
index.js:
import fuga from 'fuga'; console.log(fuga); // hoge
エクスポートしないでcodeだけ実行する
fuga.js:
console.log('fuga');
index.js:
import 'fuga'; // fuga
grunt-contrib-connectのmiddlewareの順序による挙動について
grunt-contrib-connectとgrunt-connect-proxyでstubcellを設定したが POST
や DELETE
のリクエストが method not allowed
で弾かれてしまって嵌ったのでメモ。
middlewareの設定順序が不適切
最初に正しい方法。middlewaresの先頭にproxyを挟む必要がある。
connect: { server: { options: { base: ["htdocs"], middleware: (connect, options, middlewares) -> middlewares.unshift(require("grunt-connect-proxy/lib/utils").proxyRequest); return middlewares; } }, proxies: [ // ... proxyの設定 ... ] } }
middlewares.unshiftする必要性
引数で middlewares
を受け取った時、connect.static
と connect.directoryIndex
のmiddlewareがデフォルトで設定され、それらは GET
, HEAD
, OPTIONS
のMethodしか許可していないため。
今回の僕のような POST
や DELETE
のようなRESTな感じのリクエストを投げたい場合にこれらよりあとにmiddlewareを設定してしまうとプロキシに到達する前に method not allowed
となる。
middlewares.unshift
のように先頭に middlewareを追加するか、 引数で middlewares
を取らず、空の配列から新しくmiddlewaresを生成してしまうかするのが良いと思う。
背景
grunt-contrib-connect
で静的ファイル(htmlとかjsとか)を配信し、RESTFulなAPIサーバーのモックとして stubcell
を立てて、 grunt-connect-proxy
でプロキシしてアプリ開発を行っていた。
が、proxyしているRESTFulなサーバに DELETE
や POST
を投げても 405
のレスポンスが返ってくる。
その時のGruntfileはこんな感じで、middlewaresにproxyRequestをpushしていた。 この時、middlewaresの配列が空の配列であるという錯覚が僕の3時間を無駄にした。
connect: { server: { options: { base: ["htdocs"], middleware: (connect, options, middlewares) -> middlewares.push(require("grunt-connect-proxy/lib/utils").proxyRequest); return middlewares; } }, proxies: [ // ... proxyの設定 ... ] } }
調べた過程
ChromeのdevToolsを見ると、allowのヘッダが某かで付与されていた。 とりあえずmiddlewaresにallowを突っ込むヘッダを付与してみる。
moddleware.push(function (req, res, next) { res.setHeader('allow', 'GET, DELETE'); next(); });
しかし通らない。
stubcellやproxiesのソースを読み、console.logを直で仕込みどこまでリクエストが伝播しているのかを調べているうちに、そもそも grunt-connect-proxy
にリクエストが届いていないことが判明。
grunt-contrib-connect
の某かで405を投げてるっぽい。
grunt-contrib-connect
の中の node-connect
のコードを読むが、 405
を投げている箇所が見当たらない。
検討がまったくつかないけれど、とりあえず障碍の範囲は絞れたので、grunt-contrib-connect
の nextの実装に console.log をかまして様子を見る。
その過程で、どうやら、middlewareがproxyの前に幾つか処理されているらしいことがわかる。
gruntfile上で console.log(middleware)
するとすでに配列にstaticとdirectoryIndexのmiddlewareが入っているではないか!
push辞めてunshiftして解決。
Dartを使ってみる
Dart
- ECMAの標準規格になったらしい
- jsにcompile可能な汎用言語らしい
- javaとjavascriptのいいとこ取りらしい
ってことで試してみる
イメージ
- DartEditorなるものがあるけど、とりあえずvim使ってみる
- Botでも書いてみるかー?
- for web appsな雰囲気あるけど、現状はWEB向きってだけで別にCLIツールでも良さそう
- とりあえず感触を知るところを目的に、いきあたりばったりで。
installation
core
homebrewでdartの1.6.0がインストールできるらしいのでいれてみる。
$ brew update $ brew upgrade $ brew install dart
versionを見てみる。
Dart VM version: 1.6.0 (Tue Aug 26 22:30:33 2014) on "macos_x64"
- dart
- dart2js
- dartanalyzer
- dartfmt
今回はdart-editorいれなかったけど、brew install dart-editor
でいけるっぽい。
vim-plugin
dart-vim-pluginがある。
NeoBundleの設定に追加してインストール。
NeoBundle 'dart-lang/dart-vim-plugin'
...とおもったら、デフォルトだとfiletype認識してくれないので以下を追加。
au BufNewFile,BufRead *.dart set filetype=dart
hello world
hello-world.dart
void main() { print("hello world!"); }
$ dart hello-world.dart hello world
できた。簡単。 ・・・ついでにdart2jsも試してみる。
$ dart2js hello-world.dart Dart file (hello-world.dart) compiled to JavaScript: out.js
out.jsに吐出されたらしいのでひらいてみ・・・・・・・・・
・・・・
・・・・
・・・・そっ閉じ。
next()
とりあえずインストールはしたのでこれからコツコツ勉強してこう。
実際、今まで培ったnpmライブラリの知見を活かせない(dartはdart専用のライブラリを使う)のは大分未練がある。 でもシンタックス的には結構良さそうにも見えるので、今後に期待を込めて続けられたらいいのかなって雰囲気。
npmライブラリを利用できるか、node上でdartをエミュレートできると移行と実験しやすいんだけど・・・。
まあ、ともあれ勉強っすな
CasperJSを拡張したライブラリをローカルに置こうとして苦戦した記録
CasperJSを使っていて大変苦労したのでその記録。
やりたかったコト
CasperJSを継承した独自拡張のライブラリを複数のファイルでrequireして個別にプログラムを実行したかった。
grunt-casperのようなライブラリをから使う場合と、単体のファイルをcasperjs
コマンドで実行する二通りの用途を想定していた。
継承
継承自体は簡単に可能。 coffee-scriptを使っているならなおのこと。
Casper = require("casper").Casepr class MyCasper extends Casper start: -> console.log "start my casper!" super
外部ファイルとしてrequireする
辛かったのはここから。
上記のクラスをmodule.exports
で吐き出し、他のファイルからrequire
で参照しようとした。
"use strict" Casper = require("casper").Casper class MyCasper extends Casper start: -> console.log "start my casper!!" super module.exports = MyCasper
"use strict" MyCasper = require("my-casper.coffee") casper = new Casper() casper.start "https://www.google.com/", -> @echo "open #{ @getTitle() }" casper.run()
上記のようなサンプルコードを用意して、コマンドを叩く。
vimshell% casperjs runner.coffee Error: Cannot find module 'casper' phantomjs://bootstrap.js:289 phantomjs://bootstrap.js:254 in require /home/mizuki/project/casper-sample/my-casper.coffee:8 /home/mizuki/project/casper-sample/my-casper.coffee:29 /home/mizuki/project/casper-sample/my-casper.coffee:30 ReferenceError: Can't find variable: Casper runner.coffee:8 runner.coffee:16
Cannot find module 'casper'
requireしようととしているcasperが見つからない。
bootstrap.js:289
このファイルをまず見に行く。
情報がほとんど無いので、エスパーで回答すると、
- casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
どう見てもずれている・・・
ここからPrintDebugタイムに突入し以下の情報を仕入れた。
- PhantomJSの
require
にpatchを当てている - casperなる(CasperJSに関連した)node_modulesはなく、
patchedRequire
の中でCasperJSのmodules
のディレクトリを見に行くようにになっている
patchedRequire
のコード
casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
その中で呼ばれているcasperBuiltinPath
メソッドがcasperの内部のmodulesさんからcasper
を探してきている。
function casperBuiltinPath(path) { return resolveFile(path, fs.pathJoin(phantom.casperPath, 'modules')); }
さて、ここらへんにprintデバッグのコードを埋め込むわけだが端的に結論を行ってしまうと、 呼 ば れ て い な いのだ。
require先のライブラリの中ではcasperjsのpatchが当たらないらしい。 どういう仕組でそうなっているのかは、PhantomJSも含めて周辺コードを追跡しないといけないので、ひとまずはこの仕組を諦めることにした。
いずれリベンジしたいところである。
余談
ローカルパスの検索
phantom.casperScriptBaseDir
もしくはfs.workingDirectory
を基準にrequire
に指定したパスを走査する。
function localModulePath(path) { return resolveFile(path, phantom.casperScriptBaseDir || fs.workingDirectory); }
casperScriptBaseDirはどこで設定されるのかというと、
- casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
- casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
コマンドラインのtest
サブコマンドを除く第一パラメーターである。
すなわち、下記のrunner.coffee
のディレクトリである。
vimshell% casperjs runner.coffee
今回示した例ならさほど問題はないが、src/runner.coffee
の様なケースだと、若干面倒になる。
これはnodeJSも同様だが、相対パスと実行ディレクトリを意識しなくてはならない。
casperScriptBaseDir
を書き換えることでこの問題を回避することもできるがオススメしない。
Nodeであれば、NODE_PATHを追加することで、そのディレクトリをnode_modulesの走査対象とするが、CasperJSについてはそこまで確認していない。
この辺りのソースを追っていけばヒントは得られそう。 casperjs/bootstrap.js at 4f105a91a0e1d48826d124b2be3627276986fcb9 · n1k0/casperjs · GitHub
ともあれ、非常に苦戦したので、とりあえずその調査の記録だった。
YAPC::Asia 2014に参加してきました #yapcasia
YAPC::Asiaとは
8/29, 8/30に開催された、世界最大規模のプログラミングカンファレンスです。 Perl界隈のエンジニアからPerlは関係ないけど、プログラミングが好きな人が集まる年に一度のエンジニアの祭典!
この記事は
わたしく@mizuki_rの個人的な見解をだらだら述べる記事でございます。 なお、藤沢にある某メイドバーで執筆しているなう。何してんだ、ほんとなにしてるんだ僕。
全体の振り返り
最後のkeynoteのtypesterさんのトークは正直胸に刺さった。 なんだろう、まだうまい言葉に落とせていないような感動具合。 本当にいいトークだった。
通して、自分の立ち回りや今後のキャリアプランとかを改めて考えさせられるスピリチュアルなトークが多かった印象。 同期が二人発表しているのを見て、やっぱりトークしたかったなぁと思う反面 参加してよかったYAPC! 大好きYAPC! スタッフの皆さんお疲れ様でした!
@yusukebe さん大変だとおっしゃっていたけどぜひとも来年も開催を、そして次こそスピーカーとして参加したいw
あ、あと落選したトーク、どこかで話せる機会を作りたいな。
8/29日の振り返り
僕が参加したトークは以下。 真面目なまとめや評価に関しては、技評さんや他のすばらしいエンジニアのブログを参考にしてくれといいな。
あと、量が多いので個人的に興味のある記事だけピックアップしちゃう。
- インフラエンジニア(狭義)は死んだ
- Go For Perl Mongers
- お待たせしました。Perl で BDD を簡単に実践する最高にクールなフレームワークができました
- Perl::Lint - Yet Another Perl Source Code Linter
- WHERE狙いのキー、ORDER BY狙いのキー
- Mojoliciousを使ったwebアプリケーション開発 実践編
- Java For Perl Mongers
インフラエンジニア(狭義)は死んだ
WEBのインフラ系は、物理面を意識することも減ったし、便利なツールも増えてきている。 アプリが動いているのもソフトウェアだし、便利なツールもプログラミングできないと使いこなせない場合も増えている。 この先、プログラミングできないインフラエンジニアは死にそう。
そんな状況で、プログラミングから逃げていた(逃げていたとはもう今は思えない)studio3104氏がどうプログラミングと向き合ってきたのかっていうお話。
「インフラエンジニア」っていう言葉は「プログラミングできない」「プログラミングができなくてもいい」みたいな認識があって、 「インフラエンジニア」ってなのることでそのことを許容しているのではないか? 自称は自意識に影響を与えるというメッセージはすごく僕に刺さった。
僕自身フロントエンドエンジニアという自称の中で、いくつかの責務から目をそらしていた節がある。
与えられた役割、動ける範囲を改めて見直して自称ではなく、自分として何ができるかを改めて考えてみようと思った。
すごい意識の高いトークで一発目からしびれました。
お待たせしました。PerlでBDDを簡単に以下略
tokuhiromさんが書いてきたTest系Moduleの振り返りと、perl6並に夢の詰まったTest::Builder2の開発停止に伴う、じゃあぼくらはどうすればいいんだに対する回答。
それがTest::Kantan 最近のテストライブラリから、言うまでもなく後方互換を保ちつつテストの集計を刷新したunicode文字使ったり色つければウケがいいというフレームワーク。
subtestはテストのコンテキストがわかりにくく、JavaScriptでBDDを主体としたSpecによるテストを行っていた最近の僕としては、 より可用性のあるライブラリっぽい気配がしてもう胸がたかなる。
なお、後輩が試した話によるとサンプルそのままだと動かなくて、describeバグってるぽい? 余裕見て検証したいところである。
Perl::Lint
バグとなりそうな危ういコードを指摘してメンテナビリティの高いコードを推奨しつつレビューの手間を省くツール、それがソースコードリンター。 PBPのポリシーを実装したperlcriticは遅いので、もっと早いのを作りました、というトーク。
Perlの静的解析の手法と、Perl::Lintの使い方の説明をしつつ、いやぁモダンな名前空間だなぁと思っていた。 perlcriticnのカスタマイズはなかなか職人芸な気がしていて手が出しにくい。しかも時間かかるから常にテストと一緒に走らせるには重い。
そんな状況の打開策を提案してくれるモジュールのよう。
独自ポリシーの定義をサポートしつつ、perlcriticのまんまのポリシーを定義している。
独自ポリシーの定義をサポートしつつ、perlcriticのまんまのポリシーを定義している。 もちろん、簡単なポリシーなら簡単にかけるが、難しいポリシーをかくのは難しいというまあそうだよねってところだけど、今後に期待。
なお現在ラスボスのようなポリシーを実装してくれるコントリビューターを募集しているそう。 われこそわという方はぜひ。
僕はjshintを読んで挫折しました。
8/30の振り返り
- オープンソースの開発現場 - Perl 5.20 のSubroutine Signaturesが来るまでの奮闘の軌跡
- 半端なPHPDisでPHPerに陰で笑われないためのPerl Monger向け最新PHP事情(5.6対応)
- ほんとにあったスキーマの話 「ソーシャルゲーム」
- Perlあるある
- Mobile Application Development for Perl Mongers
- そんなにビッグでもないデータ処理手法の話
オープンソースの開発現場
perl 5.20で入ったsignaturesにまつわる議論についてのお話。 個人的にはベストトークショーになってほしいくらいいい話だった。
signaturesの実装を提案し議論を醸したMartini氏の奮戦とその立ち回り、p5pという民主主義のメリット・デメリットはとても興味深いものだった。 perl5は多様な人が居て、多様な意見がある。
そのなかで自分の目指すべきところを正確に見据え、その優先順位を守って、時には受け止め、時には受け流しうまいこと立ちまわることがOSSにおいて大事なのだと感じた。 いろんな人達の日々の努力よって僕らは支えられ、いまこうしてコードを書いているのだと改めて感謝したトークだった。
ちなみにはやくsingaturesを使うの楽しみにしてるぜ!!!
半端なPHPDisで以下略
皆まで言うな、今回のベストトークショーである。 perlのカンファレンスでPHPのトークがベストトークショーともう伝説だよねこれwwww
語るまでもない、PHPのもつ闇としかしその闇と戦うPHPerの強いメンタルを垣間見た。 元PHPerとしては、PHPの変化にちょっと興味をそそられ、たまには弄りたいなと思った。
でもやっぱりPHPはいいかなwwww
Perlあるある
豪華メンツを集めた対談みたいな、Perl初学者向けのトーク。 名を轟かすPerlMongersの赤裸々な素顔に迫るトークだった。
いろいろ名言いただきましたけど、ちょっと個々では割愛。 多くて・・・。
ただ、 「コードを書くのに許可はいらない」 「コードも作文も同じ。読まれて意味の分からないコードは書かない」 「基礎が大事」 「Done is better than perfect」 心に刻みたい。