テレワーク(4)

全員出社禁止。

火曜日の夕方、NW回線が日々遅くなっていく状況にイライラしながらも、テレワークで仕事をしていたときのことだった。 首相の緊急事態宣言が発表されたとチャットに流れ、思わず仕事の手を止めニュースを見て、感想を言い合う。チャット越しとはいえ、みんなの感情の揺れ動きが手に取るように分かるとき、Teamsにて管理職全員の招集がかかった。

もともと、緊急事態宣言が出ることを見越して、火曜日の夜には何らかの追加対策方針が出されると聞いていた。 自分なりの対策案も考え、部長陣に提案する用意もできていた。 なので、心構えは出来ていて、よし、と思っていた。

最初はパワポ資料を使った月曜日時点の会社の方針の振り返りから入り、その後、慌てて作ったであろうメモ帳に記載されたテキストがデカデカと画面に表示される。 そこに書かれていた内容は、全員出社禁止、その6文字であった。

先週末時点で、プロパは既にテレワークで、出社は2週間に1度まで削減する計画を立てていた。 協働者のテレワーク準備も大方済んでいた。 だから、ある程度の強い方針でも現状と大きく変わらないだろうという予測のもとで、自分なりの対策案を立案していたが、まさかの全員出社禁止に、声が出なかった。

そこからは、緊急事態宣言が一週間前のように感じられるほど、慌ただしい2日間である。 課長同士で連絡を取り合い、1ヶ月間出社禁止となった場合の業務への影響を一晩で整理し、上司や他チームへと説明し、アップデートされた情報から更に自チームへの影響を見直し、そして他チームへと展開する。 その合間に、協働者の責任者に順次事情を説明し、テレワークができる協働者とそうでない協働者の扱いの違いに対する対応や、支払いに関する話、今後の見通しなど、出して良い情報、出せない情報、プロジェクトの方針、自チームの方針、そして自分の考えを伝えていく。 その合間に、子供が保育園に通えなくなったから業務時間を減らしたいという部下の要望や、NW回線の遅延により打鍵誤りが発生し環境を壊してしまったという報告、同じくNW回線の遅延により社内のセキュリティルールを守っていたらチャット以外のコミュニケーションが全く取れないという現場の悲鳴を対処しつつ、リモデの画面を見ながらPCを操作するよりも、自端末をホストにして、共有された画面をスマホで見ながらマウス/キーボードを操作するほうが快適であることに気づき、スマホ画面を見ながらシンクラを操作して決算時期特有の様々な点検報告書を仕上げつつ、新年度固有の各種周知事項をボイスで社員に伝える。

課長陣はテレワークで済んだが、部長陣は、各フロアに待機し、誰かが出社したら追い返すという役目をこなしていた。 正直、大して給料に差がないのに、部長は課長に対する影響力以外の実行力を持たされずに責任だけ負わされて大変だと、仕事中、上司にボイスで雑談を振ったら、実行部隊を直接指揮する君たちに比べれば雑務がないだけ楽だよと言われ、いやいや、いま貴方の出社理由が究極的に雑務でしょと感じてしまい、返す言葉に詰まってしまった。

そんな感じで、7日の夜から数えて、48時間中、36時間は働いた。まさかテレワークで、在宅勤務で、こんなに働くことがあるのかと思うぐらい、緊急事態宣言の余韻を感じる暇もなく、久しぶりにガッツリ働いてしまった。 火曜日の午後には、NW回線が込みすぎて、「明日から早朝と夜間しか仕事しません」なんて冗談を言っていたのに、そんな余裕すらなかった。 テレワークだから、通勤時間がない分、睡眠時間が確保できているのが唯一の救いだ。 それでも、正直、緊急事態宣言が出たのが、今でも二日前というのが信じられない。 (4月7日だよね、6日じゃないよね。本当に、時間間隔がおかしくなってて、これを書いているときも、何度も何度もネットの記事の日付チェックした。さらに、日付の引き算方法を勘違いしているのではないかと、カレンダー見ながら、一日前、二日前と指差し確認してしまった。)

そして、この2日間の外出は、わずかに40分である。割合にして、1.4%である。コンビニ3回、そば屋1回。

外出自粛。

自分がまさか、こんな形で実現するとは思わなかった。

