bussorenre Laboratory

bussorenre Laboratory

windows subsystem for Linux で 困ったこととその解決法

「この記事は個人の見解であり、所属する組織の公式見解ではありません」

5月8日、4月には結局間に合わなかった Windows 10 Redstone 4 のアップデートが配信されました。Redstone におけるメジャーバージョンアップは従来のService Pack 並の大きな変更ですが、その中でも特に WSL, Windows subsystem for Linux における機能拡張に着目して、WSL で どこまで出来そうか確認します。

Redstone 4 における最も基本的でかつ重要な変更として、パーミッション管理が多少改善された事にあると思っていています。特に(visual studio Code 等でコードを編集するために)、WIndows 側のディレクトリにローカルリポジトリをおいていた場合、今までは ユーザー root, グループ root, パーミッション777  になっていたと思います。これが少しはましになりそうです。

今回利用するのは WSL の中でも Ubuntu 18.04 を利用します。いつになったら RedHat がリリースされるのか。笑

Windows Update を手動チェックし、更新をインストールする

Windows をゲーミング用途以外で触るのは本当に久しぶりです。 早速 Windows Update をかけます。時々アップデートを無視してしまうことがあるので、Cortana で「Windows Update」 と入力し、強制的にアップデートをかけます。ついでにWindows Defender の定義ファイルも更新しましょうね~。結構時間かかります。

終了すると必ず再起動を求められるのでお忘れずに。

古いWSL環境を削除する

必ず CMD.exe から管理者モードで 以下のコマンドを実行します

lxrun /uninstall /full /y

これにより、現存するUbuntu 環境が消えます。もしエラーが実行できない場合は、よくわかりません(※ なんでエラーになったのかわからないのですが、特に気にせず次のステップにすすめました)。 なので、無視して次に進めて大丈夫です

Windows Store から Ubuntu 18.04 をインストールし、普通に起動します。 ユーザー名、パスワードを設定できるので設定します。

umask の設定をする

まず、デフォルトの状態でディレクトリを作ると、パーミッションが 777 になっていると思います。(なっていないならこのステップは無視) vim かなにかで .profile を開き、以下の行のコメントを解除します

#umask 022

コメントアウトしたら source .profile で再度読み込みを

windows 管理下のディスクにLinuxパーミッションを付与できるようにする

Windows が採用しているファイルフォーマットNTFSには、Linuxパーミッションを保存することが出来ないので、アダプターとなるファイルシステム drvfs にメタデータを付与するオプションを付けて、再度マウントする

# C がすでにマウントされているなら、一度アンマウントする
$ sudo umount /mnt/c

# metadata オプションをつけて再度マウントする
$ sudo mkdir /mnt/c
$ sudo mount -t drvfs C: /mnt/c -o metadata

これにより、windows 側のフォルダも、パーミッションが付与できるようになる。やったぜ。 ところがこれ、大きな落とし穴があり、windows 側でファイルを更新すると、なんとパーミッション等のメタデータが破壊されてしまう。なんでやねん!!!笑

というわけで、マウント時にデフォルト値を設定してあげることで、windows 側でファイルをいじっても元通りっぽいパーミッションになることができる。

$ sudo mount -t drvfs C: /mnt/c -o metadata,uid=1001,gid=1001,umask=22,fmask=111

↑の例だとC 全体をマウントしているので、workspace などのみをマウントして利用するのが安全そう

$ sudo mount -t drvfs 'C:\workspace' /mnt/workspace -o metadata,uid=1001,gid=1001,umask=22,fmask=111

その他 windows 環境での作業改善をする

個人的にはMac のctrlキーが Aの左にあるの、すごい気に入っていたので、ctrlキーを A の左のキーに割り当てます。windows 標準JISキーボードは大体左にcapslock があるんじゃないでしょうか。 フリーソフトでいじることも可能ですが、変なソフト入れたくなかったので直接レジストリをいじります。

cortana に regedit.exe と入力します。

細かい方法は参考記事に載っていますが、capslock を 左ctrlに割り当てるには

  • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layoutを開く。
  • 右クリックして→「新規」→「バイナリ値」を作成して、名前を「Scancode Map」にする。
  • Scancode Mapを開く。
  • 以下のように値を設定する。
