素人Web屋の備忘録

素人Web屋の備忘録。たまに雑記。

HTTP通信のこと

今までよくわかっていなかったHTTP通信周りの知識を得るためにこちらの本を読みました。
初版が2010年なのでほんの一部だけ古い内容などもありますが、全体を通してすごく面白くて一気読みできましたし、とても勉強になりました。

よくわからないところは流し読みしてだいたい5時間程度で読めた感じです。
自分が知りたかった内容が網羅されていたので個人的にはとても満足できる一冊でした。

こちらの本で学習したことを備忘録として簡単にまとめていきます。


URI(Uniform Resource Identifier)とは

  • リソースを統一的に識別するID
  • URIを使えばWeb上にあるリソースをユニークに表せる

URIの構成

  • URIスキーム + ホスト名 + パス + クエリ
    ※この構成は代表的な構成で、ほかにも色々な構成がある
/*
スキーム http://
ホスト名   news.google.com
パス     /
クエリ   ?hl=ja&gl=JP&ceid=JP:ja
*/
https://news.google.com/?hl=ja&gl=JP&ceid=JP:ja



HTTPとは

HTTPはHTML、XML、画像、動画、javascript、各種オフィス、PDFなど何でも転送できる。
バージョン1.1が長く利用されてきたが現在は2.0が広まりつつある。

TCP/IPとは

ネットワーク層(ここで使用されるプロトコルはIP)でパケットを送信する。IPを使って宛先を特定する。
トランスポート層(ここで使用されるプロトコルTCPまたはUDP)でコネクション張る。(ネットワーク上の接線)
ネットワークレイヤーの上にWebがあり、コネクションはネットワークで確立され、セッションはWebで確立される。

クライアントサーバとは

HTTPメッセージ

リクエストとレスポンスはHTTPメッセージと総称される。

HTTPメッセージ(リクエスト)の構成

  • リクエストライン
  • ヘッダ
  • ボディ

HTTPメッセージ(レスポンス)の構成
* ステータスライン
* ヘッダ
* ボディ

ステートレスとは

サーバがクライアントのアプリケーションの状態を保存しない制約
アプリケーションの状態とはセッションの状態のこと。
処理に必要な情報はすべてリクエストに含まれる。


後日HTTPメッセージのヘッダについてまとめようと思います!
ここまで読んでいただいてありがとうございました!!!

Promise基礎

仕事でNode.jsを使うことになって非同期処理でPromiseやasync/awaitをよく使うので今回はPromiseについてまとめました。
async/awaitについては別の機会にまとめようと思います。


Promiseの特徴は4つあります。

  • Promiseオブジェクトは3つの状態を持っている(Pending, fulfilled, rejected)
  • 状態は変化する(Pending -> fulfilled or rejected)
  • Promiseの状態によってその後の処理が変化する
  • then()で処理をチェーンできる(callback地獄にならない)