先程、進捗資料を書き終え、やっと休める目処が立ったので、今日初めての外出で買ってきた晩ごはんとともに、今、ビールを飲みながら、これを書いている。

それにしても、疲れた。

本当に、疲れた。

ArrayList と LinkedList

今日の技術ネタ。 難しい話は、なし。

議題

ArrayListとLinkedList、どちらを使えばよいでしょうか。

  • 最近、会社のタバコ部屋で、上記の質問をされました。
  • 気まぐれに、自チームで開発しているツールのソースコードレビューをしていたら、一度作ったら変更しないListに対してLinkedListが多用されていたので、なぜそれを選んだと聞くと、LinkedListの方が汎用性に優れるという回答があった。

自分の考え

とりあえず、ArrayListを使え。 ArrayListとLinkedListの使い分けが理解できなければ、LinkedListは使う価値なし。

理由1:性能面

ArrayListに対するLinkedListが持つ圧倒的な優位性は、下記の2つです。 たった、これだけです。

  • 先頭への挿入が速い
  • Iterator/ListIterator使用時のadd/removeが速い

まず、先頭への挿入が速いという話ですが、先頭への挿入しかしない場合は、ArrayListの末尾に挿入して、一通りの挿入処理が終わったら、reverseすれば良いです。それで、十分に元が取れます。 もし、先頭と最後に半々ぐらいで挿入したい場合は、ArrayDequeを使えば良いです。ArrayDequeは、RingBufferの構造をしているので、先頭と最後への挿入であれば速いです。

次に、LinkedListは、Iterator/ListIteratorを使用したときは、途中の要素を追加/削除するときは圧倒的に速いです。

LinkedListを教科書とかで読むと、一般的には途中要素への挿入削除が速いとしか書いていませんが、これは動作させるマシンの特性に依存します。 ArrayListの場合、途中に挿入・削除しようとすると、配列のコピーが発生しますが、連続領域のコピーであるため、このコピーは速いです。 対して、LinkedListの場合、Iterator等を使わずに挿入・削除を行おうとすると、ポインタを手繰りながら目的のエントリまで到達し、そこで初めてO(1)処理が行われます。 そのため、メモリへのランダムアクセスが大量に発生します。

昨今のCPUは、メモリアクセスに比べてCPU性能が上がりすぎているため、CPUキャッシュをいかに使うか、すなわちメモリの局所性をいかに活かすかが重要であり、昔ほどLinkedListの優位性はなくなりました。 (もちろん、今でも挿入・削除しかしないのであれば根本的にはLinkedListの方が速いのですが、本当に、それだけで済みますか? 途中で検索処理が1回でも入った瞬間に、そのメリットは打ち消されます。例えば、何番目に挿入するっていう処理、検索なしに書きますか? 大抵の場合、何番目に挿入するかを決定するためにリストを舐める処理が入ると思います。この舐める処理を入れた瞬間、ArrayListに負けます。)

そのため、LinkedListは、Iterator/ListIteratorで頭から舐めながら、都度都度入れたり抜いたりするときだけ使えます。ただ、この処理、書きますか?という話です。この処理を、素でさっと書けるだけの技量があるなら、そもそも、ArrayListとLinkedListを迷うようなことはありません。

理由2:メモリ面

LinkedListとArrayListでは、メモリ使用量が圧倒的に異なります。

Javaは、オブジェクトヘッダを持つため、オブジェクトを生成するだけで8バイトのメモリを消費します。 LinkedListは、双方向リストであるため、エントリのオブジェクトヘッダ(8バイト)、前のエントリへの参照(8バイト)、本エントリの値への参照(8バイト)、次のエントリへの参照(8バイト)と、1つのエントリを保持するために32バイトのメモリが必要になります。

対して、ArrayListであれば、配列でガッツリ確保しているため、本エントリの値への参照(8バイト)だけが必要になります。(配列のヘッダなどは、保持するエントリの数が多くなればオーバーヘッドとしては無視できる。) ただし、ArrayListは大きめに配列を保持する(最大1.5倍)ため、余分な領域が生まれます。

そのため、ArrayListが平均1.3倍の配列領域を確保していると考えると、LinkedListの方がArrayListに比べて3倍ぐらいメモリを使用することになります。

結論