0000 0000 0000 0000 
0200 0000 1D00 3a00 
0000 0000

で実現できます。1d00 というのは、ctrl キー 0x1d のリトルエンディアン2バイト記法のため

さて、これで多少は使えるようになりました。 次は実際に快活環境を入れて、開発動かしてみるか……

参考にした記事とか

コンテキストスイッチにどうやって立ち向かうか

「この記事は個人の見解であり、所属する組織の公式見解ではありません」

またこいつは炎上しそうな記事を書いて……と自分で思いましたが、真剣に悩んでいるので人の目に触れる所に置いて意見を貰うことにしました。

本来、コンテキストスイッチとはCPUが複数プロセスを並行して動かしているように見せるために、CPUやメモリの状態を入れ替え差し替えする機能の事を指しますが、この記事では、1人の人間が、文脈の異なるの業務を並行的にこなさなければならない状況で発生する、脳内での業務の切り替え の事を意味します。

前提のお話

コンテキストスイッチにはコストが掛かる

まず、前提として、コンテキストスイッチには、スイッチングコストがかかります。

例えば、1人の人間(P)が100 の業務量をこなせるとします。(単位はまぁ概念的なものなので適当に想像してくれ)

上司は部下にあれこれ仕事を割り振るのですが、その中でも、A-E の業務に着目し、業務量を見積もると、だいたい以下のような感じでした。

A = 70
B = 40
C = 30
D = 20
E = 10

この時、P さんに任せる仕事として最適なのは どういう組み合わせでしょうか?

単純に計算すると、 A + C = 100 だったり、 B + C + D + E = 100 だったりするので、そういう組み合わせが良いと思うかもしれません。

しかし、ここには「人間はコンテキストスイッチングに多少なりとも時間がかかる」という条件が考慮されていません。

例えば、月から金まで働くとして、月火水 は A という業務に着手し、木金は C という業務に着手する。その間に業務の切り替え(コンテキストスイッチ)の発生回数は2回で、(A からC への切り替えと、C からAの切り替え。厳密にはC からA は土日を挟むので発生しないかもしれないがそれはさておき) コンテキストスイッチにだいたい1の業務量を要する。

とすると、A とC のタスクをアサインされている人の業務量は 70 + 30 + 2 = 102 になるわけです。ちょっと残業ですね

では、B + C + D + E = 100 の業務を持つ人が 1回のコンテキストスイッチにかかる業務量を1 として、必ずB, C, D, E の順番で業務を実行していくとどうなるか?というと、業務量は105 になります。

じゃぁ実際に105か?と言われると、そんなことはないです。

例えばBの仕事を実行している時に急遽Eの仕事のクライアントから緊急の電話が掛かってきたりすると、一旦Bの手を止めてEの頭に切り替えなければなりません。要件がすめばまたBに頭を戻せば良いわけですが、この時コンテキストスイッチが2回発生しています。

業務量が更に増え、107 になりました。こうして、残業が増えていくんだなー。

大きな集中力が必要な業務

アートの製作や、複雑なロジックの実装、MVPの検討など、非常に高度な集中力を要する業務というのが存在します。例えば40 の「集中力が必要な業務」の進行中に、だいたい20まで進行したところで、上記のようなクライアントからの緊急の電話等でコンテキストスイッチが発生すると、頭がリセットされて最悪0 からになるかもしれません。0までいかなくても、「で、ええっと何の話をしたんだっけ?ああそうそう」というロスタイムが生じる経験は誰にでもあると思います。同じ議論をやり直しているかもしれない。

集中力が必要な業務中に、コンテキストスイッチが発生しないようにする工夫は必須です。

コンテキストスイッチが発生しまくる現場では、こうした集中力が必要な仕事はなかなか手がつけれません。無理です。

みんな1人月として業務を振ってくる

例えば、A という業務と B という業務、それぞれ別のチームの仕事だったとします。B のチームの人からは、Aのチーム/仕事が見えないので、ついつい P さんに1人月分(=100)の仕事を振ってしまいがちです。

同じことがA でも発生します。例えば、Aチームでは、納期に間に合うか間に合わないかくらいのギリギリなスケジュールで動いていて、「P さん、ちょっとこのチケット持ってもらえませんか?」みたいな会話が発生したりします。まだB に比較的余裕があって「ああ、OK じゃぁA のほう頑張ってくれ」とコミュニケーションできればいいですが、「え、それは困るBもパツってる」とかになってくると、しんどくなります。