Promiseの使い方

  • return new Promise((resolve, reject) => {do something})でPromiseオブジェクトを作ってreturnさせる関数を用意する(作ったときは状態はPending)
  • その関数を呼び出して状態変化させたPromiseオブジェクトを次の処理に渡す
  • 次の処理ではPromiseオブジェクトの状態によって処理が分岐する(以下のソースではconsole.log(result)orconsole.log(error)

※Promiseの使い方補足
Promiseオブジェクトはresolveの処理が行われるとfulfilledになる
Promiseオブジェクトはrejectの処理が行われるとrejectedになる
以下のソースのpmFnc(true)が呼ばれるとPromiseオブジェクトはresolveを実行してfulfilledになる
Promise(pmFnc(true))の結果はコールバック関数の引数(.then(result => ...)で受け取れる(resultのこと)

function pmFnc(result) {
  return new Promise ((resolve, reject) => {

    if(result) resolve('success!')
    reject('failure...')
  })
}

pmFnc(true)
.then(result => {
  console.log(result)
})
.catch( error => {
  console.log(error)
})

console.log('1st comment')

結果は以下

1st comment
success!


簡単にですがPromiseについてまとめました!
次はasync/awaitについてまとめたいと思います。

読んでいただいてありがとうございました!!

Express基礎

復習しながら自分用にmdでメモってましたがせっかくなので備忘録としてこちらに残します。
2018.11月からB2BSaaSに転職したことでNode.jsを書く機会があるのでNodeの学習を再開しました。
前に学習していたときから時間が空いて色々忘れている部分も多かったのでexpress-generatorの雛形+過去に自分が書いた記事を見て復習中です。

Node.jsについて書いた過去のエントリはこちら



Express自体

ルーティングとミドルウェアのWebフレームワーク
Expressはリクエストが来たら上から評価される

Expressアプリケーション

一連のミドルウェア関数呼び出し
(連続してミドルウェア関数を呼び出すことで成り立っている)

ミドルウェア関数

以下の3つ所有

  • requestオブジェクト
  • responseオブジェクト
  • request-responseサイクルにおける次のミドルウェア関数に対するアクセス権
    次のミドルウェア関数nextという変数名であらわされる

実行できる4つのタスク

  • 任意のコードを実行
  • requestオブジェクト、responseオブジェクトを変更
  • request-responseサイクルを終了する
  • スタック内の次のミドルウェアを呼び出す
    ※現在のミドルウェア関数がrequest-responseサイクルを終了しない場合はnext()を使って次のミドルウェア関数に制御を渡さなければならない。そうしないとrequestはハングしたままになりガーベジコレクションの対象にならない

Expressアプリケーションで使用できる4タイプのミドルウェア


アプリケーション・レベルのミドルウェアについて

以下の例はapp.use()を使って/ミドルウェアをマウントしている
* /ミドルウェアのサブスタックが形成されたことになる
* /のパスは設定しなくてもよくて、設定しない場合はアプリケーションがリクエストを受け取るたびに実行される
* next('route')を使うことで次のルートに制御を渡している
※app.use()だとnext('route')使えないので注意する(app.METHOD()もしくはrouter.METHOD()で使用可能)

/* GET home page. */
app.get('/', function (req, res, next) {
  if (req.params.id === undefined) {
    next('route')
  }else {
    next()
  }
}, function (req, res, next) {
  res.render('index', { title: 'Express02' });
})

app.get('/', function (req, res, next) {
  res.render('index', { title: 'Express' });
})

エラー処理ミドルウェアについて

  • 引数は(err, req, res, next)の4つでなければいけない
  • 他のapp.use()とroutes呼び出し後に定義する(最後に定義するということ)
  • エラーハンドリング用にapp.use()を使ってエラー処理関数を定義する
  • エラー処理関数でnextを呼ばないときはレスポンスを記述する必要がある
    next(err)を呼び出した時点で、エラー処理関数だけ実行され他のミドルウェア関数は実行されない


エラーを発生させる

var createError = require('http-errors');を使ってエラーを発生させる

エラーコードは以下ページ参照

https://www.npmjs.com/package/http-errors

app.use('/', function(req, res, next) {
  next(createError(404));
});

app.use(function(err, req, res, next) {
  console.log(err) // NotFoundError: Not Found
  console.log(err.message) // Not Found
  console.log(err.status) // 404

  // request-responseサイクルのローカル変数(res.locals)はクライアントにレスポンスを返すまで参照することができる
  // req.app.get('env')で環境を検出
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  //レスポンスのステータスコードを指定
  res.status(err.status || 500);
  res.render('error');
});


また、express-generatorの雛形のapp.jsのソースを色々調べて備忘録コメント残したものが以下です。

// Create HTTP errors for Express, Koa, Connect, etc. with ease.
var createError = require('http-errors');
// The path module provides utilities for working with file and directory paths
var path = require('path');

var express = require('express'); 
var cookieParser = require('cookie-parser'); // サード・パーティー・ミドルウェア
var logger = require('morgan'); // HTTP request logger middleware for node.js. サード・パーティー・ミドルウェア

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
console.log(__dirname) // D:\localhost\node\www

app.use(logger('dev')); // ログの出力フォーマットを指定
app.use(express.json()); // This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser.JSONペイロードで受信したリクエストを解析する
app.use(express.urlencoded({ extended: false })); // This is a built-in middleware function in Express. It parses incoming requests with urlencoded payloads and is based on body-parser.URLエンコードされたペイロードで受信したリクエストを解析する
app.use(express.static(path.join(__dirname, 'public'))); // This is a built-in middleware function in Express. It serves static files and is based on serve-static.HTMLファイルや画像などの静的リソースを提供する
app.use(cookieParser());

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

以下のサイトを参考にさせていただきました。

Express - Node.js web application framework

ミドルウェアの使用 | Express 入門 | CODE Q&A 問題解決 [日本語]

逆引きメモ:expressの使い方 - Qiita

一通り復習が終わったらVue+Nodeで何かwebアプリを作りはじめたいと思います。
ここまで読んでいただいてありがとうございました!!

Vueで書籍管理画面っぽいものを作ってみた

Vueの学習のために書籍管理画面っぽいものを作ってみました。
書籍リストを読む処理にaxiosを使いましたがcodepen上はaxiosを使用しないソースになっています。
axiosを使用したソースはページ下部に載せておきます。

ちなみに書籍リストは以下のユニークなidを持った配列にしました。

[
    { "id":1,  "title": "book01", "price": 100 },
    { "id":2,  "title": "book02", "price": 200 },
    { "id":3,  "title": "book03", "price": 300 },
    { "id":4,  "title": "book04", "price": 400 },
    { "id":5,  "title": "book05", "price": 500 },
    { "id":6,  "title": "book06", "price": 600 },
    { "id":7,  "title": "book07", "price": 700 },
    { "id":8,  "title": "book08", "price": 800 },
    { "id":9,  "title": "book09", "price": 900 },
    { "id":10, "title": "book10", "price": 1000 }
]


仕様

  • 価格絞り込み
  • 数量絞り込み
  • 昇順/降順並び替え
  • 書籍登録
  • 書籍更新
  • 書籍削除
  • 書籍リストのリロード(リロード中にNow Loading表示)
  • 500円以下は10%OFF付ける

価格絞り込み・数量絞り込み

Vueコンストラクタ関数を使ってVueインスタンスを作成します。
Vueインスタンスにはいったんデフォルトで以下のオプションオブジェクトを渡します。

const app = new Vue({
    el: '#app',
    data: {
        budget: 2000,
        amount: 20,
        books: []
    },
)

画面上で入力した値をデータにバインドするためにv-modelディレクティブを使います。

// HTML
<input v-model.number="budget"><span>円以下</span>
<input v-model.number="amount">冊以内に絞り込む


価格絞り込みについて

computedを使います。

  1. filterメソッド(非破壊的)を使って予算以下の書籍リストを構築してreturnする
  2. returnされたリストを表示させる
// computed
matched: funciton() {
    return this.books.filter(books => {
        book.price <= this.budget
    }, this)
}
// HTML
<li v-for="book in matched" :key="book.id">

これで価格の絞り込みが完了です。


数量絞り込みについて

computedを使います。

this.matchからreturnされる配列のうち数量分をsliceする

// computed
amounted: function() {
    return this.matched.slice(0, this.amount)
}
// HTML
<li v-for="book in amounted" :key="book.id">

これで価格の絞り込みからの数量絞り込みが完了です。


昇順/降順並び替えについて

昇順/降順ボタンを押すたびに順序を切り替えるように実装します。

  1. データにflg用のプロパティを持たせてflgの状態で昇順/降順を切り替える
  2. Lodashを使って並び変える
  3. returnされる配列を表示させる
const app = new Vue({
    el: '#app',
    data: {
        budget: 2000,
        amount: 20,
        books: [],
        sort: false // add
    },
)
// computed
sorted: function() {
    return _.orderBy( this.amounted, 'price', this.sort ? 'desc' : 'asc')
}
// HTML
<button @click="sort=!sort">
    <span v-if="sort">降順</span>
    <span v-else>昇順</span>
</button>

これで価格絞り込みと数量絞り込みをした書籍リストを昇順/降順で並び替えることができます。


書籍登録について

  1. 書籍にはそれぞれユニークなidを振っているので書籍リストのlengthに応じてidの値を自動で割り振れるようにlengthを取得するメソッドを用意する
  2. 追加する書籍のプロパティを入力する(idは1で用意したメソッドを使う)
  3. pushメソッドで書籍リストに「入力したプロパティを持つ新しい要素」を追加する
const app = new Vue({
    el: "#app",
    data: {
        budget: 2000,
        amount: 20,
        books: [],
        sort: false,
        titleR: null, // add
        priceR: null  // add
    }
// computed
max: function() {
    return this.books.reduce((a, b)=> {
        return a > b.id ? a : b.id
    }, 0)
}
// methods
regist: function() {
    this.books.push({
        id: this.max + 1,
        title: this.titleR,
        price: this.priceR
    })
    this.titleR = null;
    this.priceR= null;
}
// HTML
<span>書籍名:</span><input v-model="titleR">
<span>価格:</span><input v-model.number="priceR">
<button @click="regist">書籍登録</button>

書籍更新について

  1. 更新したい書籍idと更新後のタイトル、価格を入力する
  2. 更新したい書籍idと一致する要素の配列インデックスを取得する
  3. その配列インデックスのプロパティを$setを使って更新する
const app = new Vue({
    el: "#app",
    data: {
        budget: 2000,
        amount: 20,
        books: [],
        sort: false,
        titleR: null,
        titleU: null, // add
        priceR: null,
        priceU: null, // add
        id: null,     // add
    }
// methods
update: function() {
    if(this.id != "") {
        this.books.forEach(el=> {
            if(el.id == this.id) {
                let target = this.books.indexOf(el);
                this.$set(this.books, target, {
                    id: this.id,
                    title: this.titleU,
                    price: this.priceU
                })
            }
        }, this)
    };
    this.id = null;
    this.titleU = null;
    this.priceU= null;
}
// HTML
<span>書籍No.</span><input v-model.number="id">
<span>書籍名:</span><input v-model="titleU"><br class="spi">
<span>値段:</span><input v-model.number="priceU">円
<button @click="update">書籍更新</button>

書籍削除について

  1. 削除ボタンを押す
  2. 削除ボタンが押された要素の配列インデックスを取得する
  3. spliceでその配列インデックスの要素を取り除く
// methods
delate: function(el) {
    let target = this.books.indexOf(el);
    this.books.splice(target, 1);
}
// HTML
<button @click="delate(book)">削除する</button>

書籍リストのリロード(リロード中にNow Loading表示)について

※ここでは書籍リストを直書きしていますが、axiosを使ってjsonから読ませる方法も次のセクションに記載します。

  1. Vueのウォッチャを使って書籍リストの高さを監視する(データにheightを持たせてデフォルトの高さを0にしておく)
  2. 書籍リストがない場合はNow Loadingの表示を出す
  3. 一秒後に書籍リストをDOMにマウントする
  4. $nextTickを使って書籍リストがDOMにマウントされたら書籍リストの高さを取得する
  5. 取得した高さをstyle属性にバインドする
  6. リロードボタン押下時にいったん書籍リストを空にして2~5の処理を繰り返す
const app = new Vue({
    el: "#app",
    data: {
        budget: 2000,
        amount: 20,
        books: [],
        sort: false,
        titleR: null,
        titleU: null,
        priceR: null,
        priceU: null,
        id: null,
        height: 0, // add
    }
// watch
books: function() {
    console.log(this.$refs.booksCont.getBoundingClientRect().height)
    this.$nextTick(()=> {
        console.log(this.$refs.booksCont.getBoundingClientRect().height)
        this.height = this.$refs.booksCont.getBoundingClientRect().height
    })
}
// methods
loadBooks: function() {
    this.books = []; // リロードボタン押下時のための処理
    setTimeout(()=> {
        this.books = [
            { "id":1,  "title": "book01", "price": 100 },
            { "id":2,  "title": "book02", "price": 200 },
            { "id":3,  "title": "book03", "price": 300 },
            { "id":4,  "title": "book04", "price": 400 },
            { "id":5,  "title": "book05", "price": 500 },
            { "id":6,  "title": "book06", "price": 600 },
            { "id":7,  "title": "book07", "price": 700 },
            { "id":8,  "title": "book08", "price": 800 },
            { "id":9,  "title": "book09", "price": 900 },
            { "id":10, "title": "book10", "price": 1000 }
        ]
    }, 1000)
}
// HTML

// Now Loading箇所
<div class="p-top__loading" v-if="!books.length">
    Now Loading...
</div>

// 高さをbindする箇所
<div :style="{height: height + 'px'}">
    <ul v-cloak ref="booksCont">

// リロードボタン箇所
<button @click="loadBooks" :disabled="!books.length">
    <span>リロード</span>
</button>

書籍リストをaxiosでjsonから読む方法

書籍リストをaxiosでjsonから取得する方法を以下に記載します。
やっていることはjsonから書籍リストを読み込んで1秒後にDOMにマウントする処理をcreatedで実行しています。

// JSON
[
    { "id":1,  "title": "book01", "price": 100 },
    { "id":2,  "title": "book02", "price": 200 },
    { "id":3,  "title": "book03", "price": 300 },
    { "id":4,  "title": "book04", "price": 400 },
    { "id":5,  "title": "book05", "price": 500 },
    { "id":6,  "title": "book06", "price": 600 },
    { "id":7,  "title": "book07", "price": 700 },
    { "id":8,  "title": "book08", "price": 800 },
    { "id":9,  "title": "book09", "price": 900 },
    { "id":10, "title": "book10", "price": 1000 }
]
// methods
loadBooks: function() {
    this.books = []; // リロードボタン押下時のための処理
    axios.get("./json/books.json").then(responce => {
        setTimeout(()=> {
            this.books = responce.data
        }, 1000)
    })
    .catch(e => {
        console.log(e)
    })
}
// created
created: function() {
    this.loadBooks();
}

500円以下は10%OFF付ける

// HTML
<span v-if="book.price < 500 ">10%OFF</span>

分かりづらい部分があるかもしれないので後日リライトするかもしれないです。
あと今はPromiseよりAsync/awaitを使うのが一般的かと思いますので、もう少しモダンな書き方ができるかもしれません。

機能を実装するにあたりこちらの本を参考にさせていただきました!!ありがとうございます!!!
基礎から学ぶ Vue.js
https://www.amazon.co.jp/dp/B07D9BYHMZ/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

ここまで読んでいただいてありがとうございました!!!

未経験で入社したWeb制作会社を退職しました

入社から退職まで

ちょうど一週間前の2018年10月18日、約2年働いたWeb制作会社を退職しました。(正確にはいまは有給消化中で10/31付で退職)
退職を機にこの2年間を振り返り、Web業界未経験で入社した自分がこの2年間どのように働いてきたのか、そして転職に至った経緯をお話してみようと思います。

このエントリを通して、これからWeb業界に進もうと思っている人、現在過酷な労働環境で働いている人にとって何か価値ある情報を少しでも提供できたら嬉しいです。(目安として自分の場合は月の平均残業時間は約70hでMAX150hくらいでした)

元々自分は文系の四大卒でこの業界とは無縁だったんですが、たまたま前職でスマホアプリ関連のカスタマーサポートに従事したことがきっかけでこの業界に飛び込みました。当時はITに関する知識も無くやりたい方向性も決まってなかったので、とりあえず初心者の自分でも理解することができたHTMLとCSSが使える職場を求めて転職活動していました。(HTMLとCSSはドットインストールで学んだ)

現職のWeb制作会社には、ちょうどフロントエンドで退職者が出たタイミングだったようで未経験の自分でも採用してもらうことができました。こちらは後々上司に聞いた話ですが、面接に制作物を持っていったことが好印象だったようです。

自分が入社したWeb制作会社は部門を超えてメンバー同士が仲良く人間関係は良かったです。その中でも自分が所属していたエンジニアチームは、直属の上長を含めて特に仲の良いほうでした。入社当時は未経験にも関わらず自分がやりたい仕事に就け、人間関係の良い職場に入社できて嬉しく思っていました。

入社後は先輩からのお題をひたすらコーディングをしてフィードバックをもらう研修をしていましたが、一週間が経つ頃には現場が案件の山で回らなくなったので、僕もすぐに現場に合流して案件をアサインされる立場になりました。結果としてこの頃を境に退社が終電近くになることが当たり前になりました。

自分の主な仕事としては、LP・Webサイトのコーディング、Webサイトの保守運用でした。立ち位置的にはフロントエンドエンジニアよりコーダーに近い感じでした。jQueryしか書いてませんでしたし、サーバーサイド言語への理解やCMS構築などは得意ではありませんでした。

仕事はかなり忙しかったので終電帰りは多々ありましたし、連日の徹夜(このときはさすがに病んだ)や土日出勤も普通にありました。いま思うとよくやっていたなあと思いますが、当時の自分は次の2つを自分の中に見出すことができていたので激務でもダークサイドに落ちることなく続けられたのだと思います。(もちろんこの2つがあっても病むときは病みますが)

  1. やる気に満ちていたこと
  2. 自分のスキルが日々向上している手応えを感じていたこと

そして自分が転職する主な理由もここにあって、要は現職でこの2つを見いだせなくなったからです。
この2つは循環すると思っていて、自分の場合に当てはめると入社当時はスキルはありませんでしたがやる気がありましたし、やる気があるので能動的に手を動かしてスキルを習得して自信を付けていきました。それがまた新たなやる気を生み出すサイクルがありました。
しかしこのサイクルが仕事を始めて1年半くらいしたときに無くなってしまいました。

制作会社ですのでクライアントワークが主なのですが、上流は案件で使用する技術の変化に対してあまり寛容ではない雰囲気がありました。そのためレガシーな技術を使うことが多く、新しい技術がたくさん世に生み出されているにも関わらず使えないことが多々ありました。(技術スタックといえば大げさですが、たとえば脱jQueryが出来ないとか。)
もちろん上流の意向も理解していて、今まで問題なく動作している環境をわざわざ変える必要はありませんし次も同じ技術スタックで制作すれば何か問題が発生することもありません。 ただ自分としては書いてるソースはいつも似たり寄ったりで(時には使いまわしたり)自分のスキルが向上している感覚を持ちづらくなりました。自然と仕事のモチベーションも低下し徐々に悪循環になっていきました。それに加えて日々SNSなどでエンジニア界隈の情報に触れるたびにスキル不足を実感して自己研鑽しようにも、仕事に忙殺されてなかなか時間を確保できない状態でした。

入社して約1年半経ったときにこの状況に気づき、自分の現状と今後のキャリアに危機感を持ちました。
こうして2018年の春から転職に向けて動き始めて2018年9月に無事内定をいただき、2018年10月18日が現職のWeb制作会社の最終出社日でした。


激務でもダークサイドに落ちないために

現職の環境は労働時間でみるとけっこうハード(月の平均残業時間約70h、MAX150h)でしたし、このくらいの残業だと一応国の定める36協定の特別条項の限度時間も超えきそうな気もします。厚生労働省の定める過労死ラインに届く可能性もありますので一般的に見たら病むリスクは高かったのかなとは思います。(自分の場合は転職活動で忙しかった8月、9月を除く期間の平均残業時間を計算したら72hでした。)

実際のところ激務でしんどいなあと思っていたものの、自分はストレスから体調に支障をきたすようなことはありませんでした。
この点については自分なりにそうならないように気を付けていたポイントがあったので以下に書きたいと思います。
仕事中に気を付けていたこととプライベートで気を付けていたことが違うのでそれぞれについて書きます。

仕事中に気を付けていたこと

  1. 深刻にならない
    短納期で詰められていたり疲れていたりするとネガティブになりがちですが、深刻になるより開き直ってました。実際にもし納期が間に合わなかったとしても死ぬわけじゃありません。一人でコーディングしていると納期に間に合わない=自分に責任があると思いがちですが、実際は営業やディレクターも含めチームで仕事をしているので責任の所存はチームにあります。その時の自分にできるベストを尽くせば良いと開き直って仕事をしていました。

  2. 席を外す
    自席に座って黙々と仕事をすることは大事かと思いますが、ずっと続けているとストレスになるのでよく外に出て散歩していました。
    場合によっては席を外せないくらい詰められるときもありましたが、そういうときはトイレに籠って(逃げ込んで)一息ついたりしていました。
    そして仕事のことを考えないように別のことで思考を埋め尽くしてリフレッシュしていました。(自分の場合はSNS、LINE、休みの予定立てたりとか。)

  3. 不満を言う
    チームメンバーも同様に残業しているケースが多かったためよく駅までの帰り道に仕事の不満を言い合ってました。
    自分の精神衛生上何か不満があれば口に出してしまったほうが良いので、帰り道に不満を言い合える時間はほんと貴重でした。

※前提として普通に生活してて起こる体調不良(発熱とか)とかについてはしっかりお休みいただいていました。

仕事後(プライベートな時間)に気を付けていたこと

  1. 疲れが肉体的疲労なのか精神的疲労なのか見極める
    自分は疲れには肉体的疲労と精神的疲労の2種類があると思っていて、それぞれケアする手段も違うと思っています。
    肉体的疲労から来ている疲れにはマッサージに行ったりお風呂に入って早く寝たり、とにかく体力回復を最優先することで乗り越えていました。
    精神的疲労がある場合は、とにかくリフレッシュすることを最優先にしていました。終電前に帰れたら近所のバーに一人で飲みに行くとか、時間の許す限りマンガ喫茶に籠るとか、用もなくゲーセンに入ってみるとか、仕事漬けの生活の中では感じることがない外部からの刺激を意図的に与えることでリフレッシュしていました。ゲーセンは自分は全く用がないのですが普段感じることのない刺激がたくさんあって上手くメンタルリセットできたことを覚えています。

  2. 運動する
    自分はこの仕事を始めたいころ、体力勝負になると思ったのでジムに入会して週一筋トレする生活を送っていました。
    少し前からエンジニア界隈で筋トレが話題ですが、実際体力もあがるしセロトニンの分泌も促進されてメンタルも安定するし、費用対効果の高いライフハックだと思います。

また、自分の場合は現職の人間関係がとても良かったことが幸運でした。そのためハードワークのストレスはあったものの人間関係のストレスはほぼありませんでした。
もし激務で人間関係も悪い職場があったとしたらそれはすぐに辞めたほうが良いと思います。職場を変えてしまったほうが手っ取り早く一番低コストだと思います。


転職活動へ向けて

転職活動をするにあたり、自分が行ったことは以下の3つです。
1. ブログを開設して、休日に自己学習したことをまとめ、アウトプットすることをはじめました。
2. それと並行して、自分のポートフォリオを作成して、自分のスキルセットを外部に見える化しました。
3. 1と2をやりつつ転職エージェントに登録して、紹介していただいた中で自分のアンテナに引っ掛かる企業に面接にいく。

実際に転職活動をしている期間も仕事は忙しかったので、転職エージェントはかなり役に立ちました。
仕事と転職活動の準備で時間がない中で自分で企業を探すとなるとすごく大変だと思いますが、転職エージェントがその部分を代行して行ってくれるので、スムーズにエントリーから面接まで進むことができました。忙しい人にとっては便利なサービスだと思います。
時間がある人は、自分が気になる企業をネットで探したり、知り合いから情報をもらったりして転職活動するのも大いに有りだと思います。

※自分の場合は仕事が忙しくどうしても面接をキャンセルしなければいけない時もありましたが、先方のご厚意でリスケしてもらうなどしていました。


次の職場のこと

2018年11月からは念願だった自社プロダクトを持っている会社で働きます。
僕自身この2年制作会社で働いてみて受託の働き方の楽しさを感じる一方、基本的に納品して終わる働き方に物足りなさを感じていました。自分が制作したLPやWebサイトは本当にユーザーの役にたったのか、効果はあったのかなど気になることがたくさんありましたがそれに対して何か働きかけることはできませんでした。
その点、自社プロダクトを持っている会社はそのプロダクトをPDCAを回して常に改善し続けることが仕事です。自分の行った仕事について、受託制作に比べて少なからず何かしらの反応はもらえるのではないかと思っています。
実際に働いてみなければ確かなことは言えませんが、ひとつのプロダクトにとことん向き合う働き方がこれから始まると思うと制作会社では味わえなかった楽しさが絶対ありますし、早く価値を提供できるエンジニアになろうというモチベーションが沸々と沸いてきます。
次の職場ではVueやNodeをメインで使うことになりそうですが、この点も自分が自己学習していた分野と全く同じだったのでとても楽しみです。


最後に

ここまでいろいろと書きましたが、未経験で何も実績がない自分を採用してくれた現職のWeb制作会社には本当に感謝しています。
自分が在籍していたこの2年間苦楽を共にしてくれたチームメンバーや、一から指導していただいた先輩方、本当にありがとうございました。

在籍していた期間は忙しくこうして振り返る暇もなかったですが、振り返ってみると今では良い思い出でこの経験はかけがえのない財産になりました。
この経験を生かして、次の職場でもエンジニアとして更に成長できるよう頑張りたいと思います。

というわけで長くなりましたが、引き続き都内にはいますので今後ともどうぞよろしくお願いたします。
ここまで読んでいただいてありがとうございました!!!

ウィッシュリスト

【まつもとゆきひろ氏 特別講演】20代エンジニアのためのプログラマー勉強法まとめ

先週末にサポーターズさん主催の【まつもとゆきひろ氏 特別講演】20代エンジニアのためのプログラマー勉強法 に参加してきました!
これまで技術的なことしか書けていなかったのですが、とても学びが深い講演会だったので初めて雑記的にまとめを書いてみようと思います。
内容濃すぎ && 80分 という講演会だったのでざっくりまとめです!
講演会の様子はyoutubeで配信もされたので、このブログの最後にURL貼っておきます。


以下Matzさんによるプログラマー勉強法まとめ

今回「勉強」という言葉を使ったのはあえてミスリードを誘う目的。
具体的には「(学校)勉強」には「苦手を克服するべき」というメタファーがある。
「苦手を克服するべき」は社会人の勉強では間違い。

学生と社会人の勉強の違い9つ

1.満点VS満点なし
社会人の勉強に満点がない、つまり上限がない。平均値や偏差値がないから学生時代の常識が通用しない。

2.苦手克服VS得意を伸ばす
社会人にとって苦手を克服するのは意味がない。自分の苦手は誰かが得意だったりする。
得意を頑張ったほうがいい。好きなことは上達する、上限はないからどこまでも伸ばせる。
「苦手を克服すべき」というメタファーは誤り。得意を伸ばすことがあるべき戦略。

3.記憶VS把握
試験があるわけではないから記憶しておく必要はない、それよりも何を知っているか把握することが重要。
基本的な概念、使い方、知識のインデックスを頭の中に作ることが重要。
Googleは友。詳細は必要な時に調べればいい。

4.知識VSインデックス
学生時代は知識を丸ごと頭の中に入れておかなければいけないが、社会人では知識のインデックスを作ることが重要。

5.試験VS常在戦場
学生時代は試験のための勉強。社会人の勉強は、いつ役に立つか分からない勉強をすることになる。
社会人の勉強は、「この日に役に立つ」というスコープ外れてるから、いつ役に立つか、そもそも役に立つものなのかすらわからない。

6.評価軸が一次元VS多次元
数学は数学でのみ評価される。次元が一次元。
エンジニアのスキルセットでいえば、それぞれみんな違う特質を持っている。
そのため評価軸は多次元になる。

7.メインVSサブ
学生は勉強がメイン。社会人は仕事がメインなので勉強がサブ。

8.間接的VS直接的
学生のときに勉強したことが役に立つかは直接はわからない。
社会人の勉強はスキルに反映するので直接的に伸びる。

9.安定VS変化
学生のときは教科書の内容が変わることは滅多にないし勉強が安定している。
社会人の勉強、例えばJSに関して言えば今勉強していることが古くなったり消える。
社会人の勉強はこういうことがけっこうある。

こんなに違うものを同一視して、このメタファー(苦手を克服すること)は役に立つのかというと役に立たないことがけっこうある。
社会人は「勉強」ではなく「学習」では?


なぜ勉強するのか

「成功したい」「高収入が欲しい」「良好な人間関係が欲しい」「嫌なことはしたくない」「好きなことで生きていきたい」など目的がある。
これらを達成する確率を上げるために必要なことは「高評価」「尊敬」「尊重」など。
勉強の目的はこれらを得るため。


どうやって「何を勉強するか」「どうやって勉強するか」を決めるかのヒント

1.必要なことは「Self reflection(内省)」
自分を真剣に見つめることが大事。
走り出すのは楽、走り続けるのは大変。まず走る前に方向性を考えることが大切。
仕事について、自分が好きなもの、嫌いなもの、得意なこと、苦手なことを即答できるか大事。
好きなことは上達するから苦手を克服するのはあまり意味はない。好きなことに集中したほうが効果的。
内省して以下をする。
何を勉強するかどうやって勉強するかを自分で決める。
自分のスキルについて真剣に考えてinventory(棚卸し)をする。
方向性を決める。

2.パターン認識について
パターン認識は成功の秘訣。
アメリカのスタートアップ数百人に共通して持っている素質はパターン認識能力が高い。
社会における様々なパターンを抽象化して認識する。過去の人たちの失敗を抽象化してパターン認識して失敗を避ける。
自分が尊敬する人はだれか?そういう人たちからパターンを探せ(尊敬できる人のパターンを認識して抽象化する必要がある)。

知らない人を尊敬することはできない。
自分が尊敬あるいは尊重を得るためには「知られないといけない」。
余談:尊敬は人格的評価が伴い、尊重には人格的評価は無関係。

一般論として人は有名人に弱い。本能的にミーハー。
知名度は価値と可換である。つまり以下。
× 成功したから有名になる。
〇 成功のためには有名にならなければならない。

成功するためにはまず知られる必要がある(=価値があると思われる必要がある)。
「有名である」=「価値がある」は循環論法。
価値があると思うから有名になる。有名であるから価値があると思ってもらえる。
今世間から評価されていない人はどうしたらいいのか。
マーケティングキャズム理論で説明できる。

キャズム理論
顧客5段階
イノベーター アーリーアダプター アーリーマジョリティ レートマジョリティ ラガード
アーリーマジョリティまで商品が届くことはあまりない。例えばJSの新しいフレームワーク。これ仕事で使う?様子見。このまま浸透しない。
アーリーアダプターとアーリーマジョリティの間にはキャズムがある。
キャズムを乗り越えるために以下。
ニッチに進出 → 一定のシェアを超える → 横展開する → キャズムを乗り越えられる可能性がある。

今日のテーマ「勉強法」というより、結局は自分のマーケティングの話。
ユニークさを強調すること。埋没しないことが重要。周囲の目に留まる確率が高ければ高いほどいい。

未来は誰にも分らないし未来のことを考えても意味がない。
それより自分の傾向について考える。内省する。
自分の将来を運任せにするのではなく戦略を立てる。

具体的な勉強方法について

1.モチベーション
好きなことは放っておいてもやるからモチベーションは高い。
漠然とした希望はモチベーションが弱い。例:このスキル身に着けたら面白そう → もっと具体的なほうが頑張れる
「暇」「退屈」は自分に対する注意報。自分のモチベーションを管理できていない。
本当にやりたいことを優先順位をつけて上から取っていけば「暇」や「退屈」って思う暇がない。
「暇の撲滅」を考える。

2.時間管理
どうやって時間をつくるか。
その人の時間の使い方でその人の優先順位がわかる。
勉強に関して言えば、本当に勉強が大事だと思っているか、もしくは大事だと自分を説得できているかで、時間を勉強に使うことができる。
プライベートを犠牲にするのはあまりよくない。
社会人の勉強は、仕事に反映されるために勉強する。
社会人の勉強は就業時間にすることが原則。
そのために仕事の生産性を高めて仕事の時間を勉強に使う。
大事なことは自分を忙しすぎない状態に持っていくこと。
作業の見積りは3倍くらいのバッファを取ることが適当。
社畜やめよう。
こういうことを理解する上司がいるか会社を選ぶバロメータになる、尊重されているか分かる。
これを理解してくれない会社は滅びたほうがいい、逃げたほうがいい。

3.アウトプット
勉強する=インプットはミスリード
インプットは差別化要因にならない。
アウトプットするかが重要。アウトプットは面倒、億劫、羞恥心があるから大変。
例:youtuberがやっていることは誰でもできることだが、実際は心理障壁があるから誰もはできない。
アウトプットによる知識の定着がある → ほかの人に読んでもらうところまで考えるともう一段階高いところで体系化されることがある。
クオリティは棚に上げてとりあえず世にだすこと大事。
アプトプットを繰り返すと楽にアウトプットできるようになってくる。
アプトプットを最適化していく。
アウトプットの心理障壁が取れてくる。
そうすると人間の可塑性が起きてくる。

4.可塑性
可塑性とは変化しやすさ。
立場によって人は変われる。
人は置かれた環境に合わせて変化できる。自分は固定的だと思わないほうがいい。
環境に強制されたときにゆっくりだが確実に変化することができる。しかも予期しない方向で変わることがある。
自分のinventoryをしていたとしても、自分の変化は予期できない。変化を発見したらそれに従う。


最後のアドバイス

1.基礎を抑える
あまり変化しない定番の知識
コンピュータサイエンス
アルゴリズム
コンピュータアーキテクチャ

2.英語
英語があれば18億人とコミュニケーションできる。
IT業界の新しい情報は英語で発生する。
タイムマシン経営ができる(アメリカで流行りを日本に持ってきてビジネスする)。
英語は読むのが最低限。次に雑談ができること。そして公演ができる状態へ。
語学は場数。脳の中に回路を作れるかの勝負。
完璧を目指さない。

3.コンフォートゾーン
コンフォートゾーンは居心地の良い空間のこと。
ずっといると成長がない。コンフォートゾーンを意識的に出ると成長できる。
変化を恐れない訓練をする。
誰かを見下さない。見下すとコミュニケーションができない。我々の仕事は人相手の仕事。
自分は多次元でものを見れていれば人を見下さない。例:この面では勝っているがこの点では劣っているな
同様に自分を卑下しない。


内容も時間も盛りだくさんだったのでざっくりですが以上な感じでまとめてみました!
最後に感想ですが、80分の講演のMatzさんの言葉で特に印象的だったのが以下の2点の内容でした!

「自分は運が良かったから大して深く考えていたわけじゃないけどこのキャリアを歩めたけど、運という要素は誰にでもあてはまるものではないから、戦略的に成功する確率を高めることが必要」ということ。

「未来は誰にも予想できないから考えても無駄。大企業が出している未来予測も実際は当たらない。自分の傾向や内省について真剣に考えることが大事」ということ。

講演会参加前は、具体的なプログラミング勉強法(例えばこのサイトは便利とか、こういう順番で知識を身に着けると効率的とか)を聞けるかと思っていましたが、
実際はかなり体系的なお話を聞くことができて、とても学びが深い講演会でした!
今後もたまにはこういう技術的なこと以外も書いていけたらと思います。ここまで読んでいただいてありがとうございました!!

まつもとゆきひろ氏 特別講演】20代エンジニアのためのプログラマー勉強法
https://youtu.be/YG0MzpNiZUg

Vueで絞り込みとソート機能を実装してみた02

前回は絞り込み機能を実装したので今回はそれにソート機能を実装していきます。
前回:Vueで絞り込みとソート機能を実装してみた01

今回やること
* 降順と昇順を任意に表示切替できるようにする

ソートするにはcomputedのmatchedの返り値の配列を受け取ってそれをLodashを使ってソートしてから配列を返せば良いです。 この配列を既存のcomputedのlimitedで加工します。limitedの処理は前回と受け取る配列が違うだけです。 それでは実装していきます。
main.js

const app = new Vue({
    el: "#app",
    data: {
        budjet: 10000,
        limit: 3,
        flg: false,
        list: [
            {
                id: 1, name:"ザバス ホエイプロテイン100 ココア味", price: 3659
            },
            {
                id: 2, name:"ウイダー マッスルフィットプロテイン ココア味", price: 1922
            },
            {
                id: 3, name:"アミノバイタル アミノプロテイン レモン味", price: 3157
            },
            {
                id: 4, name:"パワープロダクション マックスロード チョコレート風味", price: 7980
            },
            {
                id: 5, name:"ゴールドスタンダード 100% ミルクチョコレート味", price: 4980
            }
        ]
    },
    computed: {
        matched: function() {
            return this.list.filter((el) => {
                return el.price <= this.budjet
            },this)
        },
        sorted: function() {
            return _.orderBy(this.matched, 'price' this.flg ? 'desc' : 'asc')
        },
        limited: function() {
            return this.sorted.slice(0, this.limit)
        }
    }
})

sortedではLodashを使ってソート済みの配列を返しています。
色々なメソッドが揃ってます。使い方はドキュメントを参照してください。
Lodash Documentation
https://lodash.com/docs/4.17.10

index.htmlは以下のような感じにします。

<div id="app">
    <p v-cloak>
        <input v-model.number="badjet">円以下に絞り込む<br>
        <input v-model.number="limit">件を表示する
    </p>
    <ul>
        <li v-for="item in list" :key="item.id">
            商品名:{{ item.name }}価格:{{ item.price }}円
        </li>
    </ul>
    <button @click="flg=!flg">切り替え</button>
</div>

これで切り替えボタンをクリックするごとにVueインスタンスのデータに持たせているflgプロパティのtrue/falseが切り替わり、
それによって降順/昇順が切り替わって表示されるようになります。
これでソート機能も追加することができました。

今回こちらの本を参考にさせていただいています。ありがとうございます!
基礎から学ぶ Vue.js
https://www.amazon.co.jp/dp/B07D9BYHMZ/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

読んでいただいてありがとうございました!!!