ChatGPTと学ぶシステムアーキテクト試験(午前2)

今回、QiitaでChatGPTなどの活用方法を発信しよう!という企画をやっていたので、参加してみました。
自分が投稿したこちらの記事と同じ内容です。

今回は最近流行りのChatGPTを高度情報技術者試験に応用するとどんな感じになるか、試してみました。

今回題材に使ってみたのは、[令和3年度のシステムアーキテクト午前2の問題](https://www.ipa.go.jp/shiken/mondai-kaiotu/gmcbt8000000d5ru-att/2021r03h_sa_am2_qs.pdf)です。

# 試しに問1を解かせてみる
![q1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/aad7d5aa-ddc5-a5e3-ce96-14267b4c4377.png)

そうすると、以下の回答が出てきます。
![q1_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/4b38fb38-063b-2e86-1ac9-22583821a0db.png)

おーーーーっ、正解だ!

# 続いて問19を解かせてみる
![q19_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/66fd3f2f-9deb-84fb-11e4-13fb552e65bc.png)

ChatGPTの回答はこちら。
![q19_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/1787d492-0789-5e50-5491-27d5d99cd4d2.png)

正解は「イ」なので、これは外れです。
AIも間違えることはあるということか。

![q19_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/10f5aa77-2f28-2359-7108-557147edc0ba.png)
ちゃんと間違いを認めて謝罪するのは素直だな(笑)、と思ったら今度は向こうが問題を出してきた:open_mouth:

![q19_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/65059b9d-ceb6-b63e-c933-fa24df09b457.png)

とりあえず回答すると答えと解説を出してくれたけど、1回目の解説が前の問題の解説のままだ・・・

# とりあえず25問解かせてみた
![25_finished.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/505d1d53-05ce-dd10-50ad-fec41b659614.png)

正解数は19問。おーーーーっ、合格だ!自分はギリギリセーフの15問だったので、俺より優秀なのか:sweat_smile:っていうかしっかり勉強しろ俺。

# 超大雑把にまとめてみる
とりあえず、ITが生み出しただけあって、IT分野については普通に優秀ですね。たまに間違えることがあるのでファクトチェックは必要ですが。
ただ、分野によって得意不得意が激しいみたいなので、例えば夏目漱石の「坊ちゃん」について聞いてみたら、デタラメもいいところでした:scream:
![bocchan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66360/dcb534a7-9d90-7009-5451-88bf8c8a2245.png)

MySQLが遅いと思ったときにやること


1.はじめに
1年近くサボってた弊技術ブログですが、zennデビューしたということで、こちらにも同じ記事を載せて見ます。
今回はこちらの記事と同じ内容です。

MySQLで検索や更新などを行っているときに「このクエリ遅いなー」と思ったときにどういう流れで解決を図るか、自分なりの定石(?)です。
ちなみに、MySQLのバージョンは8.0を前提に記載しています。

2.スロークエリログ

まずはやはりこれ。でもそもそも出力される設定になっていないと見ることもできません。なので、出力される設定にしておきましょう。
設定ファイル(Windowsならmy.ini、MacまたはLinuxならmy.cnf)の[mysqld]のセクションに以下の設定を入れる必要があります。

slow_query_log=ON
long_query_time=2
slow_query_log_file=slow.log

1つ目はスロークエリログ出力の有無で、ONにする必要があります。
2つ目は実行に何秒以上かかったらスロークエリとするかの判定基準です。どれくらいにするかはDBをどういう使い方をするかにもよるけど、自分は大体2〜3秒くらいが多いかも。
3つ目は出力するログファイルの名前。ここはわかりやすい名前にするのがいいでしょう。

スロークエリログの見方については、こちらあたりを参考にして見てください。
絶対見るのは実行したSQLとかかった時間(Query_time、Lock_time)で、それ以外に探索したレコード数、ヒットしたレコード数とか状況に応じて必要な情報を、といったところでしょうか。

3.EXPLAIN

スロークエリログの次に見るのがEXPLAIN。MySQL Workbenchなどで遅くなっているSQLの前にEXPLAIN をつけて実行すると、実行計画(クエリをどうやって実行するか)を出力してくれます。
実行計画の見方はこちらあたりが参考になると思います。
例えば、typeのところにALLやindexがあったらインデックスがうまく使われていないんだなとかがわかると思います。

4.インデックス

上記に書いたインデックスですが、さすがに今時インデックスを全く貼らないという人はあまりいないと思いますが、それでもただ闇雲に貼ればいいというわけではありません。
例えば、TRUEまたはFALSEのみしか入らないカラムに貼ってもほとんど意味はないです。後、値がよく変更されたり新たな値が入ったり消されたりするカラムに貼るのもお勧めできないです(全体的に重くなるので)。
貼るべき箇所はレコードによって一意またはいろいろな値が入るカラムで、かつ検索条件やORDER BYのソートキー、あるいはJOINの結合条件になることが多いカラムに貼るのがいいでしょう。

後、カラムに対して何らかの演算を行なったり、後方一致や中間一致(前方一致はOK)のLIKEで検索を行う場合はインデックスが効かなくなるので注意が必要です。
あるカラムに何らかの演算を行うようなSQLを頻繁に実行する場合は演算結果をGenerated Columns(仮想列)としてテーブルに持っておいて、それにインデックスを貼るやり方もあります。Generated Columnsについてはこちらを参考にして見てください。

5.その他クエリチューニング

よく言われるのが、

SELECT * FROM CUSTOMER;

のようにワイルドカードを使うのではなく、

SELECT id, name, age FROM CUSTOMER;

のように必要なカラムだけを指定するとかです。
後はJOINする時は結合対象のテーブルをWHEREで絞り込んでから結合するとかサブクエリが複雑になりすぎている時は一旦バラしてサブクエリを使わずにできるか検討するとかでしょうか。

6.パラメータチューニング

スロークエリログのところでも出てきたmy.iniまたはmy.cnfのパラメータでパフォーマンス改善に寄与できるところはいくつかあります。
例えばinnodb_buffer_pool_sizeを大きくしてメモリにキャッシュできるサイズを大きくする(マシンのメモリサイズの7〜8割が目安と言われています)などがあります。
こちらの記事に詳しい情報が記載されています。

7.終わりに

こんな感じでスロークエリの改善と一言で言っても、いろいろなアプローチがあります。自分もまだまだSQLチューニングについては勉強することがあると実感しますが、手を加えて遅いクエリが早くなった時は何とも言えない充実感があります。
皆さんも高速化手法を覚えて、MySQLライフを楽しみましょう!

Java13〜17 振り返り

Qiitaのアドベントカレンダーに18日に予定入れていたのだが、ダラダラして遅くなってしまった(汗)
以前この記事でJava8〜12までの流れをものすごくざっくりと紹介していたので、それから2年9ヶ月の間にJavaがどのように進化していったかを思いっきりざっくりと書き連ねてみる。
ちなみに、Java9からはずっと半年ごとにバージョンが更新されています。

2019年9月 Java13 テキストブロック、switch式など
2020年3月 Java14 Recordクラスなど
2020年9月 Java15 Sealedクラスなど
2021年3月 Java16 VectorAPIなど
2021年9月 Java17(LTS) switchのパターンマッチングなど、Javaアプレット廃止

この中だと、Recordクラス、Sealedクラスはうまく使えばプログラミングの幅が広がりそうですね。後、Javaのswitch文は若干使いづらいと感じていたので、これで使いやすくなるかなという期待はあります。
後は、時代の流れもあって最近は使われることも少なくなったとはいえ、昔はアプレットを使っていろいろ遊んだこともあったので、アプレット廃止は仕方ないとはいえ少し寂しかったり。

SQLアンチパターン

やろうと思っていた個人開発がどうにも滞ったまま何ヶ月も経ってしまい、でも久々に記事だけでも更新しなきゃなということで今回は技術書の紹介。
今回紹介するのはSQLアンチパターンという本。業務でDB設計をやる機会が増えて、設計に関して気をつけなきゃいけないことを把握しようと思って買ってみた。
本全体の感想としては、DB設計に関わる人なら一度は読んでおくべき本だなという印象。テーブル定義や設計などで避けるべきことが網羅されている感じ。
紹介されているパターンが25もあるので、今回は特にやりがちなパターンを3つほど紹介してみる。

1. 3章 : IDリクワイアド(とりあえずID)
新しいテーブルを作る時、何でもかんでもとりあえずIDカラムを入れるというのをやりがちな人は結構多いのではないかと(自分含む)。
例えば、学生ごとに受講する科目を定義するstudent_subjectというテーブルを考えてみる(studentテーブルとsubjectテーブルは別途定義されているとする)。
id student_id subject_id
1 1 1
2 1 2
3 2 3
4 3 2
また、テーブルを生成する際にUNIQUE KEY (student_id, subject_id)でstudent_idとsubject_idが一意になるようにする。
そうなると、”id”カラムってなんのために使うんだという話になってくるので、必要でないカラムをあえて入れておく必要はないのではということになる。
とはいえ、このテーブルに成績を表すgradeというカラムを追加して、さらに別のテーブルと連結させる必要が出てきたりした場合はidカラムに相当するものが必要になるので、ケースバイケースではあるが(もっとも、この場合はテーブル名をもっと別の適切な名前にすべきだが)。
要約すると、「このidカラム、本当に必要ですか?」ということか。

2. 10章: サーティーワンフレーバー(31のフレーバー)
あるカラムに入る文字列の値をいくつかに限定したい場合、MySQLではENUM型で定義することがある。他のRDBMSはあまり使ったこと長いのでわからないが、CHECK制約を入れて入る値を限定するやり方があるらしい。
例えば、従業員が所属する支社が”TOKYO”、”OSAKA”、”NAGOYA”、”SAPPORO”の4つのいずれかという場合、officeカラムをENUM(‘TOKYO’,’OSAKA’,’NAGOYA’,’SAPPORO’)という風に定義していたとする。
employeeテーブル
employee_id name        office
1                      Suzuki       TOKYO
2                      Sato            OSAKA
3                     Tanaka       NAGOYA
4                     Yamamoto TOKYO
5                     Yoshida      SAPPORO
ところがある日、那覇支社が新たに追加された場合ENUM(‘TOKYO’, ‘OSAKA’,’NAGOYA’,’SAPPORO’,’NAHA’)に定義を変更するのは結構面倒臭い。

このような状況を避けるには、以下のようにすればいい。
officeテーブルを新たに定義し、employeeテーブルにoffice_idを持たせる。
employeeテーブル(修正版)
employee_id name        office_id
1                     Suzuki     1
2 Sato 2
3 Tanaka 3
4 Yamamoto 1
5 Yoshida 4
officeテーブル(追加)
office_id office_name
1 TOKYO
2 OSAKA
3 NAGOYA
4 SAPPORO
5 NAHA

ただし、入る値が”LEFT”、”RIGHT”など絶対に追加されることが無いと断言できる場合はENUM型を使ってもいいと思う。なので、ENUM型での定義を考える場合は新たな値が追加される可能性をまず検討すべきかと。

3. 18章 : インプリシットカラム(暗黙の列)
プログラム内でデータベースから検索する時、’SELECT * from (テーブル名) where (検索条件)’に相当するような検索クエリを呼び出すような形で結果を取得するようなことがあると思う。
あるいは、’INSERT INTO (テーブル名) (カラム) VALUES (値)’でレコードを追加するときにデフォルト値が設定されているカラムを省略したりすることもあるはず。
けど、実はこれらには落とし穴があったりする。例えば、カラム数が10あったとして、取得した値をカラムごとに配列に入れていた場合、誰かが不要なカラムを1つ削除したとすると、配列の要素数が9しかないのに10番目の要素にアクセスしたらエラーになってしまう!
それ以外にも不要なデータまでも持ってきていることでクエリが必要以上に重くなってしまうこともあり得る。
なので、多少面倒でも必要なカラムのみを明示的に指定した方が後々問題が発生するのを避けることができる。

終わりに
25のアンチパターンの中で、自分も気をつけていないとついやりがちなパターンを3つほど上げてみたけど、逆に「これは普通やらないだろ」ってのもちらほらあったなあ。
例えば、1章の「ジェイウォーク(信号無視)」は1つのカラムに無理やり複数の値をカンマ区切りで入れるのは少なくとも自分は気持ち悪く感じるし、20章の「SQLインジェクション」は最近のフレームワークだとほぼ対策がされているのではないかと(それでも、ユーザー向けのシステムの場合はテストの時にフォームにSQL文を入れて変なことにならないかの確認はやるけど)。
それでも、こういう「べからず集」は意識して開発していけば後々のトラブルの元が減らせることになるので、設計していて違和感を感じたら本を見返して問題点と対策を把握しておくのがいいだろうな。

半年近く滞っていた個人開発の方も、どこかのタイミングで再開したいなあ。

Tramoriesその1 開発環境構築(SpringBoot, MySQL)

前回の記事で個人開発でWebサービスを作るのを目標にすると書いて、1ヶ月以上経ってしまったorz
というわけでまずは環境構築(Macを前提にしています)。まずはサーバーサイドから。

1. MySQL
まだインストールしていない方はこちらが参考になると思います。
自分はすでにインストールしていましたが、下記のようなエラーが出るので、こちらを参考に解決を図る。

すると次は下記のエラーになったので、こちらを参考にしてみる。

そうしたら、解決!記事を書いてくれた方に感謝!m(__)m

その後は下記のSQLでユーザー、データベース、権限を作成。

CREATE DATABASE tramories;
CREATE USER tramories IDENTIFIED BY ‘*******’;
GRANT ALL ON tramories.* TO 'tramories'@'localhost' IDENTIFIED BY ‘*******’;

2. Spring Boot
データベースを作った次は、Spring Bootの環境構築。
Spring Bootの環境構築にはSpring Initializrというとても便利なサイトがあるので、これを使います。
自分はProject : Maven, Language : Java, Spring Boot : 2.5.0で作りました。
DependenciesはSpring Boot DevTools, Spring Web, Lombok(自動的にゲッターとセッターを作ってくれるので、すごく便利!), Thymeleaf, Spring Security, OAuth2 Client, Spring Data JPA, Flyway Migration, MySQL Driver, Spring Batchを入れました(他にも何か入れたかも)。

その後は大雑把に以下の流れ。
1. application.propertiesに必要な設定を追加
2. ログインユーザー用のサービス、エンティティ、リポジトリを作成し、Flywayでユーザーテーブルとレコードを作成
3. 簡単なログインページを作成し、ログインできるところまで確認

詳細は後日GitHubにアップするので、そちらを見ていただければと。

次回はフロントエンド(React)の環境構築をやります。

2021個人開発Webサービス案

明けましておめでとうございます。2021年もよろしくお願いします。

さて、今年の目標の1つとして、今年こそ個人のWebサービスを開発しようと思っています。
開発しようと思っているサービスと、使う予定の技術はざっと以下のような感じです。

サービス名
 Tramories トラモリーズ(travel + memories

サービス概要
旅の写真(昔の写真も含む)を共有し合うサービス

サービス詳細
投稿機能(写真+簡単な説明)、タグ、コメント、いいね、ユーザーフォロー
 OAuth2認証(検討中)オススメ機能(検討中)

一般的なミニSNSっぽい感じですが、

使用技術
 サーバーサイド
  JavaSpring Boot(機械学習を入れる場合はPythonFlask
Laravelを使うかかなり迷ったけど、今仕事で使っていることだし、Spring Bootにしようかと。
機械学習でおすすめ機能とかスパムフィルターとか取り入れるんだったら、Flaskで機械学習API作るのもありかなと思ったり。

 フロントエンド
  TypeScriptReact
フロントエンドのフレームワークはこれかなと。JavaScriptで行くかTypeScriptにするかは若干迷っているけど。

 データベース
  MySQL
ここはこうなるか。PostgreSQLは一度も触ったことがないんで。最近流行りのNoSQLも今回はいいかなと。

 Webサーバー
  Apache
ここもこれしかないか。Nginxも最近は増えてきているようだけど、Apacheで。

 インフラ
  Microsoft AzureHerokuなども検討中)
ここが一番の悩みどころ。以前AzureにWordpress入れたら1ヶ月で6000円とかしてすごい焦ったもんなあ。
誰かWebサービスを安くデプロイする方法を知っている方教えていただけるとありがたいです。

ドキュメント、その他
 画面仕様書、テーブル定義書、機能設計書(処理フローなど)、単体テスト仕様書、結合テスト仕様書
個人サービス作る場合ってドキュメントとか公開するものなのかなあ?公開しないにしても仕事の練習になるだろうし、作ろうとは思っています。

少しづつ作って行って、何とか年内には公開したいなあ。

Javaの例外処理

今回はQiitaのアドベントカレンダーの投稿日ということもあって、Javaでの例外処理のやり方について、さらっと紹介していこうと思います。

1. プログラムにおける例外とは

そもそもプログラムにおける例外は何かというと、一言で言うと「文法としては正しいにも関わらず、実行すると想定外の状況が発生し、プログラムが実行不能になること」と言うことになります。
まず厄介なのが、「文法としては正しい」ので、コンパイルが通ってしまうことです。なので、「よっしゃ、コンパイルが通ったぞ!」と思って実行したら、「あれ!?」と言うことになるわけです。
なので、どのような値が来るとどうなって、実際に起こり得るけど起こったらまずい状況とはどう言う場合かを考えて、それに応じて然るべき対応ができるようにする必要があるわけです。
次に、具体的に「どう言う状況が例外に当たるか」の例をいくつかあげて見ます。
・nullの領域にアクセスして何かやろうとした
・配列やリストなどの要素数より大きい数字のインデックスにアクセスした
・0で割り算した
・許可されていない場所にアクセスした
・ファイルに対して何かやってたらファイルが途中で消えた

2.例外処理の基本
Javaにおける例外処理の基本形は、こんな感じです。

try {
  // ここで何らかの処理
} catch (Exception e) {
  // 例外が発生したらここに来る
}

ただ、Exceptionクラスだと、nullアクセスも0割りも、その他諸々含めて一緒くたに扱われるので、一般的にはExceptionクラスのサブクラスを使って、起きた例外に応じた処理を行います。
例として、nullが入ったString変数に対して文字列の長さを取得しようとした場合を見てみます。

try {
  String str = null;
  System.out.println(str.length());
} catch (NullPointerException e) {
  System.err.println(e.getMessage());
  e.printStackTrace();
}

これで、例外の中でもNullにアクセスした場合の例外のみに対して例外処理が行われます。ちなみに、printStackTraceメソッドは例外が起きたところからのメソッド呼び出しの階層一覧を出力してくれます。結構便利なので、デバッグでよく使います。
どんな例外クラスがあるかは、Javaの公式ドキュメントを見てください。

3. 独自の例外定義とthrow、throws
Javaでは(大体の言語でそうだと思うけど)あらかじめ用意されている例外以外に、独自の例外クラスを作ることができます。
例えば、温度が100度を超えたらエラーにするとかを考えて見ます。

// このクラスで100度以上になった場合の例外を定義
class TooHotException extends Exception {
  public TooHotException(String s) {
    super(s);
  }
}
   try {
      int temperature = getTemperature();
      if (temperature > 100) {
        // 温度が100度以上だったら先ほど定義した例外クラスに投げる
        throw new TooHotException(“Too hot!”);
      }
    } catch (TooHotException e) {
      System.err.println(e.getMessage());
    }

こんな感じです。なお、ここで出てきたthrowは、呼び出すことで対応するcatch節に処理を移すのに使います。

もう1つ、throwに似た名前のthrowsという構文がありますが、これはある例外が発生したら呼び出し元に処理を任せるのに使うものです。
使い方はこんな感じです。


public void newFunc() throws NumberFormatException {
  // このメソッド内でNumberFormatException例外が発生したら、呼び出し元で例外処理を行う
}

ちなみに、NumberFormatExceptionは数値が入るべきところに数値以外のものが来た場合の例外です。

4. 例外が起きようと起きまいと共通の終了処理を行う場合
例外が発生して、何らかのエラーメッセージを出すものの、最後に何らかの共通処理を行いたい場合は、finallyを使います。

try {
  // ここで何らかの処理
} catch (Exception e) {
  // 例外が発生したらここに来る
} finally {
  // 例外が発生してもしなくても最後にここに来る
}

ファイルバッファを最後に閉じる例です。

  BufferedReader br = new BufferedReader(new FileReader(path));
  try {
    br.readLine();
  } catch (IOException e) {
    System.err.println(e.getMessage());
  } finally {
    if (br != null) br.close();
  }

ただ、Java7以降でtry-with-resources文を用いることによって、finallyを使わなくても使い終わったものを終了することができるので、紹介しておきます(こっちが使えるならこっちの方がいいです)。

  BufferedReader br = new BufferedReader(new FileReader(path));
  BufferedReader br = new BufferedReader(new FileReader(path));
  try (BufferedReader br = new BufferedReader(new FileReader(path));) {
    br.readLine();
  } catch (IOException e) {
    System.err.println(e.getMessage());
  }

5.その他注意点いくつか
例外処理におけるいわゆる禁じ手をいくつか紹介しておきます。
・例外を握り潰さない


try {
  // 何らかの処理
} catch (Exception e) {
}

これだと、例外が発生した場合でも握りつぶして次に進んでしまいますが、このようなことはせず、ちゃんと例外に応じた処理(エラーログを出して処理を終了するとか)を行いましょう。
・例外処理は本当の例外に対してのみ行う
ごく稀に、例外処理を分岐みたいな使い方をする人がいますが、このようなことをやってはいけません。分岐はちゃんとif文とかを使い、プログラムとかシステムとかで通常は起こりえないイレギュラーな事態だけcatchされるようにしましょう。

ここまでざっと例外処理について書いて来ましたが、やはり実際に色々プログラムを書いて見て慣れるのが一番です。
これを読んだみなさんも是非例外処理を使いこなせるように頑張りましょう!

Javaの文字列入門

ここのところあまり更新できていなかったので、久々の投稿、今回はJavaの文字列についての扱いを簡単にまとめて見ます。

Javaでは文字列は標準クラス(Javaの言語機構に標準で含まれているクラス)のStringを使います。

String str = new String("Hello world");

こんな感じです。
あるいは、下記のような書き方でも宣言できます。

String str = "Hello world";

ただし、newを使うやり方だと無駄なインスタンスを使うことになってしまうので、通常はString str = "Hello world";のようにします。

文字列の扱いは、文字列用に用意されたStringクラスのメソッドを使うことで便利になります。

// length 文字列の長さを取得
String str1 = "apple";
int strlen = str1.length(); // 5

// substring 文字列の部分文字列を取得
// 1番目の引数:始まりの位置(0から始まる)
// 2番目の引数:終わりの位置(省略すると最後まで)
String str2 = "orange";
String str3 = str2.substring(2, 4); // ang
String str4 = str2.substring(0, 3); // oran
String str5 = str2.substring(3); // nge

// indexOf 指定された文字列が最初に現れる位置を返す(0が起点)
// 存在しない場合は-1が返される
String str6 = "banana";
int index1 = str6.indexOf("nan"); // 2
int index2 = str6.indexOf("non"); // -1

他にも文字列を扱うメソッドはたくさんあるので、詳しくは公式ドキュメント(Java8)を見てください。

後、文字列の比較はequalsというメソッドを用います。

String str7 = "Tokyo";
String str8 = "Tokyo";
String str9 = "Osaka";
boolean check1 = str7.equals(str8); // true
boolean check2 = str7.equals(str9); // false

こんな感じです。イコール(=)で比較するとメモリ領域を比較することになるので、必ずしも期待した結果にならないので気をつけてください。

文字列の結合はプラス(+)を使います。

String str10 = "Super";
String str11 = "Star";
String str12 = str10 + str11; // "SuperStar"

こんな感じです。ただし、何回も繰り返すとパフォーマンスが悪くなるので、このような場合はStringBuilderクラスを使って以下のようにします。

StringBuilder builder = new StringBuilder();
List<String> data = getData(); // getDataは文字列のリストを取得するメソッドとします
int dataSize = data.size();
for (int i = 0; i < dataSize; i++) {
    builder.append(data.get(i));
}
return builder.toString();

こんな感じで、いくつか気をつけるところがあったりしますが、うまく文字列処理ができるようになりたいものです。
文字列処理は正規表現を使うともっと複雑なことができたりしますが、それについては別の機会に紹介します。

令和2年秋 データベーススペシャリスト受験記

10月18日日曜日、4月に行われるはずだったのが延期になっていたデータベーススペシャリストの試験を受けて来た。会場は沖縄県立那覇工業高校。

午前1はこの時のおかげで免除で、午前2から。
自分の受けた教室は受験人数は20人より少し少ないくらいか。

午前2
問題はこちら。いきなり問1にCAP定理が出て、焦る。昨年CAP定理が出たから今年は出ないだろうと思っていたけど、違う切り口で出てきた。これはやはりCAP定理についてちゃんと理解しておく必要があるということか。
問2も新作問題のNoSQLについてだが、参考書で別のノードに時間差で反映されるのがあった気がして、イにマークする。
問3からは過去問通りの問題が出て来て、ペースが上がってくる。
最後の方に電気泳動型電子ペーパーとか知らない問題も出て来たが、終わってみるとまあ大丈夫かなという感触。
解答はこちら。自己採点で18/25。一安心。

午後1
問題はこちら
予定では問1+問2か問3のどちらかなので、まずは問1を解いていく。
問題の意味はまあわかるのだが、45分(90分の半分)でやるにはどうにも量が多い。最後の方は結構慌てて書いたので、リレーションをいくつか書き損ねてしまう。
問1が終わったところで47〜8分くらい経過。問2と問3をざっと見て、問2の方が記述の量が少なそうなので問2に行くが、これが失敗だった。
設問1と設問2の最初はまあわかったのだが、そこから先がさっぱりわからず、これはまずいと思い問2を退散し、問3に。10分くらいタイムロスしてしまったので30分で問3を解かなければならない。
しかし、問3はやってみると3問の中では一番簡単で、販売額がNULLになるケースと一番最後のテーブル構造以外はそんなに悩まず解くことができた。
試験後のツイッターとか5chとかを見た感じだと、やはりみんな問1が時間かかり過ぎという声が多かった。

午後2
問題はこちら
こちらは物理設計が苦手なのでお絵かきの問2と最初から決めており、問1には目もくれず問2にかかる。
こちらは時間的には午前1よりは十分にあるのだが、ルート巡回とかがいまいちイメージしきれず、リレーションの線を引く箇所も結構迷うところが多く、なかなかしんどかった。
特に設問2(2)の6箇所中5箇所が同じ回答になってしまい、本当かよと思いつつ、他に回答が思い浮かばず6箇所中5箇所が同じ回答のまま進める。
どうにか回答を埋めきったけど、全然答えに自信が持てないorz
去年のパン屋の問題がかなり難しかった反動で易化を期待したけど、残念ながらそうはならなかったか。

その他
試験勉強はこの本を主に使いました。
午前2は何回か過去問をやって大丈夫そうだったので、午後にやや重きを置いて勉強しました。
勉強の仕方としては、問題と解答をよく読んで解き方を理解して行くというものでした。ただ、今になって思えばもう少し手を動かせばよかったかなと。

合格発表は12月25日のクリスマス。去年のアーキテクトも含めて高度試験は3回午後2で沈没しているので、そろそろ受かりたいけど、どうなるか。。。

合格発表は12月25日のクリスマス。去年のアーキテクトも含めて高度試験は3回午後2で沈没しているので、そろそろ受かりたいけど、どうなるか。。。

2020/12/25追記

何とか合格しました!!
午前1:免除、午前2:72点、午後1:69点、午後2:62点でした。
午後2は本当ギリギリだったので(配点がわからないので何とも言えないけど)、リレーションをあと数本引き忘れていたら落ちていたと思うと、本当ゾッとする(汗)
勝因としては、最後まで諦めずに粘ったことと、午後1で手が動かなくなった時点で問2を退却して問3に切り替えたことか。
とは言え、現在業務でテーブル設計とかやっているけど、実務の点ではまだまだだと痛感するので、これから勉強を積んで本当の意味でデータベースのプロになれるよう研鑽を積んでいきたい。

次は何を受けるかを考えると、ネットワーク(に限らずインフラ全般)は苦手だし、エンベデッドは業務と結びつかないし、セキュリティ改め情報処理安全確保支援士は資格を維持するのにかなりお金がかかるみたいなので、長文を書くのは苦手だけど、論文系の資格(システムアーキテクトorプロジェクトマネージャ)を狙うしかないなあ。

TypeScript入門 その3

TypeScript入門3回目の今回は、データ型の中でも、前回紹介できなかった列挙型(enum)、タプルや関数オブジェクトあたりについて説明しようと思います。

1. 列挙型(enum)
列挙型(enum)とは、あらかじめ決められた値のみを取ることができるデータ型です。例えば、こんな感じです。

enum Signal {
 Red, Yellow, Blue }; let red = Signal.Red; let yellow = Signal.Yellow; let blue = Signal.Blue; console.log(red); // 0 console.log(yellow); // 1 console.log(blue); // 2 // let green = Signal.Green // コンパイルエラー!

このようにして定義された変数signalは、Red, Yellow, Blueのいずれかしか代入することが出来なくなっています。
また、enumはデフォルトでは内部では0から始まる整数を取るようになっていますが、

enum Signal {
  Red = 2,
  Yellow = 3,
  Blue = 4
};

というように、定義するときに取る値を変更することもできます(数値だけでなく、文字列を入れたりもできます)。
ところで、最近ではenumを使わない方がいいという意見もあるようです。
enumを使わない書き方としては、こんな感じです。

const Signal = { 
  Red: 0,
  Yellow: 1,
  Blue: 2
} as const;
type Signal = typeof Signal[keyof typeof Signal];
let red = Signal.Red;
console.log(red);  // 0

このような有限集合のデータ型をUnion型と言います。
TypeScriptの経験が浅い自分はenumのデメリットを把握しきれてないのですが、enumはJavaScriptとの互換性がないというのは確かにありますね(コンパイル後のソースを見ると一目瞭然)。

2. タプル
次は、複数の型の値をまとめて持つことができるタプルというものを紹介します。
配列のように複数のデータ型を宣言することで定義できます。
例えば、こんな感じです。

let person: [string, number, string];
person = ["Taro", 26, "Tokyo"];
console.log(person[0]); // Taro
console.log(person[1]); // 26
console.log(person[2]); // Tokyo
person[1] = 30; // OK
person[1] = "30"; // コンパイルエラー

とはいえ、この書き方だと何を表しているかわからなくなりがちなので、下記のような使い方の方がわかりやすいかもです。後、先ほどのenumももちろん要素にすることができます。

type name = string;
type age = number;
type address = string;
enum gender {male, female};

let person: [name, age, address, gender];
person = ["Taro", 26, "Tokyo", gender.male];

3. 関数オブジェクト

TypeScriptでも、JavaScriptと同じように関数の定義を行えますが、やはりそこはTypeScript。引数と戻り値に型を指定することができます。

function multiple(a:number, b:number):number {
  return a * b;
}
multiple(5, 3); // 15
multiple(5, "3"); // コンパイルエラー

こんな感じです。
また、TypeScriptでは下記のようにオプション引数を使うことができます。

function multiple(a:number, b:number, c?:number):number {
  if (c) {
    return a * b * c;
  }
  return a * b;
}
multiple(5, 3); // 15
multiple(5, 3, 4); // 60

後は、同じ名前の違う型で定義された関数も定義することができます。いわゆるオーバーロードです。

function add(a:string, b:string):string;
function add(a:number, b:number):number;

function add(a:any, b:any):any {
    if (typeof a === "string" && typeof b === "string") {
        return a + ":" + b;
    }
    return a + b;
}
add("Hello", "World"); // Hello:World
add(7, 4); // 11
add("Hello", 4); // コンパイルエラー

 

今日はこの辺りで。
次回最終回(予定)はクラスとかのオブジェクト指向に関する話題を紹介しようと思います。