delhi09の勉強日記

技術トピック専用のブログです。自分用のメモ書きの投稿が多いです。あくまで「勉強日記」なので記事の内容は鵜呑みにしないでください。

「プログラミング言語の習得」をブレークダウンして考えてみる(WEBアプリ開発の場合)②

概要

前回の記事に続いて、本記事では、WEBアプリ開発をする上での前提知識・スキルという意味での「言語の習得」をブレークダウンして考えてみたい。

前提

既に何らかの言語でWEBアプリケーション開発の実務経験がある人が、他の言語を習得しようとする場合を前提としている。

従って、以下のような一般的な知識はある前提である。

一覧

ブレークダウンしてみた結果、個人的に覚えた方がいいと思うことの一覧は以下のようになった。
※ あくまで個人の経験に基づくので、過不足あるとは思うが、とりあえずこれくらい覚えればいいんじゃないかと思う。

  1. 環境構築
  2. パッケージ管理
  3. モジュールの仕様
  4. 言語の基本
  5. コードコメント
  6. 変数宣言
  7. 計算
  8. 値の判定方法
  9. 条件分岐・ループ
  10. 文字列操作
  11. 正規表現
  12. データ構造
  13. ディレクトリ・ファイル操作
  14. 時間
  15. 言語の設計思想を理解する
  16. 関数
  17. クラス
  18. エラー処理
  19. ロギング
  20. HTTP通信
  21. 暗号化
  22. JSON
  23. コマンドライン引数
  24. OSコマンド
  25. DB操作
  26. UnitTest

以下で説明していく。

環境構築

No 項目
1 言語の実行方法を覚える
2 エディタ・IDEの使い方を覚える
3 代表的なLinter・フォーマッターの使い方を覚える
4 エディタとLinter・フォーマッターの連携を覚える

説明

仮想化ツールや優秀なエディタ/IDEが出てきたことで、単に「言語が実行できる環境を準備する」という意味での環境構築は、5年〜10年前と比べて楽になったと感じる。

他方で、Linter・フォーマッターをエディタと連携させて開発するのが当たり前になってきている。(Pythonならblackやflake8、JSならESLintやPrettier)

自分でコードを整形したり、チーム開発でもコードレビューでフォーマットに関する議論が不要になるので、こちらもトータルで見れば楽になっているのだが、Linter・フォーマッターは往々にして設定が複雑なので、最初はけっこう時間がかかる。

ただ、1回、設定の仕方を覚えてしまえば、後の学習がスムーズになるので、面倒でも先に覚えてしまった方がいいと思う。

また、エディタは最近ではVS Codeを使うことが多いと思うが、言語特有のプラグインとかがあるので、その辺を抑えておく必要がある。

パッケージ管理

No 項目
1 パッケージ管理ツールの使い方を覚える

説明

サードパーティのライブラリは遅かれ早かれ必ず使うので

  • デファクトスタンダードなパッケージ管理ツールは何か把握しておく。(Pythonならpip、JSならnpm)
  • パッケージをインストールするコマンドを覚えておく。

くらいは最低限やっておく必要がある。
細かいオプションは必要になったら調べればいいと思う。

モジュールの仕様

No 項目
1 モジュールの仕様を理解する
2 異なるモジュールのインポート方法を覚える

説明

モジュールの仕様は言語ごとに異なるので、理解しておく必要がある。

例えば以下のような階層構造でファイルが置かれており、Main.(java|py)からFoo.(java|py)をインポートしたいとする。
Foo.(java|py)には「Foo」というクラスが定義されているとする。

example
├── Main.(java|py)
└── lib
    └── Foo.(java|py)

このような場合に、JavaPythonではインポートの仕様が異なる。

Javaの場合

import example.lib.Foo

Pythonの場合

from example.lib.Foo import Foo

これは、以下のような言語仕様の違いによる。

  • Java
    • 1つのファイルには1つのクラスを定義する。
    • ファイル名とクラス名は同じ名前にする。
    • ファイルが存在するディレクトリまでがモジュールのパスになる。
  • Python
    • 1つのファイルに定義できるクラスや関数に制限はない。
    • import対象が存在するファイルのファイル名までがモジュールのパスになる。

このように、モジュールの仕様は重要かつ言語によって異なるので、覚えておいた方がいいと思う。

言語の基本

No 項目
1 コーディングスタイルを覚える
2 ファイルの命名規則を覚える
3 コードブロックの書き方を覚える

説明

例えばPythonなら、変数はスネークケースで書く、クラスはアッパーキャメルケースで書くなどの基本的なコーディングスタイルは覚えておいた方がよい。
行末にセミコロンをつけるかどうかなども言語によって異なる。

例えば変数名の場合、Javaはキャメルケースだが、Pythonはスネークケースである。
また、Javaは行末にセミコロンをつけるがPythonはつけない。