そしてコレはただの経験則ですが、だいたいしんどい次期は重複するので、Aがパツってる時にB が余裕ある という事はあんまりありません。パツってる時はだいたい緊急度が高い会話をする必要が多く、それだけコンテキストスイッチも発生し、雪だるま式に業務量が膨張します。

自発的に発生するコンテキストスイッチ

所謂生理現象です。トイレ行きたいとか眠いとか腹減ったとか、そういう生理的欲求による中断の他に、僕は勝手に小さなフラッシュバックと呼んでいるのですが、何か特定の事象を見て、それに興味が奪われたり、忘れていた何かを思い出してしまったりする現象があります。

外部からの割り込み以外にも、自分の中で発生する割り込みも存在します。これも経験則なので根拠微妙ですが、精神的なダメージを負っている時によく発生するイメージがあります。

コンテキストスイッチにどうやって立ち向かうか

そもそも複数業務をアサインしないようにお願いする

上司と相談出来る環境、そして上司がそれを納得して受け入れてくれる環境なら見えてくる選択肢です。 が、だいたい1人の人間に複数種類の業務がアサインされている時はもう上司の時点でパツってるので、この方法が通ることはまずありえません。

もしどうしても、1人の人間に複数タスクをアサインしなきゃいけない時、最も効果的だなって思っているのは 80:20 くらいで、それ以外のアサイン方法でまともなのを知りません。

業務時間を固定する

例えば、80:20 で分割した場合、20のほうの業務を必ず金曜日に行う 等の合意が取れていれば、コンテキストスイッチの発生回数は極端に減ります。 さっきも書きましたが、土日が休みな場合コンテキストスイッチは土日に行われるので、101 くらいの業務量で済みます。

割り込みを回避する

特に集中力を要する仕事で有効な方法だと思っていて、誰からも声を掛けられない場所に引きこもり、チャットツールも閉じる というのが有効だと思っています。人が減りだす 20:00 - 24:00 のオフィスであったり、世間が寝静まった1:00 - 5:00 の間に最も集中力が高まることを感じるのもこれかなと思っていて、理由は割り込み回数が極端に少ないからです。

集中する部屋 みたいなのが固定デスクとは別に設けられているオフィスは良いと思うのですが、そうでなかったり、全域フリーアドレス とかになってくるとものごっつしんどいですね。

自分はどうすればいいのか

さて、じゃぁ今自分がどうなっているかというと、A+B+C+D+E= 120 くらいになっています(限界量100) コンテキストスイッチは頻繁に発生するので、実感値としては200くらいです

さて、どうすれば良いのか。

そもそも複数業務をアサインさせないようにお願いする は既に実行済みですが、「A+B+C+D にはなるかも」って感じで、うーんそれでもまだ4あるのか辛いという状態。次に有効かなと思っているのが、「じゃぁ月曜日、火曜日休みで 土日出社という感じのフレックス制度になりませんか?」 という相談。これは明日試してみるが、多分、人事や総務的な観点からお断りされると思っていて厳しい。

自分の中で、業務時間を固定してその時間はそれ以外のことを一切しない という強い意志表示をする というのが、多分自分に出来る唯一のカードだな。と思っていて、今全力で冷徹になろうとしている。(スケジューラーブロックを完全にブロックして会議を打ち込まれるのを防ぐ等。)

他にどうすればいいのか。

「お前の頭が悪い」と言われたら「すみません」としか言えません。自分の頭の悪さはコントロール出来ないので………。お前が無能だからそういうアサインのされ方をされるんじゃないか?と言われたらぐうの音も出ませんが、無能が加速するのでできれば辞めてほしい所……。

他の人がどういう感じで仕事しているのか、えるちゃん以上に私、気になってます。

どうしてwebフレームワークに苦手意識を感じるのか

創作物(ドラマやアニメ)において、「この物語はフィクションです。登場する人物・団体・名称等は架空であり、実在のものとは関係ありません。」という注意書きが必ず記載されるのと同様に、個人ブログにおいても、必ず「この記事は個人の見解であり、所属する組織の公式見解ではありません」という但し書きを書く必要が出てきたので、鬱陶しいですが毎回書きます。ご容赦を。

