JavaScript:動的型付けとは

JavaやC#に慣れている人だとJavaScriptの動的型付けの概念に戸惑うと思うので、この記事では動的型付けについて簡単にまとめてみます。


JavaScriptには、下記の7つのプリミティブ型(ECMAScript 2015の場合)とObject型が存在します。

説明
Boolean真偽値を示す。true または false
nullnull値を示す。
undefined未定義の値を示す。
Number浮動小数点型を示す。例1:100 例2:123.45
BigInt整数型を示す。例:123n(これで整数の123の意味となる)
String文字列型を示す。例:”Hoge”
Symbol名前空間の衝突を防ぐ特殊な型。言語仕様の拡張等で用いられる。

JavaScriptの場合、下記のように変数を定義します。
型名を指定するのではなく、”let”というキーワードで変数であることを示します。

※補足

“let”の代わりに”var”や”const”で変数を定義することもできます。
“var”で定義した変数は、定義したブロックの外でも参照可能になります。
“const”で定義した変数は定数となり、上書きができなくなります。


どのような型でも”let”で変数定義できる、という話であれば、JavaやC#の型推論と同じような話になります。
しかし、JavaScriptの動的型付けは、型推論とは異なる点もあります。

JavaScriptでは、一度変数を定義した後に、定義した時とは異なる型の値を代入することが許されます。

例えば、下記のコードでは、Number型の変数を定義した後にString型の値”Hello World!”を代入していますが、異常終了することなくコンソール上に”Hello World!”と出力されます。

なお、JavaやC#では一度変数の型を定義した後に異なる型の値を代入することは許されておらず、コンパイルエラーとなります。
この挙動の違いを理解していないと、バグ調査する際の絞り込みが難しくなることがあるので、注意が必要です。


いかがでしたでしょうか?

JavaやC#の経験者がJavaScriptを触ると動的型付けの概念に戸惑うと思うので、記事にしてみました。
他にも、整数型の扱いについても戸惑うのではないかと思っています。これは別の機会に記事にしたいと思います。

ちなみに、この記事でちょうど100記事目になりました!
今まで見て下さった方々、ありがとうございます。
これからもブログを続けていきますので、よろしくお願いします。

JavaScriptでHelloWorld(ブラウザ上に文字表示)

JavaScriptはCUIでも実行できますが、GUIで使うケースの方が多いので、GUIでHelloWorldを書いてみました。
JavaScriptのHelloWorldはログに出力したりポップアップ表示したりするものが多いですが、ブラウザ上に出力した方がJavaScriptっぽい気がするので、ブラウザ上に表示するサンプルを提示します。

【サンプルコード1】

・Sample.html

【結果1】

・Sample.htmlをChromeで開いた結果


サンプルコード1のようにJavaScriptはHTML内に書くことができますが、サンプルコード2のようにJavaScriptを別ファイルにするケースの方が多いと思いますので、別ファイルにするサンプルも提示します。

【サンプルコード2】

・Sample.html

・Sample.js

【結果2】

結果1と同じため割愛


いかがでしたでしょうか。

JavaScriptは広く使われている言語であり、面談時点でJavaScriptのスキルを求められない現場でもJavaScriptを使うことがあります。
他言語に精通している技術者であっても、JavaScriptには慣れておいた方が無難だと思います。

テーブル結合の失敗パターン

RDBMSでのSQLによる問い合わせにおいて、複数のテーブルを結合するパターンは比較的複雑な操作になります。
そのため、ミスも起こりやすいです。

今回は、注意喚起のため、私が実務で出くわしたミスを3つ挙げます。

1.外部結合の結合条件をwhere句に書いてしまい内部結合になってしまう

2.結合条件指定不足で意図せず直積結合してしまう

3.結合条件となる値のセットを誤り結合できなくなってしまう


1.外部結合の結合条件をwhere句に書いてしまい内部結合になってしまう

例えば、以下のようなテーブルがあるとします。

・ログイン日時管理テーブル

・ユーザ名履歴テーブル

ここで、

・ユーザがログインした時のユーザ名を知りたい

・ただし、ユーザがログインした時、ユーザ名が存在しない場合がある

(この場合、ユーザ名が存在していない旨を知りたい)

 

という要件があった場合を考えます。

正しいselect文と問い合わせ結果は以下です。

もし、ここで、誤って結合条件の一部をwhere句に記述すると、下記のようになります。
左側外部結合なのに、左側のテーブルにしか存在しないレコードが抽出されません。

誤ったSQL文については下記①②のような動きになるため、このような結果になります。

① on句に指定された条件で左側外部結合を行う

② ①の結果に対して、where句とselect句が評価される。

(where句で条件指定した場合、内部結合と同じようになる)


2.結合条件指定不足で意図せず直積結合してしまう

例えば、以下のようなテーブルがあるとします。

・社員マスタテーブル

・保有資格管理テーブル

ここで、会社コードが”001″の会社の全社員が保有している資格を取得したいとします。

正しいselect文と問い合わせ結果は以下です。

もし、ここで誤って結合条件に社員コードを含めないと、以下のように実際に保有している資格数よりも多く出力されてしまいます。

なぜこうなるのかは、select文で全カラム指定すればよくわかると思います。
社員マスタテーブル.社員コードと保有資格管理テーブル.社員コードが一致しないレコードについても結合してしまうため、意図せずに直積結合が起こり、実際に保有している資格数よりも多く出力されてしまいます。


3.結合条件となる値のセットを誤り結合できなくなってしまう

例えば、以下のようなテーブルが存在するとします。

・利用料金テーブル

・利用料金明細テーブル

