人生100年!生涯エンジニア人生!

楽しいエンジニア人生!

長年苦しめられてきた、ドコモメールの駄目な仕様が、iOS14のお陰で予定より早く消えそうで嬉しい!

iOS14の仕様変更

iOS14の仕様変更で、ドコモメールの駄目な仕様に設定されているとメール送信できないことになりました。

ドコモのアナウンスです。
service.smt.docomo.ne.jp

auのアナウンスです。
www.au.com

この駄目な仕様は「2連続のドット「..」が含まれていたり、アットマーク前にドット「.@」が含まれているメールアドレス」のことで、これはRFC5321で決めたことに違反しております。

RFC5321の4.1.2. Command Argument Syntaxに仕様が記載されていますが、難解なので..や.@のメールアドレスはRFC違反だと思ってください。

RFC 5321 - Simple Mail Transfer Protocol

歴史的な経緯

RFC違反のメールアドレスは、ドコモのiモードメール(現在のドコモメール)が発祥の地で、迷惑メールの多いドコモでは、RFC違反のメールアドレスにはパソコンからのメールが届かないということで、それが迷惑メールが来ないメールアドレスとして広まってしまいました。

それだけで終わると思われた、RFC違反のメールアドレスは、auに伝播します。

2006年6月6日に、auはメールアドレスの文字数を30文字に拡張すると同時に、RFC違反仕様が盛り込まれてしまいました。

k-tai.watch.impress.co.jp

なぜ、auは盛り込んでしまったのか?今となっては推測でしかないですが、2006年10月24日から番号ポータビリティ(通称MNP)が開始されたからとも言われております。
MNP後はMNPする前のキャリアメールは使用できなくなるので、携帯電話会社を乗り換えた後も、ドメインは異なっていても同じローカルパート(@の左側)を使用したいという需要に答えたのではないか?と推測します。

k-tai.watch.impress.co.jp

その後、ドコモが2009年4月1日から、RFC違反メールアドレスを新規登録をやめる方針に切り替わりました。

www.nttdocomo.co.jp

ドコモのメールアドレス変更のページには以下の記載があります。

また、2009年4月1日以降、「.」は「..」などのように連続で使用することや@マークの直前で使用することはできなくなりました。

この変更は2009年9月1日から始まるSPモードのためかと推測されます。

www.nttdocomo.co.jp

この対応で、RFC違反メールアドレスが減ると思われましたが、意外としぶとく残りました。
ガラケー同士はもちろん、携帯電話会社提供のメールアプリはRFC違反のメールアドレスが使えてしまうからです。
そして、iOS13までのメールアプリとメッセージアプリも、RFC違反のメールアドレスが使えていました。

このため、ドコモ同士や携帯電話会社間ならRFC違反のメールアドレスの送受信は可能なのです。
2020年の今ままで、11年間もRFC違反のメールアドレスは残ってしまったのです。

まとめ

今回iOS14の仕様変更で、RFC違反のメールアドレスが設定されているとメール送信ができないことは、大変喜ばしいことです。

アプリが対応してくれればRFC違反のメールアドレスはガラケーのみになるし、2026年3月31日にドコモのiモードが終了するので、このときにRFC違反のメールアドレスがこの世から消え去るのです!
メルマガ配信をしていた自分としては、本当に早く消えて去ってほしいと心から願うのでした。

おまけ

GmailRFC違反のメールアドレスを送信してみましょう!

macOSにDefaultで入っているPostfixを有効にして、Gmailにリレーするように設定をして試してみます。

% echo 'Test mail' | mail -s test test..@example.com
2020-11-16 00:15:31.961215+0900 0x1ff82a   Info        0x0                  67732  0    smtp: A44B369D557: to=<test..@example.com>, relay=smtp.gmail.com[64.233.189.108]:587, delay=1.3, delays=0.02/0.02/1.1/0.17, dsn=5.1.3, status=bounced (host smtp.gmail.com[64.233.189.108] said: 553-5.1.3 The recipient address <test..@example.com> is not a valid RFC-5321 553 5.1.3 address. o132sm15287203pfg.100 - gsmtp (in reply to RCPT TO command))

not a valid RFC-5321 と返答があることが確認できますね。

なお、コマンドラインで送信するとき、かなり気を付けないといけなくて、ちょっとしたことで危険な事になりかねないのです。