「この記事は個人の見解であり、所属する組織の公式見解ではありません」

私は、例えばRuby on Rails のような強力なwebフレームワークが非常に苦手で、なんでこんなにやりづらいんだろう?と思っていた。フレームワークを入れたは良いが、実現したいソフトウェアをいざ実装するぞとなったら、まるで手が動かなくなる事が多い。その原因がさっぱり見えていなかったのだがようやく分かってきたので書く。

1. そもそもちゃんとドメインモデルを構築できていない。

フレームワークどうこういう以前の問題として、私個人のモデル設計力が低い。 とにかくコレに尽きると思う。特に学生の時は深いことをさっぱり考えずに「とりあえず実装するか」とコードをしっちゃかめっちゃかに書きなぐって「とりあえず動いたからリリースしようぜ」というのが許された。(許されたわけではないと思うが、基本的に設計から実装からリリースまで全部1人だったし、趣味の園長のようなプロダクトなので、困るのは自分くらいだった)

なので、オブジェクト間の依存関係とか全然考慮されておらず(いや、多少は考慮していたが、完成度の低いモデルで)酷い設計/実装だった

2. フレームワークの学習コストの見積もりが甘い

Zendにせよ、RoR にせよ、Django にせよ、所謂「重い」と言われるフレームワークはとにかく、何人もの優秀な技術者の知恵と努力が何年も積み重なったもので、一介の素人がちょっとドキュメントを読んだだけで理解出来るものではない。(ちょっとドキュメントを読んだだけで全てが分かるのなら、世界は優秀な技術者を必要としない)

とにかく学習コストが高い。学習コストが高いと嘆いているうちは、まだ自分の道具になっていないという事だし、道具に振り回されて疲れ果てることになる。既に道具として使いこなしている先輩方から「これはこうしたほうがいいんじゃね?」と言われても、何を言われているのかわからないので、反論が出来ない。

また、上述の通り、ドメインモデルがしっかりしていないので、「このフレームワークではこうするんだ」というフレームワークの思想が優位に立ち、本当にすべき実装が見えていない。というのもある。

という事を青DDD, 赤DDDを読みながら思った。

エリック・エヴァンスのドメイン駆動設計

実践ドメイン駆動設計

青DDD は読むの物凄くしんどかった。オススメしない。赤DDD は DDD についてある程度知識がある前提で進むので、青DDD の要約スライドを見て挑むのが一番学習効率が良さそう。

kotlin を始める

最近、Android 界隈でKotlin という言語が流行ってるらしい。というくらいには老害になってきたのであるが、とにかくkotlin を始める。

Android で正式に採用されたらしい。という情報だけだったら多分さわりもしなかったんだけど、どうやらこいつは、JVM 上で動くだけでなく、js, native コードにコンパイルしてくれるらしい。それ凄くない???

開発元はJetBrains. Intelli J Idea とか作ってるすごい所。 ということで、今回はkotlin はIntelliJ Idea で触ることにした。

多分すごい爆速でコード書けそうめう。

公式 : https://kotlinlang.org/ OSS : https://github.com/JetBrains/kotlin

kotlin はネイティブコードを生成できる(らしい)が、kotlinを動作させるには、JVM環境が必要。最新版は 1.2 @ 2017/12/20時点

じゃぁ、取り急ぎハローワールドから。 jvm で実行する、js で実行する、ネイティブで実行する、 の3つを実装する。(多分コードは変わらないと思うけど)

kotlin ファイルの拡張子は、kt。小室哲哉かよって思った私はもう老害。飛行機の速度かよって思ったやつはメーデー

fun main(args: Array<String>) {
    println("Hello Kotolin!!")
}

func でもfunction でもなく、fun なのか。これはちょっと嫌だなー。と正直に思った。func か、せめてfn にしてほしい感ある。 そんな事はどうでもよく。

ここで、まず見るべきは、クラス定義がない。これは一体何クラスに属するメソッドなんだ??

kotlin が吐いた生成物を見ると、Appkt.class(App.kt という名前で生成した)になっていた。なるほど。

kotlin native を使う

参考:https://github.com/JetBrains/kotlin-native

