Netflix で観た。
予告編を観た時の高揚感はすごかったが突然の恋愛要素と感情移入しづらい主人公たちのために後半には気持ちが失速してしまった。
身近なものを楽器にして演奏するのも街中で演奏するのも誰もが思いつきそうなアイディアだけど、それが"音楽"になるまで作り上げていくのはとてもとても大変なことなので、見事にやってのけたライブシーンはどれも良かった。
数年後にライブシーンだけ見返しそうな気がする。
Netflix で観た。
予告編を観た時の高揚感はすごかったが突然の恋愛要素と感情移入しづらい主人公たちのために後半には気持ちが失速してしまった。
身近なものを楽器にして演奏するのも街中で演奏するのも誰もが思いつきそうなアイディアだけど、それが"音楽"になるまで作り上げていくのはとてもとても大変なことなので、見事にやってのけたライブシーンはどれも良かった。
数年後にライブシーンだけ見返しそうな気がする。
かつての自分と全く同じ気持ちを持った質問者によるurl - What is the etymology of 'slug'? - Stack Overflow('slug' の語源は?)が気に入ったので抄訳。
python - What is a "slug" in Django? - Stack Overflowよりも質問の仕方が良い。
ちなみに今の自分が「'slug' ってなに?」と聞かれて説明するなら「ヒューマンリーダブルな ID」あたりが妥当な回答だろうか。
‘slug’ は特筆すべき理由のない言葉なのか、それともやはり何らかの意味がある言葉なのでしょうか?あるとき私は会話の中でこの言葉を使用したのですが、「なぜ ‘slug’ って呼ばれているのか」と聞かれたときに私も意味を理解してないと気づきました。
もちろんそれがどのように使われているかは知っているのですが… http://codex.wordpress.org/Glossary#Slug
結局、この言葉の背景にはどんな意味があるのでしょうか?
‘slug’ は、新聞業界から来ている言葉です。
これは、制作過程で記事に与えられる非公式の名前、つまりコードネームみたいなものです。記事が担当記者(もしくはそれ以前)から編集者を経て印刷機に至るまでの道のりでの呼び名です。例えば「'kate-and-william' の校正は終わった?」のように使われます。
一部のシステム(Djangoなど)では URL の一部として ‘slug’ を使って記事を特定します。 www.mysite.com/archives/kate-and-william
という具合です。
遡ると脚本の ‘slug lines’ に行き着くかもしれません。この ‘slug lines’ はシーンの背景、つまり、いつ誰がどこで〜などを表現するものです。後に続く文章を説明するものであるという点で ‘slug’ と似ています。
ライノタイプ*1においては、'slug' は個々の文字の形から作られた一本の線の金属を意味していました。1行ごとに単一の ‘slug’ を作ることによって、従来の1文字ごとに組み合わせを作るやり方が大幅に改善されたのです。
これは推測ですが、'slug' はもともとは(何かしらを押印しなければならないような)偽造されたコインのためのものだったのでしょう。言葉の使われ方が印刷用語に至り、そこから「1行の活字」、そして「記事の要約」へと変遷した様子を、私は容易に想像することができます。そうした印刷の世界からオンラインの世界へ移るのはこれまた実に簡単なことでしょう。
*1:ライノタイプは、キーボードを打鍵する事によって、活字母を並べてそれを鋳型とし、それに溶けた鉛を流し込んで、新聞などの印刷版型を作成する装置である。単語や空白から成る横一行を丸ごと活字にする事が出来る。かつては印刷所などにあった。ライノタイプという名称は、Line of type (一行の活字)を省略したものである。 quoted from ライノタイプ - Wikipedia
先週日本にインドネシアのプロダクトマネージャーが来た時に「レビューに時間がかかりがち」「結果として開発のリードタイムが予測しづらくなっている」という悩みを相談してくれた。そのときに「コードレビューを会話しながら行う取り組み - Hatena Developer Blogとかどうですかね、日本のチームでも “レビュー会” ってのをやっていますよ」と伝えようとしたが日本語の記事を渡すのも気が引けたので「あとでまとめておく」ってことにして社内向けに “Encouragement of Review Meeting” という snippet を書いた。
これを日本語でも書き直してみる。
最近プロダクトマネージャーと開発者間でレビューに関してこんな感じの問題があるらしい。
~ ある日 ~
マネージャ「進捗どう?」
開発者「だいたい終わってレビュー待ちの状態かな」
マネージャ「オッケー」
~ 別の日 ~
マネージャ「どう?Pull Request はマージされた?」
開発者「いや、それがまだで…。もう一回 ping してみる」
マネージャ「そうか…どれぐらいかかりそう?」
開発者「うーん、わからん…」
~ 以下、ループ ~
開発者による見積もりがすぐに元々の数字から変わったり、リリース日がずれたり、誰にとっても嬉しくない状況である。
一方、日本の開発者は複雑だったり大きすぎたりする Pull Request を作ってしまったときには “ペアレビュー” や “レビュー会” を設けており、今のところうまく機能している。
そもそもレビューのリードタイムが長くなるのは Pull Request がでかいか複雑か、それに見合う説明が足りてないか、だ。
まず開発者が意識すべきなのは
とはいえでかい Pull Request を作らざるを得ないこともあり、得てしてそれは長い間放置されがちである…。
そうした状況を避けるため、日本の開発者は “レビュー会” というのをやっている。
終わり
Original post:
I recently heard some @quipper/product-managers (or even developers) are troubled with reviewing time. Is the situation like below?
~ One day ~
Manager: “How is your work going?” Developer: “Almost finished, but… it still needs to go through review.” Manager: “Understood.”
~ Another day ~
Manager: “Did your PR get merged?” Developer: “Ah, not yet. I’ll ping them again.” Manager: “Hmm, I see. How long does the review take?” Developer: “Umm, not sure.”
~ To be continued… ~
It’s so frustrating for everyone. Estimation by a developer easily varies from the original one, and its release date does.
On the other hand, Japanese developers sometimes have kind of “pair reviewing” or “review meeting” for a complicated (large) pull-request in person. So far, it works so well that I’d like to share the way.
Most of the review time issues are caused by a large/complicated pull request, and lack of adequate description.
So first of all, developers should
Even though the idea above is right, we are sometimes compelled to implement a large/complicated pull request. And it will have been neglected for a long time…
To avoid such situation, Japanese developers sometimes have “review meeting”.
How?
END
最近「それ開発しなくてもよくないか…?(既存機能の組み合わせとか別の道がありそう)」と思う案件多い気がしていたが、自分がそういう観点でレビューしてるんだと思う
— 広島の粗大ゴミ (@ohbarye) 2017年6月28日
「開発しなくても既存の機能や基盤のうえで提供できる価値はあるし、既存機能を組み合わせて新商品や機能を作り出すこと、またはフィジビリティを行うことも場合によってはできる」…なんだかそういうことを常に念頭において開発するようになり、とにかくコードを書ければそれでよいみたいな気持ちがなくなってきた。
もちろんずっとコードを書いていたいのだが、小さい問題解決のために大きな問題を後回しにするようなコードは書きたくない…という迷いがある。
携わってるシステムがそこそこ大きく、一部はレガシーと呼んでも良さそうな年季が入っているので、無策でこれ以上コードを積み上げていくのに少なからず恐怖心もある。
なぜ迷いや恐怖心があるのか。複雑なものの上に新しい何かを載せてできるのは「ちょっと複雑なもの」ではなく「かなり複雑なもの」になってしまうからだ。
てきとうな式だと「複雑度10 + 複雑度1 = 複雑度15」 みたいなイメージだ。
大げさに言っているようだがこれはあながち間違ってもいなさそう… というのも、最近参加したメンバーからのフィードバックで「当初の見積もりより開発に4倍時間がかかった」というものがあり、理由を聞いたところ「既存の仕様や実装との兼ね合いが開発途中で判明し、当初に想定していたシンプルなものではなくなってしまった」という。
「見積もりが悪い」と責めるのは簡単だが俺はそうは思っていなくて「見積もりが正確にできないほど複雑なものを相手にしている」というのをチームの共通認識として持つべきだと思う。
「複雑だからしょうがない」と言って諦めてもしょうがない。
複雑だからこそ新しいものを1つ足すときには引き算の考えも同時に欲しい。最低でも1つ、可能なら2つでも3つでも同時に引き算することで複雑さを減らしていくしかない。
「何も引くことができない」というような状況の場合、振り返りや分析がきちんとできていない可能性を疑いたい。足す時に理由が必要なように、引くのにも理由が必要だからだ。
もし誰もそのことを気にかけていないなら、足し引きのバランスを担ったり引く理由を追うためのチームがあっても良いぐらいだと思う。
kechol 氏からレビューを受けて知ったのでメモ。
https://google.github.io/styleguide/htmlcssguide.html#type_Attributes によると CSS や JavaScript を読み込むときのタグに type
attribute は HTML5 では不要、というか非推奨とのこと。
Omit type attributes for style sheets and scripts.
Do not use type attributes for style sheets (unless not using CSS) and scripts (unless not using JavaScript).
Specifying type attributes in these contexts is not necessary as HTML5 implies text/css and text/javascript as defaults. This can be safely done even for older browsers.
<!-- Not recommended --> <link rel="stylesheet" href="https://www.google.com/css/maia.css" type="text/css">
<!-- Recommended --> <link rel="stylesheet" href="https://www.google.com/css/maia.css">
<!-- Not recommended --> <script src="https://www.google.com/js/gweb/analytics/autotrack.js" type="text/javascript"></script>
<!-- Recommended --> <script src="https://www.google.com/js/gweb/analytics/autotrack.js"></script>
こういうの、手癖で何も考えず書いたりしてしまう割に頻繁に情報アップデートしてもいないので Google HTML/CSS Style Guide を一通り読んでおいたほうが良さそうだ。
スマートフォンで閲覧する時は改行してほしい。PC では改行してほしくない。
みたいなデザインを実装している時に、同僚の @kechol 氏にレビューで教えていただいたのでメモ
See the Pen Responsive Line Break by Masato Ohba (@ohbarye) on CodePen.
CSS のメディアクエリで改行タグの display スタイルを操作すればよい
『7つの言語 7つの世界』を読みつつ Clojure 入門している。その中でマクロに関する記述があったが LISP のマクロに馴染みがないので、コードを見ても何が起きているのか瞬時にわからなかった。
正解のコードを少しずついじりながら、なぜそう書かないといけないのか、なぜそう書くと動くのかを確かめてみた。
ちなみに例は unless
で、これはマクロ入門でおなじみらしい。
まずは挙げられているダメな例から。
(defn unless [test body] (if (not test) body)) #'user/unless (unless true (println "Lose Yourself")) Lose Yourself nil
body
が評価されてしまっている。test
が false
のとき以外は評価してほしくない。なのでこれがダメなのはわかりやすい。
正規順序でなく作用的順序で評価してしまうと無限ループが発生してしまう例が SICP にもあった(気がする)。
以下のようになるようだ。
(defmacro unless [test body] (list 'if (list 'not test) body))
これをいじってみる。
if
を即時評価していないのはなぜ'if
の部分は以下のように書けるのではないだろうか?
(defmacro unless [test body] (if (list 'not test) body)) (unless true (println "Nothing to tell.")) Nothing to tell. ;; 評価されてしまっている nil (unless false (println "This is it.")) This is it. nil
はい、body
が評価されてしまっているダメ。
(macroexpand '(unless cond body)) body
上記の unless をマクロ展開してみると body
を実行するだけのマクロになってしまっていることがわかる。
not
を即時評価していないのはなぜでは、'not
の部分は以下のように書けるのではないだろうか?
(defmacro unless [test body] (list 'if (not test) body)) (unless true (println "Nothing to tell.")) nil (unless false (println "This is it.")) This is it. nil
一見成功しているように見える…!
だがそれが命取り…!実は駄目…!
上記の unless をマクロ展開してみると条件部が既に評価されてしまっていることがわかる。
(macroexpand '(unless condition body)) (if false body) ;; 条件は false になるのに println が実行されない (unless (= 1 2) (println "This is it.")) nil
正しい unless
をマクロ展開すると条件部がまだ評価されていないことがわかる。
(macroexpand '(unless cond body)) (if (not cond) body) ;; ちゃんと unless 呼び出し時に評価されている (unless (= 1 2) (println "This is it.")) This is it. nil
defn
で書いたらどうなる?(defn unless [test body] (list 'if (list 'not test) body)) (unless true (println "Nothing to tell.")) Nothing to tell. (if (not true) nil) (unless false (println "This is it.")) This is it. (if (not false) nil) (class (unless false (println "This is it."))) This is it. clojure.lang.PersistentList
(list 'if (list 'not test) body)
が評価されてしまった後のリストが返ってくる。body
も評価されてしまっているので println
が実行されている。
評価してほしくないフォームに quote 関数を適用すると評価を抑制できる。
ダメなマクロの例を成り立たせるために body
を'
で遅延評価させられる。もちろん呼び出し側でコントロールしているのでよくない。
(defn unless [test body] (if (not test) body)) #'user/unless (unless true (quote (println "Lose Yourself"))) nil ;; ' 記号でも書ける (unless true '(println "Lose Yourself")) nil
defmacro
は defn
のように関数を定義するが、その戻り値は実行時にコンパイラにマクロとして解釈されるようになる。
(doc defmacro) ------------------------- clojure.core/defmacro ([name doc-string? attr-map? [params*] body] [name doc-string? attr-map? ([params*] body) + attr-map?]) Macro Like defn, but the resulting function name is declared as a macro and will be used as a macro by the compiler when it is called. nil ;; 確かに Macro と解釈されているようす (doc unless) ------------------------- user/unless ([test body]) Macro nil nil