結合する時に指定するキーは利用番号になるため、以下のように利用番号には同一の値を使用する必要があります。

しかし、利用番号がプログラム中で生成する連番であり、かつプログラム中で利用料金テーブルと利用料金明細テーブルで別々に連番を付与していた場合、利用番号で結びつかなくなってしまいます。

こうなると、利用料金テーブルと利用料金明細テーブルを結合するという使い方ができなくなり、後で困ることになります。
更に、既にサービスイン後であり過去データの補正が必要になった場合、その補正も困難になる場合があります。


いかがでしたでしょうか。

今回は失敗パターンの説明ということで、テーブル結合の失敗パターンを取り上げました。
失敗パターンは実務をこなす中で暗黙知的に知ることが多いと思いますので、文章に起こして共有できる形にしていきたいと思います。

リスコフの置換原則とは

リスコフの置換原則とはオブジェクト指向の設計の原則の一つであり、「基本クラスをサブクラスに入れ替えても問題なく動かなけらばならない」という原則です。
もしサブクラスに入れ替えると正しく動かなくなるのであれば、クラスを利用する側はサブクラスを使用してはならないというのを意識しながらコーディングしなければならず、保守性が低下します。

クラスの入力・出力に目を向けると、以下の条件を満たすとリスコフの置換原則を満たすことができます。

1.サブクラスの入力のパターンは、基本クラスの入力のパターンよりも緩い

2.サブクラスの出力のパターンは、基本クラスの入力のパターンよりも厳しい
 

もし、サブクラスの入力のパターンが基本クラスの入力のパターンよりも厳しいと、利用する側はサブクラスを利用する際にサブクラスが許容する入力であるかどうかを意識する必要が出てきてしまいます。
また、サブクラスの出力のパターンが基本クラスの出力のパターンよりも緩いと、利用する側はサブクラスを利用する際にサブクラスが予期せぬ出力をしないか意識する必要が出てきてしまいます。

以下のサンプルコードは、割り算を行う基本クラスであるDivideクラスを、サブクラスのDivideBusinessクラス・DivideBad1クラス・DivideBad2クラスで入れ替えてみるサンプルです。

DivideBusinessクラスは、基本クラスが許容する入力パターンに加え分母=0のパターンも許容し、基本クラスが出力することがある負数を出力しません。Divideクラスと入れ替えても特に考慮するパターンが増えることはなく、リスコフの置換原則を満たした良いクラスです。
しかし、DivideBad1クラスは、基本クラスが許容する分子=負数のパターンを許容せず、基本クラスと入れ替えた場合は分子が負数になっていないか意識する必要が出てきてしまいます。
また、DivideBad2クラスは、基本クラスと異なりnullを出力するパターンがあり、基本クラスと入れ替えた場合は出力がnullになる場合を意識する必要が出てきてしまいます。

【サンプルコード】

・DivideMain.java

・Divide.java

・DivideBusiness.java

・DivideBad1.java

・DivideBad2.java

【結果】


いかがでしたでしょうか。

ポリモーフィズムを利用するとソースコードを簡潔にできるのですが、それを実現するためにはリスコフの置換原則を満たすことが必要です。
デザインパターン等で良い設計に触れている方なら自然に満たせるものかもしれませんが、今一度意識してみるのも良いかもしれません。

単一責任の原則とは

オブジェクト指向の設計ではいくつかの原則があります。
その中でも有名な原則の一つが「単一責任の原則」です。

この原則は、その名の通り「一つのクラスに持たせる責任は一つにする」という原則です。
この原則が何のために用いられるのかと言うと、複数の理由で1つのクラスを修正するのを防ぐためです。
ここで言う「理由」を「案件」、「クラス」を「ソース」と捉えると分かりやすいと思います。
複数の案件で1つのソースを修正する必要が出てしまうと、並行開発手順やバージョン管理等が煩雑になってしまい、品質に悪影響が及びます。

「一つのクラスに持たせる責任は一つにする」と捉えると具体的なイメージが浮かびにくいと思うのですが、「複数の案件で1つのソースを修正しないような粒度で設計する」と捉えると分かりやすいと思います。


以下では、javaのソースコードで例を出します。
商品の名前と値段を登録し、それを表示するという例です。

まずは悪い例からです。

【サンプルコード1】

・CommodityMain.java

・RegistShowCommodity.java

【実行結果1】


ここで、「商品の税込み価格を計算可能にする」という案件と、「表示を綺麗にする」という案件が発生したとします。
今の設計だと、どちらの案件も RegistShowCommodityクラスの修正となってしまいます。

そこで、商品の登録を行う RegistCommodityクラス、商品の価格計算を行う CalcCommodityクラス、価格表示を行う ShowCommodityクラスの3クラスに分割します。

【サンプルコード2】

・CommodityMain.java

・RegistCommodity.java

・CalcCommodity.java

・ShowCommodity.java

【実行結果2】


3クラスに分割した結果、「商品の税込み価格を計算可能にする」という案件は CalcCommodityクラスの修正、「表示を綺麗にする」という案件は ShowCommodityクラスの修正で対応できるようになり、別々の案件で1つのクラスを修正する状態を防ぐことができました。

【サンプルコード3】

・CommodityMain.java

・RegistCommodity.java

・CalcCommodity.java

・ShowCommodity.java

【実行結果3】


いかがでしたでしょうか。

オブジェクト指向の設計と言うと覚えることが多くて大変だという印象を持つかもしれませんが、いくつかの原則を抑えるだけでも良い設計ができます。
(デザインパターンも、原則に則って設計を考えると自ずと導き出されるものだと思っています)

単一責任の原則は代表的な原則の一つなので、覚えておいて損はないと思います。