String personName = "山田";
person_name = "山田"

公式のガイドラインがある場合はそれを確認する。(PythonであればPEP8)

1回、間違ったコーディングスタイルで書く癖がついてしまうと矯正するのが面倒なので、学習の早い段階で確認しておくのがよいと思う。

ファイルの命名規則も言語によって異なるので押さえておく。(Javaなら${クラス名}.javaなど)

また、言語によってコードブロックがブラケットだったりインデントだったりするので、その辺も確認しておく。

コードコメント

No 項目
1 コメントの書き方を覚える
2 コードドキュメントの書き方を覚える

説明

コメントの書き方は覚えるだけだが、コードドキュメントに関しては、言語ごとに仕様が存在するはずなので確認しておいた方がよい。(Pythonならdocstring、JavaならJavaDoc)

変数宣言

No 項目
1 基本的な型を覚える
2 型変換のやり方を覚える
3 変数宣言の書き方を覚える
4 再代入の可否を覚える
5 変数のスコープの仕様を調べる
6 Enumの書き方を覚える(言語が対応している場合)

説明

静的型付け言語はもちろんだが、動的型付け言語でも最近はタイプヒント有りで開発することが普通になっている。
従って、基本的な型は覚えておく必要がある。(とりあえず数値型と文字列型を覚えておけばよいと思う。)
加えて、数値型と文字列型の型の相互変換はよく使うので、合わせて確認しておく。

言語によってはJSのconstのように再代入をできなくする宣言方法が備わっているので覚えておく。

変数のスコープも言語によって仕様が異なる場合があり、自分が親しんでいる言語の感覚でいるとハマりやすいので注意が必要である。

例えばJSではletで宣言した変数のスコープはifブロック内なので、以下はReferenceErrorになる。

if(true) {
    let a = "foo"
}
console.log(a)

対して、Pythonではifブロックは変数のスコープと関係がないので、以下は普通に通る。

if True:
    a = "foo"
print(a)

また、Enumもよく使うので、対応している言語(JavaPython)では書き方を確認しておいた方がよい。

計算

No 項目
1 足し算・引き算のやり方を覚える
2 省略記法を覚える

個人的には、掛け算や割り算はWEBアプリ開発では意外と使わないし、累乗や平方根はもっと使わないので、最低限、足し算と引き算を書けるようになればいいのではないかと思っている。

文法は言語にもよるがn += 1n++のような省略記法は結構使うので、覚えておくと良いと思う。

値の判定方法

No 項目
1 文字列の比較方法
2 数値の比較方法
3 ヌルチェックの方法
4 空文字列の判定方法
5 空のリストの判定方法

これも言語によるが、比較演算子の意味が=====で違ったり、Javaのように文字列の比較は基本equalsを使うとかあったりするので、確認しておいた方がよい。

また、空文字列や空のリストの真偽に関しては、『りあクト』の以下のやり取りのように各型の真偽を整理しておくとよいのだと思う。

「なるほど。これらの型で値の真偽がどうなっているか教えてもらえますか?」
「いい質問だね。falsyなのがそれぞれfalse0Nan''(=空文字)、nullundefinedで、それ以外は全部truthyになるよ。」(第3.1版 I.言語・環境編 p.60)

条件分岐・ループ

No 項目
1 条件分岐の書き方を覚える
2 ループの書き方を覚える
3 三項演算子

説明

ループに関しては、最初に学習するのは以下のような書き方だと思う。

for i in range(3):
    print(i)

しかし、実際の開発では以下のようにListやMapをループすることの方が圧倒的に多いので、最低限ListとMapのループ方法を覚えておけばよいのではないかと思う。

Listのループ(Pythonの場合)

data = [0, 1, 2]
for e in data:
    print(e)

Map(Dict)のループ(Pythonの場合)

data = {
    "tokyo": "東京",
    "saitama": "埼玉"
}
for k, v in data.items():
    print(k, v)

また、条件分岐に関しては、三項演算子は使うと見通しよく書けることがあるので、該当言語における書き方を覚えておいて損はないと思う。

文字列操作

No 項目
1 よく使う文字列操作を覚える

説明

開発する上でよく使う文字列操作を覚える。
個人の体感になってしまうが、以下に挙げたくらいを抑えておけば大丈夫かなと思っている。

  • 文字列に変数を埋め込む
  • 引数で指定された文字列で始まる(終わる)かの判定
  • 引数で指定された文字列が含まれるかの判定
  • 部分文字列の取得
  • トリミング(前後のスペースなどを削除)
  • スプリット(カンマ区切りの文字列などをList化する)
  • 置換

正規表現

No 項目
1 正規表現の使い方を覚える

説明

