IT企業からJTCのDX部門に転職して3年働いた感想
私はITエンジニアなのですが、表題のとおり、IT企業からJTC、いわゆる歴史のある国内事業会社に転職して3年間と少々働きました。いわゆる社内SEではなく、JTCの中でIT技術を活用した新たな取組を行う部門に所属しました。同じような働き方を考える方もいるのでは思って、感想を書いておこうと思います。
IT企業ではなく、わざわざJTCでITエンジニアをやる楽しみって何でしょうか。私の場合はやはり、JTCが積み上げてきた、他の企業ではなかなか追従できないであろう資産を、IT技術も用いて有効活用することに関心がありました。特にJTCは社会のインフラを担っている場合も多いので、直接的な社会貢献という大義名分を持って働く機会もあります。
最近は特定の業界業種に向けたDX色のあるSaaSを開発するベンチャー企業も増えてきましたが、あくまでIT技術観点(特にWEB技術)でタッチできる部分から入っていくというものが多いので、事業会社の中でIT技術を活用していくのとは、どうしても異なるものです。
実際に事業会社で働いてみて、やはり社会に直結するような分野を扱っていること、そこに近い場所で貢献できる喜びや実感はありました。一方で、かなり見通しが甘かったなと感じる部分も多々あったなと思います。
ますはじめに、事業会社のDX部門というのは一種のスタートアップと考えたほうが良いです。つまり有象無象の何かであるかもしれず、予算は付いているが実質的にビジネスは進展していない組織や事業もあります。
また、スタートアップ的でありながら、よくも悪くもその企業の枠組みの中で動くことを強制されるという特徴があります。判子ラリーがあったり、経営陣のITリテラシに驚くことがあったり、異様に縦割りだったり。逆に、部門長の力次第で予算が潤沢に付いたり、自社の法務・広報部の力を借りることができるメリットもあります。そして当たり前ですが、ドメインエキスパートが社内にたくさんいます。
結局のところ、私は3年と少々務めて転職する運びとなりました。その理由は上述のとおり、参画した新規事業が進展していないからということになります。予算は潤沢に付いているのですが、これといって進捗がなく、長い目で見ても改善するイメージが湧きませんでした。
JTCには高学歴でその道では名の知られたドメインエキスパートがたくさんいます。私は全然ダメなのですが、数学や物理などの理系基礎学力の高さに尊敬の念を感じることが多々ありました。とはいえ、そういった方々であっても、ITに関しても新規事業開発に関しても素人の場合が多いです。そして、DX部門の代表というのは、外部から招聘したスペシャリストではなく、自社に元々いらした方々が務めることのほうが多いです。
スタートアップの成否が経営陣の能力に依存するように、DX部門の成否もまた部門長(さらには経営陣)の能力に依存します。成果の出ないスタートアップは潰れますが、DX部門は予算が付き続けることも多いので、見かけ上はさほど問題がないように見えるかもしれません。
私もこの3年間、さほど不自由や転覆の不安もなく取り組んできたのですが、事業の進展のなさにモヤモヤを抱え続けてきました。コアビジネスが我々の取り組みによって改善している感覚も得られませんでした。
私自身、この会社や働くメンバーは好きでしたし、待遇に困るわけでもありませんでした。しかし先々のことを考えても、この会社でお力になれる未来も見えず、この部門が解散になった場合も踏まえて、退職することを決めました。
有名なJTC、それも業界トップを張っているような企業であっても、DX部門や新規事業開発のような部門がうまくいっているとは限らないのだなあと、当たり前ですが気付かされました。あるいは、見かけ上うまくいっているようでも、実態としては停滞しており、ズルズルと延命しているだけの可能性もあります。そのあたりを入社前に見極めることが重要かもしれません。
私は今、改めてソフトウェア企業で楽しくエンジニアとして働いています。JTC時代は正直エンジニアリング以外の業務が多く、少しブランクを感じていたのですが、その部分も面接で正直に話したうえで採用されたので、本当にありがたい限りです。
一方で、年齢や在籍期間によっては、キャリアを大きく下げてしまったり、停滞させてしまう可能性もあります。JTCに所属し、社会貢献といった大義名分を持って働けることは嬉しい限りですが、そもそも事業や組織として上手く成立していないようでは、我々エンジニアは無力です。そのあたりは入社前に厳しくチェックすることをオススメします。
以上、ご参考になれば幸いです。
結局セッションIDやトークンはLocalStorageとCookieのどちらで持てば良いのか
以下の通り、OWASPによるとLocal Storage にセッションIDを保存するのはやめときなさいと言っているので、私はそれに従おうと思う。
https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#local-storage
Do not store session identifiers in local storage as the data is always accessible by JavaScript. Cookies can mitigate this risk using the httpOnly flag.
セッションID自体を盗めなくても、XSSによる攻撃は可能だから、Local Storageに保存しても結局変わらないのでは?という指摘も散見される。しかし私見を述べるならば、それがセッションID自体を盗む攻撃を防げなくてもいい理由にはならないと思っている。
適切に設定されたCookieの値をJavaScriptで取得することは出来ないが、Local Storageの値はJavaScriptで取得することができる。個人的には、適切に設定するという前提で、Cookieに保存するようにしたい。
MQTTには順序性があるがAWS IoT Ruleにはなさそう
以前の記事でMQTTでは概ね順序を重要視していることを述べた。
ここで気になるのはIoT関連サービスとしてよく利用するAWS IoTについてだが、残念ながらAWS IoT Ruleの実行順序保証はないようだ。以下はSQSの記述だが、「ルールエンジンは完全に分散されたサービスであるため、...」のくだりは一般的な話に読める。
https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/sqs-rule-action.html
注記
SQS アクションは、Amazon SQS FIFO (First-In-First-Out) キューをサポートしていません。ルールエンジンは完全に分散されたサービスであるため、SQS アクションがトリガーされたときのメッセージ順序の保証はありません。
なむなむ。
MQTTのv5.0では送信順序通りにPUBLISHが処理されるがv3.1.1では確実ではない
表題のとおりである。これは、過去記事で述べたように、v5.0では再接続時以外でのPUBLISH (PUBREC, PUBREL) の再送が許されないのに対し、v3.1.1では明示的に禁止されていないからである。
まずTCPから考えると、TCPは送信順序(シーケンス番号)を受信側で保証する。言い換えると、TCPのパケットは受信側に異なる順序で到達することもあるが、受信側で届いたパケットを送信した順に正しく並べ替える。これにより、上位のアプリケーションは、TCPソケットから順番通りにデータを受け取ることができる。もっといえば、到達パケットを格納するバッファの最前列に歯抜けのパケットがある場合、そのパケットが到達するまでTCPソケットはアプリケーションにデータを渡さないことになる。
ここで改めてMQTTについて考えると、MQTTサーバ (MQTTブローカー) は、PUBLISHを、MQTTクライアントから送信された順番通りに、TCPソケットから読み取れるということになる。これはつまり、MQTTクライアントがPUBLISHのデータをTCPソケットに書き込んだ順番通り、MQTTサーバがデータを処理することができるということである。
また、MQTTサーバ側からMQTTクライアント (SUBSCRIBE元) へPUBLISHする際にも、MQTTクライアント (PUBLISH元) からの到達順にPUBLISHを配信することが必須とされているので、MQTTクライアント(A)から送信されたPUBLISHは、それをSUBSCRIBEするMQTTクライアント(B)においても同じ順番で処理されるはずである。以下、この点についてv3.1.1およびv5.0の仕様を抜粋する。
v3.1.1 https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718105
When a Server processes a message that has been published to an Ordered Topic, it MUST follow the rules listed above when delivering messages to each of its subscribers. In addition it MUST send PUBLISH packets to consumers (for the same Topic and QoS) in the order that they were received from any given Client
v5.0 https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901240
When a Server processes a message that has been published to an Ordered Topic, it MUST send PUBLISH packets to consumers (for the same Topic and QoS) in the order that they were received from any given Client
一度TCPソケットに送信を依頼されたPUBLISHは、そのTCPコネクションにおいて同じシーケンス番号で取り扱われ続けるので、仮にロスが発生しても同じシーケンス番号で再送される。よって、仮に後発の新しいPUBLISHがロスなく送信されて先に対向へ到達したとしても、TCPは送信順序を保証するためにロスしたPUBLISHの到達を待つので、最終的には正しい順番でMQTTアプリケーションに渡ることになる。
ここでようやく表題の話ができる。v5.0では再接続時のみ再送を許すため、データの取り扱いがTCPコネクションにすべて委任され、対向側で送信順序どおりに処理されることが保証される。一方v3.1.1の場合、MQTTレベルでの再送が発生すると、同じPUBLISH (同じPacket Identifier) が異なるシーケンス番号で送信されてしまう。例えばQoS1だとすると、重複の可能性を踏まえて以下のような違いが生まれる可能性がある。
MQTTレベルで再送される場合にありえる処理順序
<- | PUB1 (ID: 1) | PUB2 (ID: 2) | PUB3 (ID: 3) | PUB1 (ID: 1) | <-
MQTTレベルで再送しない (TCPに任せる) 場合の処理順序
<- | PUB1 (ID: 1) | <- ... (PUBACKを受け取らないままコネクション切断)... <- | PUB1 (ID: 1) | PUB2 (ID: 2) | PUB3 (ID: 2) | <-
※ 切断前にPUBACKさえ受け取れれば重複はしない理解でいる。
なお、コネクションが切断されて再接続した際の再送順序についても、以下の通り前回接続時に送信を試行した順とすることが義務付けられている。これにより、仮に途中でコネクションが切断されたとしても、当初の送信順序どおりに対向でデータが処理されることとなる。
V3.1.1 https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718105
When it re-sends any PUBLISH packets, it MUST re-send them in the order in which the original PUBLISH packets were sent (this applies to QoS 1 and QoS 2 messages) [MQTT-4.6.0-1]
V5.0 https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901240
When the Client re-sends any PUBLISH packets, it MUST re-send them in the order in which the original PUBLISH packets were sent (this applies to QoS 1 and QoS 2 messages) [MQTT-4.6.0-1]
ここまで話してきて、MQTTでは順序の取り扱いが思った以上に厳格であるということがわかる。コネクションの前提についても以下の通り言及がある。
https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Network_Connections
A Client or Server MUST support the use of one or more underlying transport protocols that provide an ordered, lossless, stream of bytes from the Client to Server and Server to Client [MQTT-4.2-1].
MQTTのv3.1.1とv5.0のPUBLISH再送信は再接続時が基本
MQTTのv3.1.1とv5.0において、PUBLISH (PUBREC, PUBREL) の再送は、再接続に実施されることが基本となっている。特にv5.0では、v3.1.1と異なり、再接続時以外での再送を明示的に禁止している。
まずv3.1.1から引用する
https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718103
4.4 Message delivery retry
When a Client reconnects with CleanSession set to 0, both the Client and Server MUST re-send any unacknowledged PUBLISH Packets (where QoS > 0) and PUBREL Packets using their original Packet Identifiers [MQTT-4.4.0-1]. This is the only circumstance where a Client or Server is REQUIRED to redeliver messages.Non normative comment
Historically retransmission of Control Packets was required to overcome data loss on some older TCP networks. This might remain a concern where MQTT 3.1.1 implementations are to be deployed in such environments.
つぎにv5から引用する
https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901238
4.4 Message delivery retry
When a Client reconnects with Clean Start set to 0 and a session is present, both the Client and Server MUST resend any unacknowledged PUBLISH packets (where QoS > 0) and PUBREL packets using their original Packet Identifiers. This is the only circumstance where a Client or Server is REQUIRED to resend messages. Clients and Servers MUST NOT resend messages at any other time [MQTT-4.4.0-1].If PUBACK or PUBREC is received containing a Reason Code of 0x80 or greater the corresponding PUBLISH packet is treated as acknowledged, and MUST NOT be retransmitted [MQTT-4.4.0-2].
いずれも "When a Client reconnects with ... , both the Client and Server MUST re-send any unacknowledged PUBLISH Packets (where QoS > 0) and PUBREL Packets using their original Packet Identifiers" とある。つまり、再接続時にはACKを受け取っていないPUBLISHやPUBRELを再送しなくてはならない。
次にv3.1.1の引用にある "Non normative comment" に着目すると、古いTCP/IP実装ではControl Packetの再送が必要かもしれないと言っている。つまり、v3.1.1では、「再送信は再接続時に必須」という基本はありつつ、再接続を待たずにControl Packetを再送してもよい、と読める。
次にv5の引用を見ると "This is the only circumstance where a Client or Server is REQUIRED to resend messages. Clients and Servers MUST NOT resend messages at any other time" とある。つまり、「再送信は再接続時に必須」かつ「再接続時以外には再送禁止」と言っている。
実際のところ、v3.1.1実装の機器を使っていると、再接続を待たずに再送している場合があるように思う。