大概のケースに置いて、ArrayListの方が性能がよく、さらに全てのケースに置いてメモリ使用量がArrayListの方が優れていると考えると、 ArrayListとLinkedListのどちらを使えば良いか悩むのであれば、とりあえず、ArrayListを使うべきです。

それで性能問題が起きたら、初めてLinkedListを候補に入れれば良いです。 ただ変更するときは、OutOfMemoryErrorに注意しましょう。

Javaの文字列のメモリ使用量(Java8ぐらい編)

Javaの文字列は、メモリを消費します。 仕事をしていると、良く見積もり方法を誤っている人が多いため、ここに、簡単な見積もり方法を残します。 もう、10年前のノウハウなので、細かい値は間違えていたらご容赦を。

前提条件:Java8

Java9より、Compact Strings (JEP 254)が実装されているため、ここでの見積もり方法は、Java8まで有効です。 Java9以降の見積もり方法は、気が向いたら記述します。が、基本的な考え方は同じで、文字列がAscii文字のみで構成されている場合、1文字あたり1byteで計算されるところが変わります。

また、Java8では、使用する変数が減っているため、Java7もまた、別のロジックで計算する必要があります。 ただ、Java7は、Java8に比べてint変数が2個多いだけなので、基本的な考え方はこちらも同じです。

java.lang.Stringの構造

変数名 変数型 サイズ[byte]
value char[] 8
hash int 4

メモリサイズの計算方法

Stringクラスのオブジェクトヘッダに8バイト、char変数に8バイト、int変数に4バイト、合計20バイトがベースラインになります。通常は8バイトでアライメントされるため、4バイトのパディングが入り、24バイトがStringオブジェクトのベースラインになります。

続いて、char[]オブジェクトは、オブジェクトヘッダ8バイトに、配列長4バイトがベースラインで、あとは1文字追加される度に2バイト増えていきます。

そのため、24+12+2N(ただし、12+2Nはアライメントの関係で8の倍数へ切り上げる必要あり)が文字列のメモリサイズとなります。

計算例

文字列長 メモリサイズ 計算式
0 40 24+(12+2*0+4)
8 56 24+(12+2*8+4)
16 72 24+(12+2*16+4)
256 552 24+(12+2*256+4)

実用例

DBからCSVファイルをダウンロードするとき、メモリ使用量を意識しないと、直ぐにOutOfMemoryが発生します。 例えば、カラム数100、平均カラム長16、レコード数10万のCSVを作成しようとするとき、何も考えずに愚直にアプリケーションを作ってしまうと、 100 * 72byte * 100,000 = 720Mbyte という結果になります。 もし、これを単純に、 100 * 16 * 100,000 = 160Mbyte と計算したときに比べて、4倍以上の差が付く形になります。

さらに、DBから取得するときに、ResultSetの結果の保持の方法次第では同量の720Mbyte以上のサイズがヒープ上に存在することになるし、CSV加工のために"(ダブルクオート)を前後に付与する処理を一括実施したあとにファイルに書き込んだりしようとすると、さらに同量の文字列がヒープに積み込まれることになります。 このように、処理方式によって、メモリ使用量が大きく変わる可能性があります。

とはいえ、経験的に、でかいデータをどうこうするときに安全にざっくり見積もりたいときは、だいたい全文字数の10倍を見ておけば大丈夫です。

まとめ

小さい文字列を大量にヒープ上に置くときは、メモリサイジングをしっかりやりましょう。

テレワーク(3)

昨今のコロナ状況により、いよいよ会社側からも強めの要請が出ました。 さて、テレワークにおいてセキュリティとコミュニケーションは重要で、自分も端末はシンクラ+VDI、コミュニケーションはTeamsとTFSを利用しています。

特にこの1ヶ月間、大掛かりにテレワークを行ってきて、マネージャー目線で感じているテレワークによる困りごとを書いてみました。 なお、チーム内のコミュニケーションは、なんとかなってるように見えるし、まだ顕在化してないだけかもしれないので、この観点は省きます。

1つ目は、社員の顔が見えないこと。