正規表現もよく使うので、「正規表現」自体は分かっているという前提で、該当言語における、使うライブラリとパターンマッチや置換の基本的な書き方を抑えておくといいと思う。

データ構造

No 項目
1 Listの使い方を覚える
2 Mapの使い方を覚える
3 データ構造のループの方法を覚える
4 データ構造の追加・削除の方法を覚える
5 ソートの方法を覚える

説明

ListとMapは頻出なのでスラスラ書けるレベルで覚えた方がよい。
Pythonのように他にもSetTupleが言語仕様に組み込まれている場合は、合わせて覚えておくとよいと思う。

あとは、ループの方法や追加・削除の方法・ソートする方法などを押さえておく。

ディレクトリ・ファイル操作

No 項目
1 テキストファイルの読み書きの方法を覚える
2 ディレクトリの作成・削除方法を覚える

説明

テキストファイルの読み書きの方法を覚えておく。
ディレクトリの操作も時々使うので、合わせて覚えておくとよいと思う。

時間

No 項目
1 日付型 → 文字列の変換方法を覚える
2 文字列 → 日付型の変換方法を覚える

説明

WEBアプリを開発する上で時間は必ず扱うことになるので押さえておく。

とりあえず、該当言語における日付を扱うデファクトスタンダードなライブラリを抑えた上で、日付型 ⇄ 文字列の変換の書き方が分かっていればいいと思う。

言語の設計思想を理解する

ある程度学習が進んだら、関数やクラスを勉強する前に、言語の設計思想をざっと理解しておいた方がいいんだろうなと思っている。

理由としては、例えば、同じように言語の仕様にクラスが組み込まれていたとしても、言語の設計思想が「オブジェクト指向」なのか「関数プログラミング指向」なのかとかで、使い方が変わってくると思う。

一例として、Pythonにはクラスは存在するが、JavaInterfaceと等価なものは存在しないし、abcというモジュールを使うとInterfaceライクなことはできるが、Pythonの開発文化的にはあまり使わなかったりする。

また、Goとかはそもそもクラスが存在しないらしい。

そういった言語仕様・文化の違いも、元を辿れば設計思想(=どのような問題を解決しようとして言語が作られたか)によるのだと思う。

なので、「今習得しようとしている言語はどういう設計思想なのか?」ということが分かる本や資料があったらざっと読んだ方が、この先の学習を進める上でのメンタルモデルが形成されていいんだろうなと思う。

関数

No 項目
1 関数の宣言方法を覚える
2 デフォルト引数の宣言方法を覚える

説明

関数に関しては特に補足で説明することはなくて、上記に挙げたような基本的な宣言方法を覚えておけばよいと思う。

クラス

No 項目
1 クラスの宣言方法を覚える
2 コンストラクタの宣言方法を覚える
3 メソッドの宣言方法を覚える
4 フィールドの宣言方法を覚える
5 staticメソッドの宣言方法を覚える
6 staticフィールドの宣言方法を覚える
7 「継承」の書き方を覚える
8 「Interface」の宣言方法を覚える
9 「オーバーライド」の宣言方法を覚える
10 インスタンスの作成方法を覚える
11 フィールドの参照方法を覚える
12 メソッドの呼び出し方法を覚える

説明

クラスに対応している言語の場合は、基本的なクラスの使い方を覚える。
とりあえず上記に挙げたような基本的な使い方を覚えておけばよいと思う。

該当の言語でGoFデザインパターンを実現する方法とかまで勉強してもあまり使う機会がなかったりするし、そもそも言語の文化によっては継承によるポリモーフィズムをあまり使わなかったりするので、その辺は必要になったら勉強するでいいと思っている。

エラー処理

No 項目
1 エラーハンドリングの方法を覚える

説明

エラーハンドリングはWEBアプリケーション開発では必須である。
従って、「例外」などの言語に備わっているエラーハンドリングの機構と使い方を覚えておく。

言語に備わっているエラーハンドリング機構が「例外」の場合は例外の自作方法も確認しておくとよいと思う。

※ 私自身は「例外」以外の方法でエラーハンドリングをする言語は経験がないが、例えば以下に引用したように、関数型プログラミングの考え方では、「例外」は副作用と考えてあまり使わなかったりするらしいので、「エラー処理」という含みを持たせたセクション名にした。

たとえば以下に示すように、単に結果を返すこと以外に何かをする関数には、副作用があることになります。

  • ...
  • 例外をスローする、またはエラーで停止する
  • ...

Scala関数型デザイン&プログラミング―Scalazコントリビューターによる関数型徹底ガイド』p.3より

ロギング

No 項目
1 ロギングの方法を覚える
2 設定方法を覚える

説明

ロギングもWEBアプリケーション開発では必須なので、やり方を覚えておく必要がある。

言語によってはロギングはサードパーティライブラリを使うこともあると思うので、その場合は該当言語のデファクトスタンダードなロギングライブラリは何かを調べる。