これは大丈夫ですがバッククォートを含んだメールアドレスをコマンドラインで送信すると、バッククォートの中を実行した結果が反映されてしまいます。
下の例だと、macOSで動かしているのでOSの名前Darwinに変換されています。
ちなみに、バッククオートが入ったメールアドレスはRFC違反ではないです。

% echo 'Test mail' | mail -s test test`uname`@example.com
2020-11-16 00:12:37.105535+0900 0x1fe590   Info        0x0                  66990  0    smtp: 82F9369D4E7: to=<testDarwin@example.com>, relay=smtp.gmail.com[64.233.189.109]:587, delay=2.6, delays=0/0/1.7/0.92, dsn=2.0.0, status=sent (250 2.0.0 OK  1605453157 gx24sm15347740pjb.38 - gsmtp)

同様に、ハイフンが入ったメールアドレスはRFC違反ではないですが、オプションと誤認します。

% echo 'Test mail' | mail -s test '-test@example.com'
mail: illegal option -- t
Usage: mail [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...
       mail [-EHiInNv] [-F] -f [name]
       mail [-EHiInNv] [-F] [-u user]
       mail -e [-f name]
       mail -H

20時半からのConnpass(「勉強会がリモート開催になり、勉強会に参加しにくくなった件」の反響を受けて)

概要

「勉強会がリモート開催になり、勉強会に参加しにくくなった件」という記事を書きました。
kawahara-ci.hatenablog.com

その反響で多かったのは夜遅くなら参加できるというのがありました。

b.hatena.ne.jp

親世代でリモートワークの人は、子どもが寝たあとなら参加できるのでは?ということです。
そこで疑問がありました、夜遅くに開催している勉強会はあるのでしょうか??

結果として確認するサイトを作成しました。
「20時半からのConnpass」です。
nightstudygroup.netlify.app

確認する

勉強会を告知するサイトで有名なConnpassを確認する。
開催日は見ることはできるようですが、時刻までは見ることはできません。

connpass.com

検索で指定できるかな?と思いましたが、日付のみの検索でした。

connpass.com

APIを見る

何とかできないかな??
そうだ!APIを見てみよう!!
connpass.com

日付や月単位の検索はできるようです。

Google App Scriptを使う

APIがあるなら、データの取得は簡単です。
とりあえず、データを取得してみましょう!
Google Spreadsheetに持ってこれるじゃないか!
そう!Google App Script(通称GAS)なら簡単です。
ソースコードは綺麗じゃないのはご了承ください。)

// ConnpassのAPIを使ってデータを取得する
function get_connpass_data() {
  // 4ヶ月先までのパラメータを作成する
  var dt_object = [];
  for (var i = 0; i < 5; i++) {    
    var dt = new Date(new Date().setDate(1));
    var work_date =new Date(dt.setMonth(dt.getMonth() + i));
    dt_object.push(String(work_date.getFullYear()) + ('00'+(work_date.getMonth() + 1)).slice(-2));
  }
  var url_date = dt_object.join(',');

  // シートを選択しクリアする
  var sheet = set_sheet('data');
  sheet.clearContents();

  // 先頭のcolumnを設定
  column = [['event_id', 'title', 'event_url', 'started_at', 'ended_at', 'place', 'address']];
  sheet.getRange('A1:G1').setValues(column);
  var today = new Date(new Date().setHours(0, 0, 0, 0));

  // ページングの初期値
  var start = 1;

  do {
    // APIをfetchする
    var url = 'https://connpass.com/api/v1/event/?order=2&ym='+ url_date + '&count=100&start=' + start;
    var res = UrlFetchApp.fetch(url);
    var object = JSON.parse(res.getContentText()); 

    // APIのResultを取得する
    var results_returned = Number(object['results_returned']);
    var results_start = Number(object['results_start']);
    var results_available = Number(object['results_available']);

    var values = [];
    for (var i = 0; i < object['events'].length; i++) {
      var value = [];
      var has_today = false;
      
      for (var key in object['events'][i]) {
        // 取得するデータを選ぶ
        if (['event_id', 'title', 'event_url', 'address', 'place'].includes(key)) {
          value.push(object['events'][i][key]);
        }

        // 日付はローカル時間に変換する
        if (['started_at', 'ended_at'].includes(key)) {
          var dt = new Date(object['events'][i][key]);
          var words = dt.toLocaleString();
          value.push(words);
        }
        
        // 開催日時が今日より過去ならデータを取得しない
        if (['started_at'].includes(key)) {
          var dt = new Date(object['events'][i][key]);
          var words = dt.toLocaleString();
          var words_split = words.split(' ');
          if (today.getTime() <= new Date(words_split[0]).getTime()) {
            has_today = true;
          }
        }
      }

      if (has_today) {
        values.push(value);
      }
    }

    // Spreadsheetにセットする
    sheet.getRange(start + 1, 1, values.length, values[0].length).setValues(values);

    // 今日より過去なら処理終了する
    if (!has_today) {
      break;
    }
    start = start + results_returned;
  } while((results_start + results_returned) < results_available);

  // 処理完了後、開催日時でソートする
  var range = sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn() -1);
  range.sort(4);
}