コミュニケーションは取れるものの、やはり1日1回は生の声を聞いたり直接表情を見ないと、体調は良さそうか悪そうか、仕事に前向きになってるかネガティブになってるか、困りごとがありそうかなさそうか、などなど、対面でないと分からない情報が得られづらい。 細かく進捗を聞いても良いが、対面であれば5分で終わるコミュニケーションが、社員にレポートを求めることになってしまうため、彼らの生産性が下がってしまう。 もっとも、彼らからしてみれば、無駄に話しかけられなくて済むという話もあるかもしれない。

2つ目は、現場で何が起こってるか分からないこと。

プロジェクトで何らかの技術的問題が発生すると、たいてい技術系メンバを率いる私のチームに相談が来る。なので、他チームの誰が居室に来て、自チームの誰と話しているかを気にするだけで、メールとか、チャットとかを見なくても、だいたい、どのような問題が起きているかが想像できる。 これが、色々と分からなくなる。 そのため、自身が迅速に動かなければいけないときでも、着手がどうしても遅くなってしまう。

3つ目は、テレワークにすると生産性が極端に落ちてしまう人も居ること。

個人の能力に依存する問題もあれば、家庭環境(子供が邪魔するとか)によりテレワークが実施的に行えなかったりする人もいる。 個人の能力に関するところは、正直、諦めてます。人によってはテレワークにより生産性が上がるため、その人にタスクアサインすることで回避しています。これは、結局職場でも、他の人に頼り切りにならないと仕事ができないわけですから、その人ができているレベルの仕事であれば、他の人ならそれほど苦もなく進められるので、ここは気にしないようにして、割り切っています。 問題は、職場だと生産性が高く、家だと家庭環境の問題で生産性が低くなってしまう人、すなわち、家だと仕事にならない、という人たちです。正直、チームの生産性が落ちるため、私としては大問題です。

1つ目と2つ目の問題に対しては、地味ですが、

  • これまでExcelやらMS Projectで管理していた内容の多くをTFSに移行することで、成果物や検討状況は、なるべくTFSのワークアイテムに残してもらう
  • 社員については、面倒でも、メンバ間の情報共有も兼ねて、終業時に簡単な日報(3~5行程度)をチャットに書いてもらう
  • 打ち合わせがないときは、1日1回、5分程度、社員や各社リーダー層の都合の良いタイミングで、電話やボイチャを貰うようにする

ということを行って、対応しようとしています。

3つ目の問題は、まだ対策ができていませんが、優秀な人に生産性を落としてもらうわけにはいかないので、特別対応ということで、そういうメンバの家の近くに小さな貸しオフィスや貸し会議室のようなものを、借りてしまうことも考えています。(お金の問題はありますが・・・)

次に、テレワーク組と出社組が同時に参加するオンライン会議についてです。 これは、ノウハウが必要ですが、もし、決定権を持つ人が居る会議であれば(進捗会議だったり)、その決定権を持つ人がテレワークでないと、大抵、うまくいきません。なぜなら、出社組の中で議論が進んでしまって、テレワーク組が置いてけぼりを食らうからです。これは、寂しいです。

最後に、テレワーク主体にしたときに管理職要らなくね?説についてです。 たまにネットで見かける意見ですが、テレワーク主体にすると、管理職の仕事っていうか、管理職ができることが結構減るんですよね。 自分も、労働時間が4割ぐらいに劇的に削減されます。自分の仕事を観察したときに気づいたことですが、

  • 頻繁に話しかけられない、余計な打ち合わせに出なくて済む (更に言うと、オンライン会議って、なぜかいつもより早く終る気がしてます)
  • 労働時間の管理が簡略化される (開始・終了がチャットに書かれるので、早く帰れコールのために職場に残らなくて済むようになる)
  • 些細なことに口を出さなくなる (色々と気づかなくなるので)
  • 仕事の進みが悪い社員に対する諦めがつく (翌日にしか仕事の進みと出来不出来が分からなくなるので・・・)
  • そもそも雑談が減る (目の前に社員が居なくなるので)

という感じになってました。普段、どれだけ~と思います。

代わりに、空いた時間で何してるかというと、仕事の進み具合と仕上がりの確認ばかりやってます。

