今更ながらNode.jsでPromiseの使用例
今更ながらこの話題を。使い方を間違えるので、私としては co は非推奨。
Node.js でAPIなどを作成するときに、どうしてもDBアクセス等で callback の利用が多くなります。
特に複雑な業務システム系ならばなおさらです。
また、エラーハンドリングの記述が多くなり、ハンドリング漏れの恐れがあります。
そんな時に「Promise」「then」「catch」を使います。
// こんな感じでPromiseオブジェクトを生成 var promise = new Promise(function(resolve, reject){ // 非同期処理 setTimeout(function(){ try { var result = hoge(); resolve(result); } catch(err) { reject(err); } }, 1000); }); // コールバックに相当する部分 // thenはチェインできるので、上記にそのまま .then で繋げてもOK promise.then(function(result){ //引数はresolveの引数がそのまま渡されてくる console.log(result); }); // reject または エラーが throw された場合に呼ばれる部分 promise.catch(function(err){ console.log(err); });
まずはこれが基本形です。
次にちょっと応用してみます。
var promise1 = new Promise(....略).then(...略).catch(...略); var promise2 = Promise.resolve().then(...略); // 1. 順序を保証して実行 var serial = Promise.resolve().then(function(){ return promise1; }).then(function(promise1_result){ return promise2; }); // 2. 順序に関わらず実行 var parallel = Promise.all( [promise1, promise2] ).then(function(result){ console.log(result); // [promise1_result, promise2_result] });
1.の場合はpromise1の次にpromise2がコールされます。
もし、promise1でエラーが発生して、catchが呼ばれても次の「then」の中にあるpromise2が呼ばれます。
そのため、この「then」は try-catch-finally の finally に相当させることができます。
2.の場合はpromise1とpromise2が順序を問わず実行されます。
片方の終了を待たず、時多重分割でお互いに割り込みのタイミングがあれば割り込みながら実行されていきます。
なお、さらりと出してしまいましたが、以下は同等です。
// 何もせずにresolve()がコールされたPromiseオブジェクト var promise1 = new Promise(function(resolve, reject){ resolve(); }); // 何もせずにresolve()がコールされたPromiseオブジェクト var promise2 = Promise.resolve(); // 何もせずにreject()がコールされたPromiseオブジェクト var promise3 = new Promise(function(resolve, reject){ reject(); }); // 何もせずにreject()がコールされたPromiseオブジェクト var promise4 = Promise.reject();
Promiseで最も重要なのは、thenの使い方です。
例えば、以下のような形。
悪い例
Promise.resolve().then(function(){ Promise.resolve().then(function(){ throw new Error(); }; }).catch(function(err){ console.log(err); });
良い例
Promise.resolve().then(function(){ return Promise.resolve().then(function(){ throw new Error(); }; }).catch(function(err){ console.log(err); });
良い例は then 内で Promise を return しています。
これによって、throw new Error() された際に catch で捕まえることができるようになります。
何が言いたいかというと、以下のような書き方ができるということです。
var conn = null; var transaction = new Promise(function(resolve, reject){ // データベースのコネクションを取得する ConnectionPool.getConnection(parameters, function callback(err, connection){ if(err){reject();} conn = connection; resolve(); }); }).then(function(){ // 何かしらQueryを流して、その後の処理を実行とか return new Promise(function(resolve, reject){ conn.query(...省略) }); }).then(function(){ // 問題なくここまでくればcommit。 if(conn) { conn.commit(); } }).catch(function(err){ console.log(err); // エラーがcatchされたらrollback。 if(conn) { conn.rollback(); } }).then(function(){ // 最後に必ずコネクションを解放する if(conn) { ConnectionPool.release(conn); } });
then の中で reject したい
then の中は Error が throw されれば reject 扱いとなります。
しかし、想定されるエラーや強制的に reject をコールしたい場合は以下のようにしたほうが良いと思っています。
個人的に読みやすいですし、then の中も Promise であると考えると納得感があります。
Promise.resolve().then(function(){ if(err) { return Promise.reject(err); } });
使ってみた感想
co を使えばもっとすっきり書けます。
しかし、co はとりあえず括っておいて、yield 付ければいいんでしょ的な考えに落ちやすくダメコードを書いてしまいます。
例えば、DBコネクションを使いまわしてトランザクションを一気にロールバックしたい時に、function 毎に co を呼んでいることが原因で、上手くエラーハンドリングできないことが発生します。というか、恥ずかしながら私がそうなって泣きながら大量のコードを修正しています。。
それであれば、Promise/then/catchで書いた方が、わかりやすくて個人的に好みです。
[PR] 日本でまともに使えるオープンソースCRMが出ています。
CRM構築はオープンソースのF-RevoCRM -エフレボシーアールエム-
MySQL 5.7.10 の導入は見送ります
MySQL 5.7 になってからオプティマイザが賢くなったとか、かなりの期待感を持っていたため、ローカルや本番用のサーバに入れて検証をしてみました。
結論から言えば、MySQL 5.6 からデグレしています。
ちなみに、全く別件の障害対応に追われているため、原因調査はできていません・・・。
環境
問題1 MySQLのサービスが応答を返さなくなる
- 10テーブル(それぞれ数百万〜数十万件)に対してDelete文を発行
- 結果は数件削除(正しい結果)
- その後から他の接続が全くできなくなる【謎】
- サービスを再起動して、復旧
データを復元して同じクエリを流すと再現します。
また、Delete文だけでなく、Insertや大量にデータがヒットするSelectでも再現。
特徴といえば、それぞれのテーブルがパーティショニングされていることでしょうか・・・。
MySQL 5.6 では再現せず。
問題2 PKを条件に含むexists句の挙動がおかしい
SELECT A.*, B.ID, B.NAME, B.HOGE, C.ID, C.NAME, C.HOGE FROM A LEFT OUTER JOIN B ON (B.A_ID = A.ID AND B.USER_ID = ?) LEFT OUTER JOIN C ON (C.A_ID = A.ID) WHERE ( EXISTS( SELECT 1 FROM D WHERE D.A_ID = A.ID AND D.USER_ID = ? ) OR EXISTS( SELECT 1 FROM E WHERE E.A_ID = A.ID AND EXISTS( SELECT 1 FROM F WHERE F.E_ID = E.ID AND F.USER_ID = ? ) ) ) AND A.ID = ?
※実際にシステムが流したクエリに基づくため、違和感を覚えると思いますが、とりあえず事実を伝えたいのでこれで。
参照権限のチェックをクエリで表現してしまったため、ずいぶんと変なクエリですが、これを実行すると対象レコードが存在するにもかかわらず結果が0件になることがあります。
また、最後の「A.ID = ?」でPrimary Keyを条件にしていること問題のようで、「A.NAME = ?」にして完全一致で名前を入れると対象レコードが取得できます。
面白いのは「D.A_ID = A.ID」のようになっているところを「D.A_ID = ?」などにして「A.ID = ?」で指定している値を入れるとレコードが取得できます。
explainを取っていないとわかりませんが、実行順序で何か問題が起こっているものと思われます。
当然、MySQL 5.6 では再現せず。
# そもそもそんな複雑なクエリをMySQLで流すな、ということかもしれませんが。
安く買い叩く努力をしても損するだけ
ここ数年、腹が立って仕方がないのが、必要以上に安く買い叩こうとする人たちの存在です。
私も上からの命令で時には反発しながらも協力会社、パートナーの方々に対して、執拗な値引き交渉をしていました。
はっきり言って、これほどの無駄はありません。
クオリティが下がり、結果としてコストが上昇する
買い叩こうとすること自体も時間を消費します。
また、それだけでなくクオリティが下がるというデメリットも持ち合わせています。
特にシステム開発の現場ではコストを下げるとクオリティや納期に影響が出ることが多々あります。
要するに安かろう、悪かろうになります。
クオリティが下がった結果、不具合が多発して納期に間に合わないという悪循環に陥ってしまいます。
そうなると追加で発注をしたりするわけで、結果として高くつくことさえ起きています。
信用がなくなる
いくらお互い勉強のためとか、耳障りの良い言葉を並べたところで、あの会社は安く買い叩く面倒な客だと思われます。
現場メンバーは必死にやってプロジェクトを成功に導こうとしても次からはお断りされることがあります。
そもそも利益率の低い、あるいは赤字が出る会社に良い対応をするわけがありません。
やり過ぎは見えないところでお互いの信用問題に発展しています。
自分たちの商材は高く売ろうとする
そういう人たちに限って、自分たちの商材は1円でも高く売ろうとします。
仕事は綺麗事だけじゃありませんが、いくらなんでもおかしいんじゃないでしょうか。
業務システムをオープンソースで使うメリット、デメリット
グループウェア、CRM、ファイル管理などオープンソースを使っていますか?
オープンソースを使うのはリスクがある、とか具体的にどう対策すればいいのかなど分からず採用されないケースが多々あります。
そんなことで、まずは大まかな比較から。
商用とオープンソースの業務システム比較
商用製品、サービス | オープンソース | |
---|---|---|
ライセンス価格 | 人数課金 | 無料 |
保守料金 | 年間ライセンス等に含まれる、または買取ライセンス料金の10〜20%程度 | 1万円/月〜100万円/月など幅広く、保守の手厚さと価格はベンダーによって異なる |
機能 | 多機能 | 多機能、ただし商用と比べて劣るケースが多い(保守契約をしていると有償機能が使えるようになり商用と同等になることもある) |
問い合わせサポート | 保守契約に付帯 | 保守ベンダーと個別契約可能 |
不具合修正パッチの提供 | 保守契約に付帯 | 一般公開されるので契約不要 |
不具合修正パッチの適用作業 | 保守契約内で対応されるものもあれば、スポット対応扱いで別途費用の場合あり | 保守契約内で対応されるものもあれば、スポット対応扱いで別途費用の場合あり |
インフラの外部委託*1 | ベンダーと契約可能 | ベンダーと契約可能 |
導入サポート*2 | ベンダーと契約可能 | ベンダーと契約可能 |
業務コンサル | ベンダーまたはコンサルティング会社と契約可能 | ベンダーまたはコンサルティング会社と契約可能 |
※ベンダーとは開発元(メーカー)あるいはその製品に対して実力のある販売代理店を指します。
一言でまとめると
商用の業務システムは金額が高くなる傾向があるが高機能、オープンソースは安いが商用と比較して機能が少ない傾向がある。
商用の業務システムを採用される理由
安心感
- (多くは)開発元が保守してくれる
- (広告が多く)みんな使っている感がある
- (みんな使っている感があるので)製品が安定動作しそうな気がする
- お金はかかるけど簡易的な業務コンサルもやってくれる
高機能
- 多機能なため、目的以外の用途でも使えることが多いように感じる
お金をそこそも持っている企業は、リスク回避のために商用の業務システムを採用しているように見受けられます。
オープンソースの業務システムを採用される理由
価格
- 何人使っても無料
- インフラ費用、保守サポートなどミニマムの金額で使える
カスタマイズの範囲が広い
- ネット上でカスタマイズの方法を知ることができ、自社内にエンジニアがいれば大規模なカスタマイズも可能
- 自社内にサーバ構築ができるため、共有モジュールやインフラが要因になるようなカスタマイズ制限がない
お金がないから選択されることも当然ありますが、目的の達成が重要であってそれ以外に必要ない経費を掛けない企業が多く採用しています。
カスタマイズの範囲についても記載しましたが、これはあまり採用理由にはなりません。
目的に応じて必要なシステムを選択してほしい
オープンソースの業務システムのメリットは「費用」です。
デメリットは「みんなが使っている感が薄い」という感情的なものや、機能が商用と比べて少ないため、「目的を達成できない、あるいはそれ以外の展開を考えづらい」ことです。
それ以外は商用もオープンソースも差はありません。
実はその事実はあまり知られていません。
それを知っていれば商用ではなくオープンソースを選択する企業が多数存在しています。
一方で、商用でなければ機能不足によって実現できないものもあります。
しかし、ライセンス費用が掛からない分、カスタマイズにコストを割り当てることも可能ですから是非とも相見積を取って比較検討してください。
その上で、公平に判断して今まで以上に賢い選択をしていただきたいです。
[PR] 日本でまともに使えるオープンソースCRMが出ています。
CRM構築はオープンソースのF-RevoCRM -エフレボシーアールエム-
エンジニアは職人になれず、給与を取るか
日本のIT企業ではエンジニアを続けることを否定されています。
昔の職人は生涯職人、死ぬまで技を磨いて非常に高いクオリティのモノを作ってきたと思います。
職人の地位の低下
モノ作りは日本以外でもできることや、品質を問わなければ若い人でも十分にできる現実があります。
また、100%の品質よりも90%、80%でコストを半分、それ以下などで生産した方が価格競争力という、一般的に訴求しやすい形で販売ができます。
そのことにより、一子相伝の技を持った職人よりもコモディディ化した安価な商品を販売する傾向が出たのではないかと思われます。
また、大量生産が求められる部分もあり、一人の職人ではなく大勢や機械での生産が必要になっています。
こうして、安く使える人が求められ、企業内の職人の需要がなくなってしまったと思われます。
エンジニアは職人か?
答えはYesです。
エンジニアは職人であり、経験や知識を蓄え続けることで素晴らしいモノ作りができるようになります。
インターネットなどで情報が集められるようになったとは言え、再利用性の高いコーディング、テストケースの作成、障害対応やそれを未然に防ぐための仕掛けは経験がなければ非常に難しい部分です。
少なくとも私が知る限りでは経験年数とコードの質は比例しています。*1
いつまでも技術トレンドについていけるの?
技術トレンドについていくことは一般的に難しいと言われています。
しかし、根本的な部分は私が知るこの20年ぐらいは変わっていないと感じています。
新しい言語、新しいデザインパターン、新しいライブラリが出てくる中で全てをキャッチアップを続けることは正直困難です。
しかし、特定言語の派生を追いかけることや、それに付帯するデザインパターンやライブラリを追いかけることは容易です。
少し飛躍しますが、自分の得意分野を追いかけることは可能だということです。
結局は概念として他の言語などでも使いまわせるものが多く、自分の得意分野以外でもそれなりについていけます。
ただし、流行などもありますから、得意言語を鞍替えするなどその辺りの柔軟さは必要かもしれません。
マネージャーの方が給与が高いという現実
一生エンジニア、職人でいられないのは給与面も大きく関係しています。
これは会社としても本人としてもあまり良くない傾向があります。
その人が目指す先がマネージャー、経営者であればそれを否定するものではありませんが、エンジニアを続けたいのであればその道もあってしかるべきです。
また、エース級のエンジニアは下っ端エンジニアの数倍の生産性と正確さを持っているため、高い給与を払うだけの価値があります。
例えば、こなれてきた新卒入社3年目のエンジニアよりも、10年エンジニアを続けた人の方が2倍ぐらいの生産性を発揮することがあります。
これは積み上げてきた知識の差や経験によって、一見難しいことでも簡単なものに落とし込むことで生産性につなげています。
しかし、給与を上げていく方法がマネージャーからのステップアップしかなく、仕方なくマネージャーになる人が多く存在します。
なぜ経営者は2倍の生産性の人に2倍の給与を与えないのか
2倍の生産性を「1」と見る人と、2倍の生産性を「2」と見る人がいます。
2倍の生産性を「1」と見る人
例に出した10年目の人が標準と見ています。
ベテランになってようやく会社に貢献できる1人で、それ以外は給与を出来るだけ払いたくないという気持ちです。
生産される質にフォーカスを当てている形です。
職人目指すならメーカー系、給与はSI、人材派遣がオススメ
職人の火をつけやすいのはメーカー系
エンジニアとして、メーカー系とSI、人材派遣のどちらが良いかと言えば、メーカー系の方が好まれる傾向があります。
これは単純に研究開発が行えるため、かなりエッジの効いた技術を習得することができるためだと思われます。
SI、人材派遣の場合は幅広い技術を習得できますが、広く狭くになりがちで職人傾向の人には向いていないと判断されます。
直近の給料を取るならばSI、人材派遣系
最近はSI、人材派遣は人手不足に悩む会社が多くあります。
また、人月単価もリーマンショック以来、底をついていたのが上昇し始めているので給与を高くしても人が欲しいと思っています。
そのため、そのような業界であれば今の給与よりも高い金額で雇ってもらえる可能性があります。
職人を取るが、給与も諦めない
私は今年転職をしました。
細かい話は別の記事で書くとして、結論から言えば受けた会社のほとんどが給与アップの内示をいただきました。
正直、10名以下のベンチャー、零細企業を中心に受けたため、その規模の会社になると上から数えたほうが早い金額になります。*2
とにかくその金額を提示していただいたことは今でも感謝していますし、何よりも自分がエンジニアとして知識を蓄え、技術を磨くことに注力したことが間違っていなかったと感じました。
しかし、今は内示をいただいた中で唯一、給与ダウンの提示をしてきた会社にいます。
これは私がやりたいことを実行できる確度が最も高かったため、そのような選択をしました。
ただ、それと同時にこれからの給与を飛躍させるための選択でもあります。
何が言いたいかというと、エンジニアは続けるし、給与も諦めません。
ただ、私の人生の目標は別のところにあるので、チャンスが巡ってきたら職業としてのエンジニアはやめると思いますが・・・。
[PR] 日本でまともに使えるオープンソースCRMが出ています。
CRM構築はオープンソースのF-RevoCRM -エフレボシーアールエム-
オルタナティブSIは言い訳に過ぎない
最近、納品のない受託開発や定額開発などオルタナティブSIという単語でよく耳にするようになりました。
この言葉に非常に違和感を覚えるのは私だけでしょうか・・・。
結局納品してる
お客様の目的は特定のシステムが欲しいということであって、納品がないというのは語弊であると思う。
結局は何かしらの成果を渡す=納品しているわけだから、納品がないわけじゃない。
納品物を決めていないだけの契約=準委託契約に過ぎない。
要件定義と開発を一緒にしただけ
従来のSIは要件定義フェーズと開発フェーズを完全に分離する傾向がありました。
それが問題となり、オルタナティブSIというものが生まれたと認識しています。
オルタナティブSIはモック作成や実装開始後でも仕様変更が可能になり、最終的にはお客様の最も望むシステムが完成するという構造です。
それに伴って、開発期間が長くなる傾向があるため、SI事業者も安定した収入になりやすいというメリットがあります。
また、大きな点として受注者側は期間で縛られるため、炎上しても責任問題に発展しづらいということです。
大きな案件とかになると、無理やり追加要件をねじ込まれたりするのでそれを対価を貰って実施するために準委任契約の方が都合が良いというわけです。
オルタナティブじゃないSI事情は?
最近では通常のSIであっても、レビューフェーズを細切れに入れることがあります。
いや、最近だけでなく要件定義がきっちりできない炎上しそうな案件に対しては前からありました。
※ただし、経験豊富な営業とプロジェクトマネージャーがいる場合に限る。
とは言え、昔からアジャイル的なやり方を取り入れているわけです。
これはオルタナティブSIが解決したかった問題を解決しているような気がします。
また、追加要件に対策で、初期段階で要件定義書、設計書などに双方の押印を求めるなど応戦しています。
なんとなく甘えもあると感じてしまう
要件定義というフェーズにおいて、発注者側も受注者側も上手くやることができないから「なあなあで済む」定額契約にしましょう、って言っているように聞こえます。
おそらく多くの人がそんな意識は持っていないと思いますが、持つ人が多数現れるのも時間の問題ではないでしょうか。
そうなると、クオリティは通常の受託開発よりも上がるかもしれませんが、コストと納期の面ではお客様にとって不利になってきます。
お互いがちゃんと成長して高品質、低コスト、短期間のモノを作れるようになる仕掛けがあれば良いかもしれません。
高いライセンスを払うな、作った方が安い
CRMって、ライセンス/サブスクリプション費用ってむちゃくちゃ高いんですよね。
例えば、以下のような感じです。
- SalesforceのSales Cloudは1ライセンス15,000円/月*1
- DynamicsCRMは1ライセンス15,000円/月*2
メジャー2社しか載せていませんが、世の中の価格帯はこんなものです。
他社もいろいろありますが、この辺りのレンジで収まっているか、安いものは案件管理が十分にできない、見込み顧客を取り扱えない、請求書を印刷できないなど本当にCRMか?と疑問が湧くほどに機能が少ないです。
30人利用でいくらかかるか
商用CRMを12,000円/月と仮定します。(なんだかんだで値引きもあるでしょうし)
- 30人 × 12,000円/月 × 12ヶ月 = 432万円
3年利用したら、1,296万円です。
100人で利用したらいくらかかるか
この辺りからボリュームディスカウントのレンジに入ってきます。
商用CRMを10,000円/月と仮定します。(30人の時よりも安い)
- 100人 × 10,000/月 × 12ヶ月 = 1,200万円
3年利用したら、3,600万円です。
1,000人で利用したらいくらかかるか
ボリュームディスカウントの割引率が高くなります。
商用CRMを3,000円/月と仮定します。(100人とかよりも激安)
- 1,000人 × 3,000/月 × 12ヶ月 = 3,600万円
3年利用したら、1億800万円です。
受託開発はいくらかかるのか
例えば、オープンソースのF-RevoCRMをベースにカスタマイズを想定してみます。
- 追加機能1つ
- 業務フローに合わせた画面デザイン変更
30人規模の会社が出す要望ぐらいであれば、内容にもよりますが、100万円〜1000万円ぐらいで収まるでしょう。
F-RevoCRM自体が高機能なCRMのため、カスタマイズ量が少なく済む可能性があります。*3
また、オープンソースのため、ライセンス費用はゼロです。
その代わり保守費用が掛かりますが、30名のライセンス費用に比べれば安いです。
そのため、ちょっと欲張ってカスタマイズ費用払っても、3年間の利用ベースで考えれば全然お得なわけです。