//同じ名前のシートがなければ作成
function set_sheet(name){
  var sheet = SpreadsheetApp.getActive().getSheetByName(name)
  if(sheet)
    return sheet

  sheet=SpreadsheetApp.getActiveSpreadsheet().insertSheet();
  sheet.setName(name);
  return sheet;
}

完成したら、トリガーを設定して1時間毎にデータを取得します。

データを確認する

Google Spreadsheetのフィルターを使って確認する。
うーん、このままだと物足りないな。
ノーコード開発でやってみよう!!

glide.を使ってみました。

www.glideapps.com

ポチポチするだけでサイトが作れました。
pink-leg-5741.glideapp.io

見た目は良いのですが、無料枠はデータ量に制限があるとか、抽出条件の仕方が謎だったりして、納得できませんでした。

SpreadsheetをAPI

それならば先程のGoogle SpreadsheetをAPI化してAPI側がデータを抽出すれば良いのでは?ということで、再びGASを使います。

function doGet(e) {
  //var time_parameter = e.parameter.time;

  var callback = e.parameter.callback;
  
  var sheet = SpreadsheetApp.getActiveSheet();
  var maxRow = sheet.getLastRow();
  var maxColumn = sheet.getLastColumn();
  
  // 一気にデータを取得してJson形式に変換する
  var row = sheet.getRange(1,1, maxRow, maxColumn).getValues();
  var data = parse2Json(row);
  data = data.filter(v => v);
  
  var res = ContentService.createTextOutput(callback + '(' + JSON.stringify(data) + ')');
  res = res.setMimeType(ContentService.MimeType.JAVASCRIPT);
  
  return res
}

// Json形式に変換する
function parse2Json(values) {
  return values.map(function (value, i, arr) { 
    var obj = {};
    if(i === 0) return;
    for(var j = 0 ; j < value.length ; j++) {
      if ('started_at' != arr[0][j]) {
        obj[arr[0][j]] = value[j];
      } else {
        if (Utilities.formatDate(value[j], 'Asia/Tokyo', 'HHmm') < 2030) {
          return;
        } else {
          obj[arr[0][j]] = value[j];
        }
      }
    }
    return obj; 
  }).splice(1,values.length - 1);
}

GitHubはこちらです。

github.com

Netlify化

GASをAPI化したら、あとは表示するだけです。
(Connpass APIを直接叩いても良いのですが・・・)