特に、今回を機に仕事のやり方を見直したせいか、どこに何があるのかが一目瞭然となり、レビュー時間等をあえて作らずとも、メンバの成果物の出来が翌日には確認できて、気になるところを本人にフィードバックできるところが良いです。正直、今まで如何に無駄な仕事をしていたかが良く分かりました。 また、対面でレビューしてしまうと、感情的になってしまう私の悪い癖も、チャットやワークアイテムに対するコメントという形で文章に書くと、感情的にならなくて済む感じが、なお良いです。

さらに、メンバ自身も割り込まれることが減って集中して成果物を作るためか、ベースラインの品質も上がっているのを実感します。

ITの会社にいて、いっちょ前にエンジニア&マネージャーを気取ってましたが、全くITが活用できていなかったことに、心底恥ずかしいと感じたのが、このテレワークの期間でした。

なお、私のチームは、色々と変わろうとして、変わりつつありますが、私から上のレポートラインは、何一つ変わっていないため、パワーポイントとエクセルの進捗資料と、毎週のテキストベースのメール週報が残り続けています。 なので、今週、ある程度の仕込みが出来たので、来週の進捗資料からは、私の管理画面に飛ぶURLだけ貼り付けてやろうと画策しています。

あとは、ついnetflixを見たくなる衝動をどうにかしたい。

テレワーク(2)

約50名の社員・協働者のうち、40名弱がテレワーク可能な状態となったこと、それと昨日の記者会見の内容を受け、本日より、不要不急な出社は禁ずるという方針をたて、私のチームは全面的なテレワーク実施へと舵を切りました。

この1ヶ月のトライアルを経て、顧客や他チームとの連携においても、ある程度の混乱が発生しないよう準備はできました。 ただ、部長やPMの許可を得ていない、ぶっちゃけ許可が下りない中での判断であるため、あとでどんなお叱りをうけることやら。。。 (PMなんて、死なばもろともとか言ってたし。冗談でも言うなよ、と本気で思いました。)

次の問題は、自分の生活が維持できるかどうかだ・・・ マスクなし、トイレットペーパーは残り2ロール、備蓄カップ麺3日分。万が一外出禁止令が出たら、生活できない。 周囲のスーパーは買い占め行列状態で並ぶことも躊躇われる。

う~ん・・・

超高速なloggerを作ってみたくて

超高速なLoggerに唐突に興味を持つ。 Log4J2が非常に高速であり、性能を気にするなら、基本的にはLog4J2を使えば良いが、柔軟性を捨ててでもより高速なLoggerは作れないかと考えてみた。 なお、kotlin/jvm(java8)で実装。

参考資料は、以下のページ。 logging.apache.org

www.matthicks.com

www.sitepoint.com

要件は以下の通り。

  • レイアウト(項目の出力順序)は固定: 日時、ログレベル、マーク、出力箇所(クラス名、メソッド名、行番号)、ログメッセージ
  • 日時フォーマットは固定: yyyy/MM/dd HH:mm:ss.SSS
  • ログメッセージ方法は全てラムダによる遅延生成を必須化
  • ImmediateFlushはfalse固定
  • appenderは、ローリングファイルアペンダー相当

簡易実装の結果としては、自宅のwindows-pcにて同期ロギング(not asyncLogger)/非同期ファイル出力(ImmediateFlushはfalse)、シングルスレッドにて170万msg/sを達成した。なお、同一マシンでのlog4j2の測定は、まだ未実施なので、比較はこれからだが、一応、上述のlog4j2のページの数字よりは良い結果が出た。 ちなみに、ログの出力箇所(行番号とか)を出そうとすると、log4j2とかでもすごく遅くなるため、この簡易ロガーは、行番号出力という観点においては、少なくとも世界で2番目ぐらいには速い。(一番は、参考資料にある通りに、コンパイル時決定を行うscribe2でしょ、きっと。)

チューニングした内容は以下の通り。キャッシュ化は、ThreadLocalを利用。

  • LogEventのキャッシュ化: ほぼ効果なし(気休め?)
  • StringBuilderのキャッシュ化: 効果あり
  • Calendarのキャッシュ化: 効果あり
  • 現在時刻と前回時刻を見て日時の再文字列化コストの削減: 効果あり
  • DateFormatを使わず、固定フォーマットのハードコーディング: 効果あり
  • 日付変換処理において、割り算を減らす(/10と%10): 効果あり
  • 出力箇所のキャッシュ化: 効果あり。ただし、ラムダ式が個別クラスにて実現される仕様に依存。コンパイル時マクロとかあれば・・・。