書いてあるとおりにする。

最終的には、こんな感じのコマンドを叩いて、CとかGo みたいな実行可能ファイルが生成される。 kotlinc hello.kt -o hello -opt

うーーん、kotlin でネイティブかけるのはすごい。 私個人はネイティブ原理主義者なので、ネイティブに変換できるだけで株は大上がりですね…。

Gem を作る

今更ながらRuby について真剣にやり直そうと思う。理由はまぁ色々有るのだけど。。。どうもRuby は苦手だ。

さて、gem を作る。今までとりあえずgem install していたけど、gem ってそもそもどうなっているんだろうか??

bundle gem gemname

これで雛形を生成することが出来る。おそらくデフォルトのままで問題ないと思う。生成されるgem のファイル構成は以下のようになっている。

├── CODE_OF_CONDUCT.md
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── bin
│   ├── console
│   └── setup
├── lib
│   ├── testgem
│   │   └── version.rb
│   └── testgem.rb
├── spec
│   ├── spec_helper.rb
│   └── testgem_spec.rb
└── testgem.gemspec

4 directories, 12 files

testgem と言うのは私が書いた名前なので、各自の環境で変えていただきたい。ruby でrequire が呼ばれた時、このlig/testgem.rb が呼ばれる。また、このgem を呼び出すにはどうしたら良いのか。

このディレクトリとは別に、'callgem'というディレクトリを作成し、Gemfile を作成する。ローカルのgem を呼び出す時は、path属性を指定してあげる。具体的には以下のようになる。

gem 'testgem', :path => '../testgem'

さて、これでbundle install しようとするとエラーが起こる。どうやらspec ファイルがまだvalid じゃない(テストが通ってない)と言われるので、コレをアレコレ書く所から始めようと思う。

早速gemspec ファイルを開けるよく見ると中にToDo という文字列が見つかるので、そのへんを適当に改良する。以下のようになった。

# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'testgem/version'

Gem::Specification.new do |spec|
  spec.name          = "testgem"
  spec.version       = Testgem::VERSION
  spec.authors       = ["bussorenre laboratory"]
  spec.email         = ["mailaddress@bussorenre.com"]

  spec.summary       = %q{おためしで作ったgem}
  spec.description   = %q{こんなんでいいのか}
  spec.homepage      = "http://localhost:3000"
  spec.license       = "MIT"

  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
  # to allow pushing to a single host or delete this section to allow pushing to any host.
  if spec.respond_to?(:metadata)
    spec.metadata['allowed_push_host'] = "'http://mygemserver.com'"
  else
    raise "RubyGems 2.0 or newer is required to protect against " \
      "public gem pushes."
  end

  spec.files         = `git ls-files -z`.split("\x0").reject do |f|
    f.match(%r{^(test|spec|features)/})
  end
  spec.bindir        = "exe"
  spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
  spec.require_paths = ["lib"]

  # ココに依存しているgem を追加する
  spec.add_development_dependency "bundler", "~> 1.14"
  spec.add_development_dependency "rake", "~> 10.0"
  spec.add_development_dependency "rspec", "~> 3.0"
end

本当にToDO のところを書き換えただけです。

さて、肝心のこのgem ですが、ping というメソッドを実装し、呼び出されたらpong と返す。たったそれだけのgemを作成します。

まずspec

require "spec_helper"

RSpec.describe Testgem do
  it "has a version number" do
    expect(Testgem::VERSION).not_to be nil
  end

  it "response pong if ping" do
    expect(Testgem.Ping).to eq('pong')
  end
end

実装

module Testgem
  def self.Ping
    'pong'
  end
end

これで、rspec が通った! というわけで、さっき作ったcallgem から呼び出してみる。

まずはbundle install する。すると問題なくbundle install 出来たので、コードを書く。

require 'testgem'

puts Testgem.Ping

これをbundle exec ruby main.rb で実行すると、無事pong と表示される。

結論

gem が出来た。所謂有名所のgem も基本はこういう原理になっているはずなので、コードリーディング等に役立てていきたい。

当事者になってわかったこと

ネガキャンするつもりはないんだけど、

確かに、自分が住んでるマンションでAirbnb されると嫌だなって思った。

今はまだ問題が表面化してないけど、いずれ表面化するんだろう。