netlifyとjQueryでサクっと作りました。
www.netlify.com

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>20時半からのconnpass</title>
    <meta name="description" content="20時半からのconnpassを表示します。" />
    <meta property="og:url" content="https://nightstudygroup.netlify.app/" />
    <meta property="og:title" content="20時半からのconnpass" />
    <meta property="og:type" content="website">
    <meta property="og:description" content="20時半からのconnpassを表示します。" />
    <meta property="og:image" content="https://res.cloudinary.com/profile-card/image/upload/l_text:Sawarabi%20Gothic_40_bold:20%E6%99%82%E5%8D%8A%E3%81%8B%E3%82%89%E3%81%AECompass%0A%E4%BD%9C%E6%88%90%E8%80%85%EF%BC%9A@sapi_kawahara/v1592844332/600x315.png">
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:site" content="@sapi_kawahara" />
    <meta property="og:site_name" content="20時半からのconnpass" />
    <meta property="og:locale" content="ja_JP" />
    <link rel="canonical" href="https://nightstudygroup.netlify.app/" />

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">

    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
  </head>
  <body>
    <script>
      $.ajax({
        type: 'GET',
        url: 'APIのURL',
        dataType: 'jsonp',
        jsonpCallback: 'myCallback',
        success: function(json){
        var len = json.length;
        var count = 0;
        for(var i=0; i < len; i++){
          var started_at = new Date(Date.parse(json[i].started_at));
          var ended_at = new Date(Date.parse(json[i].ended_at));
          started_at = started_at.toLocaleString();
          ended_at = ended_at.toLocaleString();
          if ((count % 2) == 0) {
            var card_pattern1 = `<div class="row row-cols-1 row-cols-md-2 g-4">
  <div class="col">
    <div class="card bg-light mb-3">
      <div class="card-body">
        <h5 class="card-title text-truncate">${json[i].title}</h5>
        <p class="card-text">開催日時:${started_at}<br>終了日時:${ended_at}</p>
        <p class="card-text">開催会場:${json[i].place}<br>開催場所:${json[i].address}</p>
        <a href="${json[i].event_url}" target="_blank" rel="noopener noreferrer" class="card-link btn btn-info btn-lg btn-block">${json[i].event_url}</a>
      </div>
    </div>
  </div>
`;
          } else {
            var card_pattern2 = `<div class="col">
    <div class="card bg-light mb-3">
      <div class="card-body">
        <h5 class="card-title text-truncate">${json[i].title}</h5>
        <p class="card-text">開催日時:${started_at}<br>終了日時:${ended_at}</p>
        <p class="card-text">開催会場:${json[i].place}<br>開催場所:${json[i].address}</p>
        <a href="${json[i].event_url}" target="_blank" rel="noopener noreferrer" class="card-link btn btn-info btn-lg btn-block">${json[i].event_url}</a>
      </div>
    </div>
  </div>
</div>
`;
            $("#connpass-data").append(card_pattern1 + card_pattern2);
          }
          count++;
        }
        if ((count % 2) == 1) {
          $("#connpass-data").append(card_pattern1);
        } 
      }
    });
    $(document).ajaxStop(function() {
      $(".spinner-border").remove();
    });
    </script>
    <div class="container">
      <p class="h1">20時半からのconnpass</p>
      <p class="h6"><a href="https://kawahara-ci.hatenablog.com/entry/2020/10/31/Twenty_thirty_Connpass" target="_blank" rel="noopener">これを作成した経緯</a>です。</p>
      <p class="h6">ご要望は <a href="https://twitter.com/sapi_kawahara" target="_blank" rel="noopener">@sapi_kawahara</a> までお願います。</p>
      <div class="d-flex justify-content-center">
        <div class="spinner-border text-primary" style="width: 5rem; height: 5rem;" role="status">
          <span class="sr-only">Loading...</span>
        </div>
      </div>
      <span id="connpass-data"></span>
    </div>
  </body>
</html>

そして出来たのは、こちらです。
「20時半からのConnpass」です。
nightstudygroup.netlify.app

まとめ

JavaScriptが苦手でも、何とか作れました。
こうやって見える化をすると、20時半以降開催の勉強会は多くないですね。
見える化するだけなら、最初のGoogle Spreadsheetを使ってGoogle App Scriptでデータを取得するだけで良かったのですが、ついついノリでやってしまいました。(反省はしてない)
見える化できたので、今後は何かできないか考えましょう。

勉強会がリモート開催になり、勉強会に参加しにくくなった件

勉強会に参加しにくくなった

参加しにくくなったのは自分は以下の3点かなと思っています。

  • YouTubeなどに配信されるので後で見ることができる。
  • 登壇する人が発信するだけで交流が無くなった気がする。
  • 家のことを優先したい。

障壁の洗い出し

後で見ることができる

YouTube Liveで配信後は、そのままYouTubeに残る勉強会もあります。
そうなると、後で見ることができるので、情報を吸収したいだけなら、リアルタイムで参加するメリットが薄れます。

交流が無くなった

zoomの無料枠を使用していると、この傾向は顕著に出ますが、人数制限や接続時間制限が入るためです。
そうなると、参加者はYouTube Liveで見ることになり、登壇が終わり質疑応答が終わると終了になることが多いです。
また、zoomのブレイクアウトルームというのもありますが、発言が得意じゃない人には障壁になっているのかもしれません。

support.zoom.us

家のことを優先したい