というか、これだけやっても、上述の参考資料のlog4j2の数字よりも30%ぐらいしか速くならないって、log4j2はどんだけ化け物なのかがよく分かった。

思いつく範囲で、今後のチューニング予定は以下の通り。 ただ、上述のチューニングを実施して、ファイル出力なしのときの性能が10倍近くになっているので、これ以上は多くは望めないところが悲しい。(例:StringBuilder、LogEvent、再文字列化コスト削減の3つで、ファイル出力なしの1回のロギングあたり380ns→90ns。自分のマシンとしては300clockぐらいしか使ってないことになるが、本当か? キャッシュヒット次第で吹っ飛ぶクロック数だが・・・) 残りのボトルネックはファイル出力なので、これ以上はマルチスレッド時の高速化ぐらいしかないかなあ。

  • StringBuilderを止めて、CharBufferを使う
  • ログレベルの文字列書き込みや出力箇所とかの再文字列化コストの削減
  • String生成コストが一定以上あるため、出力方法をPrintWriterから他のに変える(この場合のStackTraceをどうするかは別に考える。諦めるのも有りか?)
  • マルチスレッド環境向けのチューニング(現状は出力手前でsynchronizedしてる)。要は、ログ出力呼出と実際の出力の非同期化。AsyncLoggerと同じ理屈。
  • ガベージフリーをもう少し努力する(相当キャッシュ化したので、あとはファイル出力周りとか、一時オブジェクトの生成が発生しないよう努力?)

テレワーク中

本日は咳が続くため、テレワークを選択中。(これを書いているのはお昼休み時間)

発熱もないため普段であれば勤務してしまうところであるが、昨今の状況を鑑みて、管理職として率先してテレワークを選択することで、社員がテレワークしやすい雰囲気作りに慣れば良いなと、またこんなご時世に電車に乗りたくないと考え、テレワークを選択しました。

さて、今現在私のチームは一時期よりはだいぶ減ったものの、現在も50名ほどの社員/協働者が一つのフロアで働いているという状態です。 少し前に、協働者に対するテレワーク環境と社内ルールが整ったことから、協働者含めて全員で1回テレワークをやってみようと今週準備に奔走していました。

自組織およびプロジェクトルールの改定や、テレワーク環境のためのシンクライアントの準備(かき集め)、開発LANに対するゲートウェイ登録、社内の各協働者のテレワーク利用の申請、リモートアクセスの申請、トークン申請、自宅のセキュリティチェックなどなど、とにかく事務手続きばかりやってました。その上で、ローカルルールの制定(コミュニケーション方法や勤怠共有方法など)し、他チームとの打ち合わせ方法などの調整を行い、いざ、準備万端と思って構えていました。 そして、今日/明日でトライアルを実施ののち、来週よりいざテレワークだと張り切っていたら、一個見落としがありました。

協働者の会社にテレワーク/在宅勤務の制度がない。

これは完全に私の落ち度でした。 事前に確認しておかなきゃいけなかった話なのですが、社内ルールを熟読していたら、私から協働者に対してテレワークの指示ができないということに気づき、慌てて協働者の会社にトライアル参加の意思確認を行った所、制度がないためできませんとの回答が多くありました。

私のチームの協働者は、二次委託先までなのですが、一次委託先はだいたいテレワークできるのですが、二次委託先はテレワークの制度がある会社が一つもありませんでした。(私のチームを例に言うと、一次委託先は4社、二次委託先は8社ほどになります。すごく横幅の広いピラミッド構造です。) 結果、約50名のうち、テレワークできる人が25名程度と、半数にとどまってしまいました。

非常に残念です。

とはいえ、社員のご家族がテレワークを望まれていたり、ご実家から心配されていたり、と、なまじニュースに出てしまったために、ご家族より会社に勤務すること自体を怖いと思われているところもあり、かと言って社員だけテレワークというのも全く責任感のない話であるため2chで叩かれるし)、何とかしようとした結果、この結論ですよ。

はあぁ。

なお、テレワーク自体は快適です。というか、夏場と冬場に10日間連続テレワークをしているので、自分としては特に感慨もなく、仕事が捗るぐらいで不便はないです。