ひとりタスクボード
2日目です。
タスク管理について。
僕はこれまでは、おもに Todoist と Google Calendar でやることを管理してました。
Todoist は Toggl と相性がよく、ポモドーロテクニックに向いているのが個人的に気に入っていました。
ただ、最近以下の事情により、ちょっとやり方を変えてみることに。
- 細切れのタスクが増えてきた。
- 細切れのタスクがたくさんある場合、ポモドーロテクニックはあまり効果的じゃない。
- 実際の作業はかなりの割合で PC で行う。タスク洗い出しやステータス変更などの行為を実際の作業を切り分けたい。
というわけで、物理的なタスクボードを使うようにしてみました。何年か前にも使っていたのですが再導入です。
ホワイトボードに区分を用意して、タスクをふせんで貼っていくというもの。区分は以下のとおり。
today
今日やるタスク。
future
いつかやるタスク。
doing
いまやってるタスク。
waiting
他者がボールをもっているタスク。
done
その日に終わったタスク。
よくあるタスクボードは todo / doing / done の3つの区分ですが todo の数が多すぎると優先度がわからなくなる and モチベーションが下がるので today と future で分け、また人に渡したタスクの扱いが所在なくなるので waiting を追加。というアレンジを加えています。
僕はもともとタスクの洗い出しとか何か考える際はプロジェクトペーパーを使っているので、その流れでタスクをふせんに書き出す、というのが自然にやれています。集中するポイントの転換にもなる。
課題は、 future がいつまでも残り続けること。。だいたい7つの習慣でいう第2領域なんですけどね。。
.NET とか Node.js で KeyVault を触る
KeyValult の値をコードから触りたい場合。
.NET の場合
こうする。
var client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(new AzureServiceTokenProvider().KeyVaultTokenCallback)
App Service からは MSI で認証しにいく*1。ローカルなら、Visual Studio が Azure で認証した内容が保存していて、クライアントを new するときに勝手にその情報を使いまわしてくれる。
.NET を使用した Azure Key Vault に対するサービス間認証 | Microsoft Docs
あとは client.
で Tab ポチポチしたらだいたいわかる。 VS 最高。
Node.js の場合
npm から azure-keyvault
をインストール。
npm i azure-keyvault
インポート。
import msRestAzure = require('ms-rest-azure'); import KeyVault = require('azure-keyvault');
App Service からは MSI で認証する。環境変数に MSI_ENDPOINT
とか MSI_SECRET
とかが入ってるのでそれを参照できる。
const client = await msRestAzure.loginWithAppServiceMSI({ msiEndpoint: process.env.MSI_ENDPOINT, msiSecret: process.env.MSI_SECRET, resource: 'https://vault.azure.net' });
ローカルの場合。こちらは VS / .NET のときと違って、勝手に解決してくれない。
interactiveLogin
を使って画面からインタラクティブにもやれるが、バックエンドを想定するとこう。 Azure のログインユーザー名とパスワードを生で環境変数にセットする、というのは良い気分ではないが((CLI から az login
した認証情報を使いまわせたりするのかな))。。。
const client = await msRestAzure.loginWithUsernamePassword(process.env.KeyVaultLocalUsername, process.env.KeyVaultLocalPassword);
というわけで、合わせてこうなる。
const client = new KeyVault.KeyVaultClient( process.env.MSI_ENDPOINT ? await msRestAzure.loginWithAppServiceMSI({ msiEndpoint: process.env.MSI_ENDPOINT, msiSecret: process.env.MSI_SECRET, resource: 'https://vault.azure.net' }) : await msRestAzure.loginWithUsernamePassword(process.env.KeyVaultLocalUsername, process.env.KeyVaultLocalPassword));
Secret にセットするときはこんなかんじ。すでに存在したらバージョンが increment される。
const result = await client.setSecret('VAULT_URL', 'SECRET_NAME', 'SECRET');
result
の中身はこんなかんじになる。
{ value: 'SECRET', id: 'https:\\KEY_VAULT_NAME.vault.azure.net\secrets\SECRET_NAME\VERSION', attributes: { enabled: true, created: 2018-09-04T07:03:25.000Z, updated: 2018-09-04T07:03:25.000Z, recoveryLevel: 'Purgeable' } }
膝上キーボード
ここ半年くらい、仕事中はキーボードを膝上に置いている。
板状のものはこれ。
イーサプライ 膝上テーブル ノートパソコン タブレット 15.6インチ ラップトップテーブル 木目調 EZ2-HUS006
- 出版社/メーカー: イーサプライ
- メディア: オフィス用品
- この商品を含むブログを見る
なぜかというと、机の上に手を置くのは疲れるから。何を言っているんだという人は一度ためしてみてほしい。明らかに肩が楽。膝の上に手を置くという、座ったときの正しい姿勢に近いのだから当然だ。
だが運用するまでわからないデメリットもある。
まず、数字/記号キー、Fnキーが全然あたらない。ディスプレイとキーボードの距離が広くなり、キーボードを見ようとすると首を動かす必要が生じるのだが、これまではこれらのキーを無意識のうちに目で確認していたようだ。全然ブラインドタッチできてない。これは結構ショックだ。
続いて、マウスが使いづらい。TrackPointに命を捧げている人なら問題ないのだが、ご覧の通りこの板ではマウスが乗らないのでマウスだけ机の上に置いている。普段はTrackPointで済むものの、図を描いたりするときはちょっと困る。
最後に、傍から見るとただ椅子に座ってるだけで仕事していないように見えるということだ。特に正面からだと手が見えないので大変だ。
ワイヤレスキーボードだったら膝上と机上を自由に行き来できるので、たまに切り替えるというのもでき良さそうだ。そのうち変えようかな。
Table Storage でバッチ処理
Azure の Table Storage を .NET から扱う場合は Microsoft.WindowsAzure.Storage
1 が利用できる。その中でバッチ処理についてメモ。
単一のテーブルにバッチ処理を行いたい場合は TableBatchOperation
クラスを使う。
var entities = GetEntities(); var operations = new TableBatchOperation(); foreach(var entity in entities) { operations.Add(TableOperation.Add(entity)); } await table.ExecuteBatchAsync(operations, cancellationToken);
Atomicity は担保されているらしい。なので 1 件でも失敗したらロールバックされるような動きになる。 参考
パフォーマンスもこの方がいいらしい。
また TableBatchOperation
は IList<T>
の実装なので実行順序は保証されている。はず。よね?
注意しときたいのは、このとき entities が空だと ExecuteBatchAsync
で空振り......ではなく StorageException を吐く。 TableBatchOperation
にオペレーションを詰める前に分岐させてスキップしておくのが良さげ。
var entities = GetEntities(); if(entities.Length > 0) { var operations = new TableBatchOperation(); foreach(var entity in entities) { operations.Add(TableOperation.Add(entity)); } await table.ExecuteBatchAsync(operations, cancellationToken); }
また、 1 バッチオペレーションでは Insert / Delete 同時に実行できるが、同一エンティティを Insert / Delete しようとすると死ぬ。意図的にこんなことをしようとすることはないだろうけど、結果的にそうなっちゃったってことは起こり得るかも。
try { var operation = new TableBatchOperation { TableOperation.Insert(new UserMappingSet {PartitionKey = "hoge", RowKey = "fuga"}), TableOperation.Delete(new UserMappingSet {PartitionKey = "hoge", RowKey = "fuga", ETag = "*"}) }; await table.ExecuteBatchAsync(operation, cancellationToken); } catch (StorageException ex) { // "1:One of the request inputs is not valid. ..." log.Error(e.RequestInformation.ExtendedErrorInformation.ErrorMessage) }
なお複数テーブルに対するトランザクション処理的なものは用意されていない。 Entity Group Transactions というのが使えそうな気配がするが、少なくとも SDK にそれっぽいものがなく、 REST API 専用なのかな?
-
.NET を使用して Azure Table Storage と Azure Cosmos DB Table API を使用する | Microsoft Docs によると 「
Microsoft.Azure.Storage.Common
を使え」らしいが、 NuGet で落とそうとすると preview しかなかったりして謎。↩
フロントエンドのビルド周りを触った
半年前になるが、年末から年始にかけて業務でフロントエンドのビルド周りを初めてがっつり触ったのでメモ。最新技術みたいな話は特に無いのであしからず。
(この「フロントエンドのビルド周り」を表す言葉って無いんだろうか)
今回書くこと
- JavaScript
- Babel
- Cache Busting
- CSS
- SCSS
- Cache Busting
- bundle
今回書いてないけどやったこと
- vue component のビルド
- svg を Web フォントにビルド
- あと Cache Busting
簡単に用語の説明
Babel ?
Web ブラウザは ECMAScript という規格に準拠して JavaScript の動作環境を提供していますが、 ECMAScript にはバージョンがあり、ブラウザによってどのバージョンまで対応しているかが異なります。代表的なところでは、ES6 は Chrome / Firefox / Edge / Safari などメジャーなブラウザでは動作しますが Internet Explorer 11 では動作しません。当然新しいバージョンに従って記述できたほうが開発者としてメリットがあるわけですが、できれば多くのブラウザをカバーしたい。そういう場合に、新しいバージョンで記述された JavaScript を古いバージョンでも解釈できるように変換 (transpile) してあげるツールが Babel です。
運用としては、開発時は新しいバージョンで記述された JavaScript をソース管理し、デプロイ時に何かしら自動化ツールによって Babel をかけたものを public なディレクトリに配置する、という流れになります。
SCSS ?
CSS は辛い。その辛さを軽減させた言語です。具体的には変数が使えたり関数っぽいものを書けたり子孫セレクタをネストさせて書けたり等。Babel を使用する場合のように .scss
ファイルをバージョン管理してデプロイ時に .css
に変換します。似た言語として LESS や Stylus などがありますが、いまのところは Sass 一強 のようです。
Cache Busting ?
JavaScript や CSS などの静的ファイルは、無駄なリクエストを減らすためにクライアントのブラウザにキャッシュさせる戦略をとることが多いです (Web サーバーやブラウザーの設定に依存します) 。このとき、サーバー側でファイルの中身を変更したのにクライアント側にキャシュが残っており、表示が崩れたり JavaScript でエラーが発生する、ということが発生します。これを防ぐため、ファイルが変更されたときにキャッシュを破棄することを Cache Busting と呼びます。よくやる手段 (というか他の手段を知らないのですが) は、ファイル名やクエリ文字列に日付や revision などを付与して URI を変えることで、クライアントに新しいファイルであると認識させてあげる、というものです。
Build System / Task Runner
上述のように、これらを実行するためには開発したものを変換してからデプロイしてあげる必要があります。これを実現するためのツールは Gulp や Grunt などがあり、ビルドシステムやタスクランナーなどと呼ばれています (この呼び名の差異がよくわかってない、、) 。 Grunt の方は開発が止まっており (なぜか 2018/02/07 に約2年ぶりに小さな update がありましたが) 、これから始めるのであれば Gulp の方がよさそうです。ただし、近年は「そもそもタスクランナーいらなくね? npm scripts
で十分じゃね?」という動きもあり、要注意です。
あらかじめ変換のためのスクリプトを記述しておき、コマンドから gulp
などで実行します。あるいは gulp --watch
としておくと都度コマンドを実行せずともファイルを保存したときにスクリプトが走るので、開発時はこちらを使用したりします。
JavaScript でやったこと
gulpfile.js
で以下のようにします。 gulp-babel と gulp-rev を通しています。これにより、 script
にいた .js
ファイルが変換されて public/scripts
に配置されます。各種プラグインは npm -i --save-dev
で入れときます。
const gulp = require('gulp'); const plumber = require('gulp-plumber'); const babel = require('gulp-babel'); const rev = require('gulp-rev'); gulp.task('babel', function () { return gulp.src('./scripts/*.js') .pipe(plumber({ errorHandler: makeErrorHandler(err => err.toString()) })) .pipe(babel()) .pipe(rev()) .pipe(gulp.dest('public/scripts')) .pipe(rev.manifest()) .pipe(gulp.dest('public/scripts')); });
Babel の設定はルートの .babelrc
に書いておくと勝手に読み込まれます。
{ "presets": ["es2015"] }
gulp-rev は何をしてくれているのかというと、 [元のファイル名]-[ハッシュ値].js
といった名前に変換し、そしてその対応表を rev-manifest.json
として生成してくれます。ハッシュ値は実行の度に変わります。json の中身はこんなかんじ。
{ "js/unicorn.js": "js/unicorn-273c2c123f.js" }
これをサーバー側で読み込んで、変換後のファイルを拾います。たとえば Node.js であれば
let revision; app.all('/*', function(req, res, next) { if(!revision) revision = JSON.parse(fs.readFileSync('rev-manifest.json', 'utf-8')); res.locals.revision = revision; next(); });
としておいて、view (ejs) で
<script src="/scripts/<%= revision['index.js'] %>"></script>
のようにします。
CSS でやったこと
CSS は Gulp -> Webpack -> SCSS トランスパイル という感じにしました。
......なんでこうしたか覚えてないんですけどね。。たしか js も Webpack にしたかったけどエントリーポイントを複数に指定しようとしてうまくいかなかったとか、そんな感じだったと思います。
Webpack
Webpack はいろんな機能があるので他のツールと並べて説明しづらいのですが、たとえば複数の css ファイルを一つにまとめる (bundle) 、スペースや改行などを削除してファイルサイズを小さくする (minify) 、さらにプラグインを入れて Babel や SCSS トランスパイルをかける、といったことも可能です。設定は JSON で記述します。コマンドから実行もできますし Gulp から呼ぶこともできます。
gulpfile.js
で以下のようにします。やはり gulp-rev
で Cache Busting を図ります。
const webpackConfig = require('./webpack.config'); const webpackStream = require('webpack-stream'); const rev = require('gulp-rev'); gulp.task('ws', function () { return webpackStream(webpackConfig, webpack) .on('error', makeErrorHandler(err => undefined)) .pipe(rev()) .pipe(gulp.dest('public/bundles')) .pipe(rev.manifest()) .pipe(gulp.dest('public/bundles')); });
webpack.config.js
で以下のようにします。 gulpfile.js
の中に直接 JSON を書いても構いませんがファイルの肥大化は避けたいところ。 style-loader
css-loader
sass-loader
は npm i --save-dev
で入れておきます。
var glob = require('glob'); module.exports = { entry: { css: glob.sync('./scss/*.scss') }, output: { path: `${__dirname}/bundles/`, filename: '[name].bundle.js' }, module: { rules: [ { test: /\.scss$/, loaders: [ 'style-loader', 'css-loader', 'sass-loader' ] } ] } }
gulp ws
を実行すると、 /scss
の .scss
ファイルが CSS にトランスパイルされ、更にバンドルされて css-[ハッシュ値].bundle.js
として 1 ファイルにまとまります。
ざざっと書いてきましたが、時間が無い中ゴリ押しで進めたプロジェクトだったので、技術選定にあまり時間を割けなかったのが正直なところ。かつ、このへんの情報を Web で調べようとすると、個別の技術については見つかるのですが横断的にまとまってる記事が少なく、いろいろ案件こなしてアンチパターン踏んでいかないと感覚が身につかないだろうなぁと思っています。
シベリウス 交響曲第2番 第2楽章 の無慈悲さ
まず、このシンフォニーは第1楽章冒頭で奏でられる、上昇する3つの音がモチーフとして全体を支配している。第2楽章も例外でなく、ファゴットの第1主題もこのモチーフから始まる。
たぶん、この楽章で上昇形は希望、下降形は絶望を描いている。冒頭は無感情に始まるが、次第に上昇 vs 下降の図式になり、混沌としてくる。希望と絶望どちらが正しいのか?金管のコラールはこれが一体化し非常に狭い幅で上昇と下降を繰り返す。頂点にたどり着いたと思ったら、ホルンによるフレーズの終わりは半音下降というなんとも後味の悪いものだ。
しかし、続く第2主題は一転、救いの音楽になる。美しい旋律に、木管楽器による天使のような上昇音形。そしてなんと、下降形のモチーフが明るく長調で奏でられる!もしかしたら絶望なんてなかったんじゃないだろうか?
それでもやはり、希望を信じきれない。第1主題がより感情的に再現される。疑いは続く。絶望感を帯びたままの第2主題。先ほど長調だった下降形も、今回は短調になってしまう。木管楽器の上昇音形も顔を出さない。
しかし、もうこれぞシベリウスといった調子で低音厚めの弦楽合奏が上昇下降を繰り返し、ひたすら祈る。そしてやっと、再び下降形が明るく、トゥッティで登場する。よかった......!!
という安心も束の間。チェロやヴァイオリンによる不吉なフレーズ。木管楽器が、そんなはずはない!と僅かに上昇。しかしこれも弦楽器に激しく否定される。木管も下降。そして最後は、上昇音形すら、悲しく、短調で奏でられてしまう。信じてたのに。嘘だったのか。
というわけで、第2楽章は何の慈悲も無い。
しかし、それを踏まえて第4楽章を聴くともう余計嬉しい。フィナーレは上昇する3音のモチーフをひたすら信じる。死ぬほど長い第2主題はモチーフと全く切離されたものだが、それでも信じて、モチーフに頼らずに、絶望に勝利する。それを、コーダでモチーフが称えてくれる。しかもここで、なんとずっと3音で奏でられていたモチーフは第4の音に到達する。このカタルシス!!
いやー、いい曲だ。
なお、シベ4になると全曲を通して無慈悲である。。
ホルンのウォームアップ
週末ホルニストは(ホルンに限らないだろうが)、合奏前の短いウォームアップでいかにベストコンディションに近づけられるかが重要です。
ウォームアップで重要なのは、音を出すことで体を暖めること。そして、自分のコンディションを確認すること。
集中力を欠いてダラダラと「いつものメニュー」をこなしてしまうと、合奏中もなかなかコンディションが上がらず、その日の合奏をムダにしてしまいかねません。
というわけで自分がふだんコンディションのどのポイントを確認しながらどんなメニューに取り組んでいるのか振り返ってみます。これは自分への戒め、再確認でもあります。
ロングトーン
内容
真ん中の C からスタート。音量はmfくらい。F管で、4拍伸ばしたらスラーで半音下がる。下がって4拍伸ばしたらブレス。次は下がった音からまた4拍伸ばし、スラーで半音下がる......これを繰り返す。下の音がFに達したら終了。
確認すること
- 息を適切に吸えているか?
- 量は十分か?
- 横隔膜、およびその周りの筋肉がスムーズに動くか?無理してないか?
- タンギングがスムーズか?
- 音の出だし、空気が唇を抜けはじめる感覚はどうか?
- 唇が心地よく振動しているか?
- 息を適切に吐けているか?
- 音程、音量が揺れていないか?
- 腹筋はどうか?同じ息の量を保てているか?
- アパチュアは一定か?
- 唇の振動は一定か?
- スラーはスムーズか?
- 息の向きを無理やり変えていないか?
- 唇の振動がスムーズに切り替わっているか?
- 指の動きと息のコントロールがシンクロしているか?
- 腕の筋肉の使い方が適切か?
- 右手の角度はどうか?上腕二頭筋が無理していないか?
- 左胸が無理していないか?
リップスラー
内容
F C A C (ブレス) F C A F を1セットとして、半音ずつ上げていく。音量は f 。フルブレスで。
確認すること
- 息を適切に吸えているか?
- ロングトーン後なのでより吸えるようになっているはず。無理なくフルブレスできるか?
- 息を適切に吐けているか?
- f に唇、腹筋が耐えられるか?
- スラーはスムーズか?
- 音が途切れるよりは間に音が入ったほうがいいが、思いどおりに切り替わるか?
- アンブッシュアは一定か?
- 唇、息の向きが無理していないか?
- 音量は適切か?
- 音によって音量が変わったりしないか?
ロングトーン再び
内容
真ん中の C を ff で伸ばす。
確認すること
- 息を適切に吸えているか?
- まだ油断しない。
- 息を適切に吐けているか?
- 横隔膜が一定のスピードで動くか?
- 唇が適切に振動しているか?
- アパチュアが広くなり、ここまで振動しなかったところが振動するようになっているはず。その振動が無理していないか?
ハイトーン
内容
五線の中の F からスタート。8拍くらい伸ばし、半音ずつ上げていく。上のFに達したら終了。
確認すること
- 息を適切に吸えているか?
- 細くなっていないか?
- 唇の周りの筋肉はどうか?
- 無理していないか?しっかり引き締まっているか?
- アパチュアが適切か?
- 狭いアパチュアに心地よく息が通っているか?
- 顔全体の筋肉はどうか?
- 眉毛を上げたりして、こめかみあたりの筋肉がほぐれているか?
ざっと挙げてみましたが、まだまだある気がする。。
あと、タンギングのメニューを取り込んでもいいかも、と思った。
思いついたらまた書いてみよう。