19時とかは、夕飯時刻とかぶります。
私は、勉強会に参加して感想や思いをハッシュタグを付けてリアクションすることが多いのですが、夕飯時なので夕飯を食べながらとかは子どもの教育上絶対に良くない!のでやりません。
そのため、夕飯時間をちょっとずらすか、夕飯を後で食べるなどをすることがありますが、家族に迷惑をかけてしまうので、頻繁にできません。

解決方法

オフライン開催時は、主催側としてはスポンサーを付けて軽食を出すなど、私の趣味で日本酒を持ち込むなどして、勉強会にプラスの要素も盛り込んでいきました。

後で見ることができる

この上記の件は、オンラインでは難しいですが、後で見るのを応用が可能だと思っています。
リアルタイムのときだけ聞けるプレミアムな話とか、リアルタイムのときだけにアンケートを取り希望者のみに景品などを送るなど工夫をすればいけそうな気がします。
そういう勉強会なら、私も参加しやすいかもしれません。

交流が無くなった

交流については、オフライン開催時も悩みの種だったので、これはオンラインになっても変わらず考えていきたいです。
オフライン開催時も、そうでしたが、私は聞き役に回ることで逆に交流できた感じなので、この方法はオンラインでも使っていきたいです。

家のことを優先したい

家のことは、昼間に開催とか21時開催とか、時間をずらす方法しか今は思い付きません。
家族に迷惑をかけずに、子どもと団らんをしつつ、19時の勉強会に参加というのは非常に難易度が高いです。
ここはVRを超える、ソリューションが出れば!と思ったが、私は聖徳太子では無かったので、家族と取り決めをして参加する勉強会を選択するしか無いですね。

50代のオッサンが、飲み会のときに、偉そうに若者に語るクソつまんない話

きかっけ

「50代のオッサンが、飲み会のときに、偉そうに若者に語るクソつまんない話」とは何か?説明します。

武勇伝

「俺が若いときは、こんな楽じゃなかったよー」という苦労話。
「限界を超えてみろ!そうすれば楽になる」という無理強い話。
「俺は毎日終電、土日も仕事してた」という俺頑張った話。

これらを武勇伝と呼びます。
こんな武勇伝を聞きたいですか?
飲み会で金を払って聞きたい話ですか?

聞きたくないですよね!!

武勇伝は得られる知識が無い

仕事での苦労なんて、ひとそれぞれで、聞いた側の参考になるのは少ないです。
無理をする話なんて、無理の限界値なんて人によって異なるので参考になりません。
頑張った話?あー、そうですかーとしか思えないです。

武勇伝というのは知識としては価値がなく、クソつまんない話なのです。

生存者バイアス

「生存者バイアス」って言葉をご存知でしょうか??
または「勝者の理論」とも言うときもあります。
武勇伝というのは生存者バイアスで、語った者が勝者なので、勝者の話にしかないないのです。
ブラック企業などは、この生存者バイアスを理解せずに、どんどん悪循環な企業風土を作り上げていきました。
それについていけないと会社を辞めるか、そして社会問題もなりましたが多くの事件がありました。

採用人事に関わってない私でも、この辺りは認識しております。

なお、生存者バイアスについては、検索すれば多数の資料やブログが出てくるので、ここでは多くは書きませんが、武勇伝=生存者バイアスだと思っていただければ良いと思います。

苦労話の伝え方

登壇するときは、この生存者バイアスは無茶苦茶気にしております。
そのため苦労話は、面白くするために演出にならない程度に脚色をしてます。
実際の話は、本当にダークで嫌悪感しか無いです。
そのため、登壇以外で、相談者が本当に聞きたいとき、苦労話を伝えるときはあったりします。
ただ、そのときも、できるだけ楽しい話を交えて話すように心がけてます。

当然ですが、匂わせる発言も良くないです。
「1週間徹夜しました!」とか「最近の若者は!」とかのような匂わせ発言を肯定する老害発言が群がります。
だから、そういうツイートは避けたいですね。

おまけ

あと、蛇足ですが、上司の飲み会での自慢話も聞いてて無駄でしょ?wwww

私は、結構前から、オッサンの武勇伝は無駄と言っております。
2020年5月25日のツイートでも「飲み会の自慢話は無駄」とツイートしていました。

結局のところエンジニアは、いつどこで勉強すれば良いのか?

概要