加えて、実際のWEBアプリケーションでロギングするときには、ログレベルに応じて出力先を変えたり、ログ出力する項目やフォーマットを設定したりすることになるので、その辺の設定の書き方も勉強しておくと後で楽だと思う。

HTTP通信

No 項目
1 HTTPリクエストする方法を覚える

説明

外部のAPIを叩いたりクローラーを作ったりする場合はHTTPリクエストをすることになるので、覚えておいた方がいい。

これも言語によってはサードパーティライブラリを使うこともあると思うので、その場合はデファクトスタンダードなライブラリを調べた上で、使い方を覚えておくとよいと思う。

暗号化

No 項目
1 代表的な不可逆暗号アルゴリズムの使い方を覚える
2 代表的な可逆暗号アルゴリズムの使い方を覚える

説明

基本的には機密情報を保存するときに使う。
後は、APIのリクエスト時にワンタイムトークンを生成する時に、鍵有りSHAを使ったりすることがある。

暗号化に関しては、例えばパスワードのハッシュ化とかならFWが内部でやってくれるから、自分でやらなくてもよいというケースもあると思うが、覚えておいて損はないと思う。

JSON

No 項目
1 JSON文字列をオブジェクトに変換する方法を覚える
2 オブジェクトをJSON文字列に変換する方法を覚える

説明

APIを使うときなどのフォーマットは今日ではJSONが圧倒的に多いので、JSON文字列⇄オブジェクトの相互変換の方法は覚えておいておいた方がよいと思う。

これも言語によってはサードパーティライブラリを使うこともあると思うので、その場合はデファクトスタンダードなライブラリを調べる。

コマンドライン引数

No 項目
1 コマンドライン引数の取得方法を覚える

説明

バッチ処理を実装する場合だと、コマンドライン引数を受け取る処理を実装する必要があるので覚えておく。

OSコマンド

No 項目
1 OSコマンドの実行方法を覚える

説明

同じくバッチ処理を実装する場合に、OSコマンドを実行したい場合も出てくるかもしれないので、押さえておいて損はないと思う。

DB操作

DB操作に関しては、言語習得段階で勉強するべきかどうかは、後続のWEBアプリ開発フルスタックフレームワークを使うか軽量フレームワークを使うかによると思う。

例えばPythonの場合、次にDjangoを勉強する予定であれば、DB操作はDjangoの学習の方に寄せてしまってよいと思う。

他方で、FastAPIなどの軽量FWを使いたいと思っている場合であれば、DB操作のライブラリの選定から自分でやらないといけないので、事前にPythonにおけるDB操作の有力なライブラリ(ex SQLAlchemy)を調べて、使い方をある程度押さえておく必要がある。

UnitTest

No 項目
1 デファクトスタンダードなUnitTestライブラリの基本的な使い方を覚える
2 デファクトスタンダードなMockライブラリの基本的な使い方を覚える
3 カバレッジの取得方法を覚える

説明

該当言語におけるUnitTestのデファクトスタンダードなライブラリ(JUnit、Jestなど)を調べて、使い方を覚える。
合わせてMockライブラリの使い方も覚えておくとよいと思う。

これも、DjangoのようにFWにUnitTestの機能が組み込まれている場合は、FWの学習の方に寄せてしまってもよいと思う。

加えて、実際の開発ではUnitTestはカバレッジを計測して指標にするので、該当言語におけるカバレッジツールとその基本的な使い方も押さえておくと良いと思う。

「覚える」の温度感

ここまでFWを使ったWEBアプリ開発の学習に入る前に習得した方がいいと思うことを挙げてきた。

最後に「覚える」ということの温度感についても考えてみたい。

「覚える」といっても本当にスラスラ書けた方がいいのは以下に挙げたくらいだと思っている。

  • モジュールのインポート
  • 足し算・引き算
  • 変数の宣言
  • 条件分岐
  • ループ
  • List・Map
  • 関数の宣言
  • クラスの宣言

これらは開発における使用頻度が圧倒的に高いので、書くたびにググっていうと流石に作業効率が悪くなってしまう。
とはいえ、使用頻度が圧倒的に高いので、無理に覚えようとしなくても、自然とスラスラ書けるようになると思う。

それ以外に関しては、「こういうことやりたい時はこれ使うんだったな」と思い出して、Google検索のキーワードにできる程度でいいと思っている。

というのは、「言語の習得」段階で頑張って空で書けるようになっても、使用頻度が高くないものは、時間が経つと忘れるからである。

まとめ

上に挙げたくらいのことを大体覚えたら、WEBアプリ開発をする上での前提知識・スキルという意味での「言語の習得」はできたと思って、次のステップに進んでよいのではないかと個人的には思う。

以上