ESLintというツールをご存知でしょうか?これは「コードスタイルを統一するためのツール」です。そのため、
- リーダブルコードを読んだことがある人
- コードの整形について知っている人
- if文まわりの改行について一家言ある人
には必要ありません。 〜完〜
!!!!!!違います!!!!!!
違います!これはESLintの一側面を取り上げただけであり、ESLintのメリットのごく一部にすぎません。
このような悲しい勘違いをこれ以上被害が広がる前に撲滅したいと思います。
続きを読むESLintというツールをご存知でしょうか?これは「コードスタイルを統一するためのツール」です。そのため、
には必要ありません。 〜完〜
違います!これはESLintの一側面を取り上げただけであり、ESLintのメリットのごく一部にすぎません。
このような悲しい勘違いをこれ以上被害が広がる前に撲滅したいと思います。
続きを読むみなさんは「型」についてご存知でしょうか?「intとかcharみたいなアレでしょ?」くらいの知識はあるかと思います。今回の記事では型についての種々の疑問について解説して行きたいと思います。
なお、この記事ではTypeScriptの型をもとに話しますが、他の言語でも言える普遍的な内容になっています。
型とは、データの分類の名称のことです。たとえば0
、42
はnumber型
、''
、'hello world'
はstring型
です。
型はプリミティブ値以外の式にもつきます。たとえば式1 + 2
はnumber型
、式'hello' + ' ' + 'world'
はstring型
です。
また、変数や関数の引数・返り値にも型をつけることができます。型がついた変数は、その型の値しか代入できません。
たとえば、number型の値を2つ受け取ってnumber型の値を返すmax関数はこのようにかけます。
const max = (a: number, b: number): number => a > b ? a : b;
型があると嬉しいことはいくつか挙げられます。
1つ目はオマケで、2つ目のほうが重要です。
たとえば、map関数は以下のような型を持ちます。
const map = <T, T2>(f: (bef: T) => T2, a: T[]): T2[] => { const res = []; for (const item of a) res.push(f(item)); return res; }
fとaを受け取り、aの各要素にfを適用した結果を返す関数になっており、型定義もそのようになっています。
静的型検査というのは、プログラムを実行せずに型が正しくつけられているか検証する作業です。たとえば次のコードはTypeScriptの型検査ではじかれます。
const n = '3'; // おや? const m = 4; console.log(n * m); // 文字列と掛け算してしまっている!
実はJavaScriptではこのコードは意図したとおり(?)12を表示してくれます。これは静的型検査がないかわりに実行時に必要に応じてキャストしているためです。
しかし、もしnが外部からの入力だったとしたらどうでしょうか…?
const n = await readFile('hoge.txt', 'utf8'); // hoge.txtから読み込んでいるけど… const m = 4; console.log(n * m); // 数値で掛け算できている保証はない
これはごくカンタンな例でしたが、もっと巨大なコードになっていくと、いちいち調べるのは大変です。そこで、型をつけて検査をしてエラーをはじきます。
TypeScriptは静的型付けをするので、静的型付き言語です。TS→JSのコンパイル時に型チェックが行われます。コンパイルが通れば実行時エラーが起きないことが保証されます*1。
静的型付き言語であっても、必ずしもすべてに型を書く必要はありません。たとえば目視でも「1 + 2
はnumber型
だ」という"推論"ができます。二項演算子なら、その左辺と右辺の項、演算子の情報さえあれば推論できます。この推論機能によって、型アノテーションを省略することができます。ただし型推論の目的は型アノーテーションの省力化ではありません。
もし型推論がなかったら、次のように書かなければなりません(下のような構文はそもそもTypeScriptにありませんが)。
const a : number = ((1 + 2 : number) * (3 - 4 : number) : number)
さすがにこれは過剰です。演算子は型が言語仕様から決まりきっているので、オペランドとの組み合わせが決まれば返り値の型は一意に決められます。型アノテーションが必要になることはありません。
関数の推論についてはややこしいので、参照記事をご覧ください。
ここで重要なのは、型推論は静的に行われることです。静的型検査を行いながら推論をしていくので、型推論によって不要な型アノーテーションを消したからといっても実行時エラーは起きえません。型推論と動的型付けはごっちゃになりがちなので、気をつけてください。
*1:ただし、TypeScriptはJavaScriptのスーパーセットで、型がないところは勝手にany型がつけられて検査時にエラーが出ないため、適切な型付けをしていることが前提ですが
2018年(学部3年) 4月 院進以外に、就職という道があると気がつく(院には当然進むものだと思いこんでいた)
5月 院進と就職で悩み始める
6月 就職しようと決める
〜12月 「自己分析」とか「業界研究」とか何すればいいか分からないし、部活が忙しくてやる暇がない
1月 近所でやってたインターンや説明会に参加する
2月 就活を始める。
企業ホームページの採用情報のところから直接応募するスタイルを取った。就活サイトに登録したり、説明会に参加したりしていなかったため、手当たりしだい応募する形になった。
課題選考はとりあえず通るので、最低限は技術力を評価されていたと思います。しかし、とにかく面接が通りませんでした。後でも書きますが、チームで開発したことがなくて、どういうふうに働くか具体的なイメージができなかったのが要因の一つだったと思います。
最終的に、受けた中で一番年収が高い企業になりました。労働条件もとてもいいので嬉しい限りです。ただ、その環境を享受できるほど能力がある自信がないので非常に不安です。というか周りのレベルについていけるのでしょうか…?がんばります。
面接でたびたび「どういうふうにして情報を仕入れていますか?(技術系の流行の追い方みたいな意味だったと思う)」と聞かれたのが印象的でした。
「Linuxカーネルの役割をカンタンにいくつか挙げてみて」と言われて出てこなかったのが悔しかったです。プロセス管理とかメモリ管理とか分かるけど、それが「カーネル」という言葉と結びついていませんでした()。授業でもやりましたし、応用情報の勉強でもやっていてそのへんの知識はあっただけに、惜しいことをしました・・・
チーム開発の経験についてほぼ毎回聞かれましたが、インターンやアルバイトなどに行っていなかったため毎回困りました。開発型のインターンに行っておくと有利かもしれません。インターンに参加しておけば、実際にチーム開発を経験できるので、チーム開発に向いていないのにプログラマになってしまう事故を防げます。
他に、自己分析をしていなかった…というかやり方が分からなかったのは良くありませんでした。自己分析をすることで、自分に合う環境を探す指標が作れるので、「何が好きか」「どう働きたいか」「何が嫌か」「どういう福利厚生が欲しいか」などをまとめるだけでもだいぶ違ったんじゃないかと思います。
就活しているのでブログにもポートフォリオを書いておきます。
名前はクロパンダです。
現在は東北大学の工学部で情報工学を学んでいます。学部4年生なので、まだ研究は始まっていません。
趣味はプログラミングと合気道です。プログラミングは中学生から、合気道は大学から始めました。
主にJavaScriptを書いています。今までに作ったもの・書いたものとして以下が挙げられます。
ほかにもあるのでサイトの制作物一覧をご覧ください。
HTML5のCanvasは「線を引く」「円を描く」のような命令ベースでプログラムを書かなければなりません。これではコードを読んでもどういう図形を書こうとしているのかがわかりません。そこで、「四角形を描く」「多角形を描く」「5本の線分で星を描く」といった風に宣言的に書けるようにするライブラリを作りました。Qiitaに投稿したところ、52いいねを頂けました。
ページ上の任意の箇所に入力フォームが設置できるサービスです。テキストファイルは1次元方向(横方向)にしか文字を設置できず、紙のような自由度がなくて使いづらいと思ったのが動機でつくりました。紙のような自由度、キーボードによる入力のしやすさを組み合わせたサービスです。
技術的に(自分としては)新しいことにたくさん取り組みました。たとえば、バックエンドでGoを使い、GraphQLのリクエストをさばいています。また、今までRDBMSしか触ってこなかったのでNoSQLのMongoDBを使ってみました。
ほかにもReact + TypeScript + Redux + immerでフロントエンドを書いたり、メールサーバーを建ててアクティベートメールを送信したり、ソーシャルログインを実装したり(これはまだ未完成)といったことをしました。
これは「新技術を試してみたい」と「こういうサービスを作りたい」というタイミングがマッチして作ったサービスです。サービスをつくるときは「新技術を試したい」という動機で作ることが多いのでめずらしいパターンでした。
これはWebSocketの習作として作ったミニゲームです。アクセスしているユーザーは「火を起こす」か「薪を足す」ことができます。そして、アクセスしている人みんなで火を絶やさず燃やし続けようというゲームです。誰かが「火を起こす」か「薪を足」したらサーバーから通知が送信され、画面が更新されます。
こっちは「WebSocketを試したい!」という理由だけでつくりました。「薪を燃やしてぇッッ!!」みたいな動機はありません。上でも書きましたが、「新技術を試したい」という動機でサービスを作ることが多く、これはその最たる例です。
何度もwebpack.config.jsを手書きしていて面倒くさくなってきたので、ここに書き方を残しておきます。
webpack.config.jsを書く際によく使うTipsとして、これらが挙げられます。
mode: env.mode || 'development'
path.resolve(__dirname, path_to_file)
を使うoptions.resolve.extensions
に読み込みたいファイルの拡張子を記述options.output.filename
で'[name].min.js'
のように指定できるoptiopns.module.rules
に書き込む最初にwebpack.config.jsのテンプレを載せておきます。どうせ未来の僕がこの記事を読むときは、このテンプレを見たいときだけなので。
const path = require('path'); module.exports = (argv, env) => ({ mode: env.mode || 'development', entry: path.resolve(__dirname, './src/main.js'), output: { filename: 'bundle.js', path: path.resolve(__dirname, './dist'), }, module: { rules: [], }, });
記事の後半の内容が必要そうなら使うバージョン。
const path = require('path'); module.exports = (argv, env) => ({ mode: env.mode || 'development', entry: path.resolve(__dirname, './src/main.js'), // entry: { // main: path.resolve(__dirname, './src/js/main.js'), // index: path.resolve(__dirname, './src/js/index.js'), // gallery: path.resolve(__dirname, './src/js/gallery.js'), // }, // resolve: { // extensions: ['.js'], // }, output: { // filename: '[name].min.js', filename: 'bundle.js', path: path.resolve(__dirname, './dist'), }, module: { rules: [ // { // test: /\.css$/, // use: ['to-string-loader', 'css-loader'], // }, ], }, });
この設定をしておくと、package.json
内で開発ビルドとプロダクションビルドをカンタンに切り替えることができます。
"scripts": { "build": "webpack --mode production", "build:dev": "webpack", ... },
応用として、options.output.filename
を書き換えることもできます。
{ output: { filename: env.mode == 'production' ? 'bundle.min.js' : 'bundle.js' } }
pathモジュールのpath.resolve
メソッドを使ってファイルパスを指定するようにします。例えばoptions.entry
、options.output.path
などで使うといいです。
なぜわざわざpath.resolve
を使うかという理由は webpack.config.jsで思ったpath.resolveって何のためにあるの?に書いてあります。
Windowsとかだとパス区切りが/じゃないこともあるみたい。バックスラッシュっていうやつ(\)。だから__dirname + '/src'だとパスがおかしくなってしまうことがあるからpath.resolveを使って安心安全で行こうぜ!ってことらしい。 (引用: webpack.config.jsで思ったpath.resolveって何のためにあるの?)
環境間の差異を吸収する目的のようです。
よく忘れるので書いただけです。特に解説することはないです。
これはそこまで頻度高くないです。
{ entry: { main: path.resolve(__dirname, './src/main.js'), sub1: path.resolve(__dirname, './src/sub1.js'), sub2: path.resolve(__dirname, './src/sub2.js'), }, output: { filename: '[name].bundle.js' } }
めちゃくちゃ当たり前なんですが、手書きすると「あれ?どこに書くんだっけ?」となるので書いておきます。