「エンジニアに独学を期待するのはもう時代遅れだと思う。」というブログが話題になりました。
cloverstudioceo.hatenablog.com

要約すると、業務時間外に勉強を強いる企業は駄目ってことです。
それは当然で、それを行わせるなら賃金を払うべきであるし、労働時間になるのだから長時間の労働も強いてはいけないです。
日本という国は、「朝早く出社して仕事の準備をして必要とあれば勉強をしておく」ということが美徳されており、それでいて賃金を払わないという、本気で意味不明な慣習が存在しました。

これはエンジニアに限らず、日本古来の働き方に蔓延していた病だったと思います。

そして、話題になったブログでは、きっかけになった記事があるので、こちらも確認してみます。 全てのエンジニアに向けて「エンジニアとして生き残るために」を読みます。
www.ntt.com

要約すると、長年エンジニアとして生きていくための戦略をどう描くかということです。
共感できる内容で、勉強という観点から見ると、多くのベストプラクティスが書いてあり、全てを実行するのは難しいかもしれませんが、1つでも実行できれば今後の人生が大きく変わると思います。

その根拠として、私は「(3)毎年1つ新しい言語を学ぶ」を近い状態でやっており「学ぶ」ことはしております。
新しい言語は文化を学ぶことであり、読むだけでもワクワクします。
そして、その言語で良い考え方があったら、別の言語でも、その良い考えを取り入れてます。
多くの開発言語は宗教のようないがみ合う世界ではなく、お互いに影響し合う世界で、それをいち早く自分の世界に構築できるのは非常に楽しい世界だと思います。

読んでて違和感がある

どちらも重要なことを言っています。 そして大切なことを伝えようとしています。

しかし、読んでいると何か違和感があります。
そう、話しているところが似ているようですが、お互い話が噛み合っていないのです。
勉強という観点から読み進めてみると、片方は「独学しろと言っていない」けど、もう片方は「なぜか独学しろ」という話として物語ができてしまい、話が噛み合っていないのです。

エンジニアに独学を期待するのはもう時代遅れだと思う。 - ヨーロッパで働くIT土方社長のブログ

おっしゃる通りで「技術者だったら独学せよ」だと投げっぱなしになってしまうので、業務時間内でみっちりとメンタリングする習得主義の社内研修制度を10月から開始したところです

2020/10/13 14:28
b.hatena.ne.jp

社内研修制度を10月から開始したところです

そのため、上のようにフォローも入っているので、独学についての噛み合っていないところは、特に業務時間内についての齟齬は解消されていると思います。

解決!?

社内研修制度のことも明らかになって、これで解決!良かった良かった。

いや、そうじゃない!!!!

Googleという会社では「20%ルール」というのがあります。(今もあるのかな?)
これは業務時間に普段の職務を止めて自身が取り組みたいことをして良いということで、日本のメガITベンチャー企業でも取り入れている会社もあり、これに似た社内研修制度が増えることは良いと思います。 そして、今年2020年から、学校でのプログラミング教育も始まり社会として、学ぶ機会が増えることは良いと思います。

しかし、社内研修制度が無い会社もあります。
更にいうと、エンジニアじゃない方がエンジニアを目指すとき、社内研修制度を利用できないことも考えられる。
学生時代は興味無かった人が、人生のライフステージの変化でプログラミングに興味を持つことも考えられる。

そういう人はプログラミングの勉強をする機会が無いように感じてしまいます。

そうなってくると、話は「独学」というところに戻ってきてしまいます。

もう一度読み直そう

何か重要なことを見落としていないか?もう一度読み直してみよう。

「エンジニアに独学を期待するのはもう時代遅れだと思う。」には「ライフワークバランス」という言葉が出てきます。
cloverstudioceo.hatenablog.com
一般的には「ワークライフバランス」のことなので、それの説明としては「やりがいや充実感を感じながら働き、家庭や地域生活などにプライベートなところで多様な生き方をする」ということなので、業務時間外に業務の勉強などはしないで、プライベートはプライベートで楽しめば良い。
その通りございます。
プライベートな時間こそ大切な人や自分の趣味に割り当てて、自分の生活をより良いものにしていくこそ、最高の人生になると思います。

全てのエンジニアに向けて「エンジニアとして生き残るために」にも「ワークライフバランス」という言葉が出てきます。
www.ntt.com
たぶん、この2つの記事は、どちらも「ワークライフバランス」のことを強く言いたかったのです。

ワークライフバランスについて

大事な言葉を見落としておりました。
ワークライフバランス」です。

言っているベクトルは少々異なりますが、最終的な目的地は同じ「ワークライフバランス」でした。

一般的には「仕事=イヤなこと」「プライベート=楽しいこと」というイメージがあります。
さて、ここでもう1つの疑問が出てきます。
エンジニアの仕事はイヤなことでしょうか?
まあ、人によっては「イヤ」と感じている人も居るでしょう。
私は「イヤ」ではないです。
概要でも書きましたが、私にとって新しい言語は文化を学ぶことであり、読むだけでもワクワクします。
自分にとって、仕事は毎日が新しい発見なのです。
そのために、気付くと「夜中でも勉強」などをしてしまいます。

私は、この仕事とプライベートの境界線をなくし、1日中大好きなことができれば、それこそエンジニアが体験できる最高の「ワークライフバランス」を送れるようになると思っております。

独学と勉強

楽しいことのワークライフバランス、私は勉強でした。

そのため、私のようなタイプが勉強をやめろと言われてもやめないでしょう。
結局、好きな人は独学をし続けてしまいます。
自走するタイプと言われるかもしれませんが、単なる器用貧乏だと思っています。

バブル期ぐらいまで時代をさかのぼれば、このような人は便利に使われます。
実際、自分は便利に使われました。
コンシューマーゲーム(昔の話)を作りながら、秋葉原にパソコンを買いに行ったり、インターネットの時代になるとOCNエコノミーを導入してファイアーウォールの代わりにプロキシサーバー立てたり、メールサーバーも立てたりしてました。
Aliasのネットワークレンダリングするために、10Baseのスイッチングハブを自腹で検証したり、DECのアルファマシンまで手を出すなど、今思うと、こき使われてただけですが、当時の自分は技術が蓄積される上に楽しいからやってました。

楽しさが学びの源泉で、それがうまい具合に勉強をするスパイラルを生んでいたと思います。 この楽しさが続く限り、独学は続けたいなと思っております。

蛇足ですが、老害エンジニアは、これを「俺の時代はな」と語ってしまいウザいって言われるので、普段の雑談では語らないようにします。

いつどこで勉強すれば良いのか?

業務時間外に勉強することが美徳だった時代は、それが許されていましたが、今はそのような時代ではないです。

cloverstudioceo.hatenablog.com

会社として、エンジニアたるもの4ヶ月に一冊は本をよみ、年に一つは新しい言語を覚えるもんだ、みたいな事を言ってるような所には誰も来てくれないわけですよ。

「エンジニアに独学を期待するのはもう時代遅れだと思う。」にも記載がありますが、上のようなことをいう会社は誰もこないというのは過言ではなく、その通りだと思います。

繰り返し言いますが、会社が個人の勉強に対して予算を使うことが制度としてあるべき姿が望まれることであり、多くの企業が行っていることで、他にも書籍代の補助などもしている企業もあります。
勉強において、率先してやる人、それとなく平穏にやる人、言われてもやらない人など、色々な人が居ますし、メンターを付けたとしてもメンターとの相性問題もあったりと、企業が提示するのは限界があります。
この辺りは、企業の体力によりますが、できるだけ、その人にあった方法が提示できれば良いかなと思います。

独学派について

私の場合は、その制度が無くても勝手にやってしまう独学タイプなのです。
つまり、エンジニアには「独学でやらない人」と「独学でやる人」の2種類の人が居るということです。
独学でやる人は勉強を勝手にやってしまうので、企業の方針と合わなくなるリスクも実はあったりします。
エンジニアの流動性は、この辺りが起因しているかもしれません。

私のようなエンジニアは、テクノロジー全般や今後の流行りスキルなどが大好きで、そちらの興味を追い求めてしまいます。
そのような人を、1つの企業に留めて置くのが良いのか?それは私もわかりません。

今は、独学することは企業の人として発信するつもりは毛頭ないですが、独学は楽しいぞということ発信は続けたいと思います。

独学で勉強を続ける人の勉強する場所は、企業だけによらないためコロナが流行る前は、多くの勉強会に参加して自分からのアウトプットをしておりました。
それが最適解だとは思いませんが、それをすることで自分を表現できると考えます。
そう、私は放浪のITエンジニアなのだから!