echo("備忘録");

IT技術やプログラミング関連など、技術系の事を備忘録的にまとめています。

【AWS】CloudWatchの料金体系を調べてみた

今回の内容

今まで何度もAWSのCloudWatchを仕事&プライベートで触っていますが、CloudWatchって「なんかお金かかるなあ...」と思うことが多かったので、CloudWatchの料金について調べることにしました。

なお、自分の認識が誤っている可能性もあるので、必ず詳細は自分で確認をお願いします。

参考

扱うサービス

CloudWatchにはいろいろサービスがありますが、今回は以下のサービスのみ対象にします

  • メトリクス
  • ダッシュボード
  • アラーム
  • ログ
  • イベント

前提

  • 金額は全て月額です。
  • 1ドル140円として計算してます。(2022/11/20現在のレート)

メトリクス

料金体系はこんな感じ

  • 基本メトリクス(初めから用意されてるもの)
    • 基本モニタリング(5分間隔)は無料
    • 詳細モニタリング(1分間隔)は10個まで無料
  • カスタムメトリクス(自分で作成するもの)
    • 10,000メトリクスまで:0.3ドル/個
    • 次の240,000メトリクス:0.1ドル/個
    • 次の750,000メトリクス:0.05ドル/個
    • 1,000,000を超えるメトリクス:0.02ドル/個
  • 詳細モニタリングも11個目からは上記の料金が適用されるっぽい?

確かに、こんなものではないかな...という感じです。
仮に20個モニタリングして、840円くらいです。(為替次第でもっと安くなる)
ただし、決して手放しに安いわけではないので、カスタムメトリックの作りすぎは注意が必要ですね。

また「Amazon CloudWatchの料金」の「料金の例:例2-カスタムメトリック」にあるように、EC2のある項目(CPU使用率など)をカスタムメトリック化して送信...などをやろうとすると、API使用料の分も料金が追加で必要なので、そこは注意です。

ちなみに、メトリクスフィルタ自体には料金はかかりませんが、メトリクスフィルタの作成時には最終的にカスタムメトリクスを作成するので、結果的にカスタムメトリクス1個分の料金がかかります。

ダッシュボード

  • 3個まで無料(最大50メトリクスまで表示)
  • 4個目以上からは、3ドル/個

これもそんな感じかな...という感じ。
今まで、無料枠で十分間に合っていたので、かもしれません。
1アカウントでたくさんEC2インスタンスを立てたり複数アプリを動かしていると、そうでもないのかも。

ただ単価はちょっと高めですね。(その分便利だけど)

アラーム

  • 標準解像度アラーム10個まで無料
    • 11個目以上は0.1ドル/個
  • 高解像度アラームは0.3ドル/個
  • 複合アラームは0.5ドル/個

これもそんな感じかな..と。(そればっか)
標準解像度のアラームならばコストが安めなので、そこまで負担に感じることはなかったです。

これもカスタムメトリクス同様、作りすぎに注意する感じです。(事前に精査しておくなど)

ログ

  • 5GBまで無料
  • 収集:0.76ドル/GB
  • 保存(アーカイブ):0.033ドル/GB
  • 分析(Logs Insightsクエリ発行):0.0076ドル/GB(スキャンデータ量)

「CloudWatchの料金高くね?」と感じる場合、だいだいこれのせいです。

「収集」の単価が他の単価に比べてちょっとお高めな感じがあります。

また「収集」とありますが、実際にはCloudWatch Logs上で閲覧できるログは全て課金対象なので、例えば「毎月10GBのログを収集する」場合、

  • 初月:10GB - 5GB(無料枠) = 5GB * 0.76 ≒ 532円
  • 2か月目:10GB(初月分) + 10GB(当月分) - 5GB(無料枠) = 15GB * 0.76 ≒ 1,596円
  • 3か月目:10GB(初月分) + 10GB(2か月目分) + 10GB(当月分) - 5GB(無料枠) = 25GB * 0.76 ≒ 2,660円

と、どんどん増えていきます。

※2022/11/21追記:
上記ですが、AWSサポートから「『収集』は新規に収集(=ログに書き出し)した場合のみが対象で、一度書き出したログがずっと残っていても『収集』枠で課金されることはない」との情報を頂いたため、取り消させて頂きます。失礼いたしました。
(もちろん、「保存(アーカイブ)」枠での課金はあります)

また、Logs Insightsクエリ発行もスキャン対象データが課金対象なので、累積データが増えていけば、当然課金額も増えていってしまいます。

対策ですが、とにかく不要なデータは削除するなりアーカイブするなりする事だと思います。
(アーカイブしても課金はされますが、単価はだいぶ安いです)

また「保持」のデフォルトが「失効しない(=ずっと残っている)」状態なので、必ず保持期間を設定しておくのをお勧めします。(CloudFormationならProperties.RetentionInDaysで設定できます)

それ以外には、CloudWatch Logsに書き出す内容を見直すのも大事かなと思います。

イベント

  • カスタムイベント以外は無料
  • カスタムイベントはイベント100万件当たり1ドル
  • クロスアカウントイベントもイベント100万件当たり1ドル

これは、そんな感じかなと思います。(個人的には良心的値段だと思う)
実際、今までCloudWatchイベントで負担に感じたことはあまりなかったです。

なお、これもカスタムメトリクスやアラーム同様、事前に内容を精査する...が大事だと思います。

まとめ(=コストを抑えるには?)

  • CloudWatchに設定する項目は定期的に精査、見直しする。(不要な項目は削除する)
  • 特にCloudWatch Logsはこまめに削除・アーカイブする。(不要にずっと残さない)
    • 面倒でも保持期間を設定する

だと思います。

では、今回はこの辺で。

【MySQL】インデックスについて

はじめに

今まで業務で幾度となくデータベースを触ってきましたが、インデックスについては見よう見まねとか、経験則でなんとなくやってきた感が強かったです。

そこで、最近インデックスに触れる機会があったので、これを機にインデックスについてまとめようと思いました

「インデックス」って何?

直訳すれば「(本などの)索引」(データベースでの場合)
ちょうど本の索引(=目次)のように、「探しているデータを素早く見つけるための指標」と考えると分かりやすいかもしれないです。

例えば基本(応用)情報技術者試験の参考書の場合、

  • 第1章 基礎理論
  • 第2章 アルゴリズムとプログラミング
  • 第3章 ハードウェアとコンピュータ構成要素

みたいな索引が付けられていて、実際に自分が勉強したい項目のページを素早く探し出せますが、これと同じことを行うのがインデックスです。

また、自分は「DynamoDBにおける、パーティションパーティションキーみたいなもの」という認識を持っています。(ある程度何のデータかを絞り込むための情報)

B木とB+木

MySQLの検索には、「B+木(=baranced plus tree)」というアルゴリズムが採用されています。

これは「B木(=baranced tree)」の改良版で、下記のような木構造です。(実データは少し簡素化しています)

ちなみに、検索の経路はこんな感じです。

例えば、「19」を検索する場合、こんな感じです。

  • 最上段では、19は11以上20以下なので、真ん中の経路を進む
  • 2段目では、19は17より大きいので、右端の経路を進む
  • 最下段で、18から20を順に探査し、19が見つかる

そして、B+木(B木もだけど)の何が重要かというと、「しきい値(≒インデックス)の値の設定が重要」ということです。

例えば同じデータ数でも、下図の左と右では、どう考えても左の方が検索効率がいいことが分かります。
こういう、検索効率がよくなるインデックスというのを考慮する必要があります。

カーディナリティ

カーディナリティとは?

インデックスを作成する上で欠かせないのが「カーディナリティ」です。
カーディナリティは「同一フィールドに含まれる異なる値の数」のことで、よく「多重度」などど表現されます。

もっと端的にいえば、distinctGROUP BYをした際に取得できる値の個数です。

たとえば、あるテーブルに10レコードがあり、そのnameフィールドが下記だったとします。

name
Kagekiyo
Kagekiyo
Kagekiyo
Kagekiyo
Yoshitsune
Yoshitsune
Yoshitsune
Benkei
Benkei
Yoritomo

この場合、nameフィールドのカーディナリティは4(Kagekiyo, Yoshitsune, Benkei, Yoritomo)です。

そして、インデックスを貼る際、カーディナリティが高い(=数値が大きい)フィールドから順に貼っていくというのが基本になります。(もちろん「基本」なだけで、該当しないケースもあります)

データの割合

もう一つ注意しなければらならないのが、データの割合です。

例えば、先程のnameフィールドについて、全100レコードあり、カーディナリティは同じく4だったとします。

しかし、例えば下図の左のグラフのように、ほぼ均等に分散されているのと、右グラフのように1データに極端に集中しているのとでは、下記理由より明らかに前者の方が早く検索できます。

  • 後者は、ほぼ全文検索しないといけない
  • データの割合的にも、後者では検索されるのは極端にデータが多い「Kagekiyo」である可能性が高い

したがって、「カーディナリティが高い」だけでなく、均等にデータが分散されているフィールドにインデックスを貼る のが重要です。

ただ実際はそうそううまくは均等にならないでしょうし、予測も難しいケースもあるでしょうから、「極端に偏りがないフィールドに貼る」でもOKだと思います。

カーディナリティが高ければ、それだけデータが分散される可能性が高いため、「カーディナリティが高いフィールドからインデックスを貼る」のが一般的、というわけです。

インデックスの貼り方&確認方法

実際にSQLインデックスを貼る方法ですが、下記の通りです

# インデックスの作成
ALTER TABLE テーブル名 ADD INDEX インデックス名(カラム名);  
# 例  
ALTER TABLE test_table ADD INDEX idx1(name);

# インデックスの確認  
SHOW INDEX FROM テーブル名;
# 例
SHOW INDEX FROM test_table;

# クエリのインデックス効果を確認する(詳細は次回に説明します)
EXPLAIN 実際のクエリ
# 例
EXPLAIN SELECT * FROM test_table where name = 'hoge';
  
# インデックスの削除
ALTER TABLE テーブル名 DROP INDEX インデックス名;
# 例  
ALTER TABLE test_table DROP INDEX idx1;

次回は

次回は、インデックスについて「効くケース・効かないケース」などについて説明したいと思います。

それでは、今回はこの辺で。

【JavaScript/MySQL】Falsyな値の扱い

はじめに

今回は、プログラミング言語のいわゆる「Falsyな値」について、JavaScriptMySQLにおける扱い&注意点についてです。

前提:「Falsyな値」って?

Falsyな値とは、下記のような値を指します。

  • 空文字
  • 0
  • false
  • null
  • undefined

表現が難しいのですが「空の値と判定される」とか「falseと判定される」ような値、でしょうか

JavaScript

よく使う使われ方

JavaScriptでこれらの値を使うケースとして「何か値が入っているか」を判定する処理があります。

具体的には、下記のような処理です。

// 何か値を取得する処理
const value = getValue();
  
if (value) {
  // 何か値が入っているとき
  console.log(`value is ${value}`);
} else {
  // 何も値が入っていないとき
  console.log('value is empty');
}
  

// 値が入っている場合もbooleanで判定したい場合はこんな感じ
if (!!value) {
  // 何か値が入っているとき
  console.log(`value is ${value}`);
} else {
  // 何も値が入っていないとき
  console.log('value is empty');
}

nullとundefinedだけ判定したい

ただ、上記の方法だと仮に空文字、0、falseといった値が入っていても「なにも値が入っていない」と判定されてしまい、ちょっと困ったことになります。

実際の入力フォームでも、0およびfalseあたりは入力値として設定することも多いので(例えば下記)、「なにも値が入っていない」と判定されるのは問題になる場合があります。

  • 飛行機や新幹線での「子供の人数」(=ビジネス目的ではたいてい0人)
  • アンケートなどでの「メルマガ受信を希望する」(=興味ない相手からは受け取りたくない)

こういう時にJavascriptでは「??(=Nullish Coalescing)」を使って判定することができます。(具体的に使用方法は下記参照)

詳細を知りたい場合、ECMAScriptの下記GitHubが参考になります。

GitHub - tc39/proposal-nullish-coalescing: Nullish coalescing proposal x ?? y

// ??は、左側がnullでもundefinedでもない場合は
// 左側の値をそのまま返す。
// 左側の値がnullまたはundefinedの場合のみ右側の値を返す。
const x = 0
console.log(x ?? -1);  // 0
  
const y = null
console.log(y ?? -1);  // -1
  
// ??を使い、こう書き換えることができる。
const z = getValue();

if ((z ?? null) !== null) {
  // 何か値が入っているとき
  console.log(`z is ${value}`);
} else {
  // 何も値が入っていないとき
  console.log('z is empty');
}

値の判定は===(型も比較)で

Falsyな値の比較ですが、これはタイトル通りで、必ず===(型も比較する)で比較してください。

==(値のみの比較)だと「どっちもFalsyな値」みたいな判定をされ、正しく判定できないからです。

実際のソースが下の画像となります。(CodeSandBoxで実行)

Falsyな値同士の比較は==だと、値が違ってもtrueになってしまうのが分かります。(===だとちゃんとfalseになる)
また、null/undefinedとの比較は==でもちゃんとfalseになるようです。

またFalsyな値同士の比較、及びundefinedとの比較の場合、==だと「===を使ってね」みたいな警告も表示されてますね。

MySQL

テーブル定義

MySQLの説明では、下記定義のテーブルを元に説明します。

フィールド名 説明 備考
id INT 主キー これは一意の値を入れるだけ
name VARCHAR2(45)
flag BOOLEAN
num INT

0(=INT型)とfalse(=BOOLEAN型)

続いてMySQLですが、MySQLでは数値型(INT)と論理型(BOOLEAN)は、ともに数値として扱われます。
なので数値型フィールドにfalseを指定したり、あるいは論理型フィールドに0を指定しても、特に型エラーなどは発生しません。

下記の結果が分かりやすいと思います。(id: 1のデータは関係ないのでスルーしてください)

# flagに0(=数値)、numにfalse(=論理値)を入れる。
# 特にエラーもなく登録できる
mysql> INSERT INTO test_table(id, name, flag, num) values(2, 0, 0, false);
Query OK, 1 row affected (0.01 sec)
  
# 結果を取得すると、どちらも0(=数値になっている)
mysql> SELECT * FROM test.test_table;
+----+--------+------+------+
| id | name   | flag | num  |
+----+--------+------+------+
|  1 | yamada |    0 |  100 |
|  2 | 0      |    0 |    0 |
+----+--------+------+------+
2 rows in set (0.00 sec)

MySQLでは、BOOLEAN型は内部的にはTINYINTとして扱われるようなので、その影響だと思われます。
実際、型定義を見てもflagはTINYINTとなっています。

# flagのTypeがTinyintになっている
mysql> SHOW FULL COLUMNS FROM test_table;
+-------+-------------+--------------------+------+-----+
| Field | Type        | Collation          | Null | Key |
+-------+-------------+--------------------+------+-----+
| id    | int         | NULL               | NO   | PRI | 
| name  | varchar(45) | utf8mb4_0900_ai_ci | YES  |     | 
| flag  | tinyint     | NULL               | YES  |     | 
| num   | int         | NULL               | YES  |     |
+-------+-------------+--------------------+------+-----+
4 rows in set (0.00 sec)

また、公式サイトでも「TRUE および FALSE 定数はそれぞれ 1 と 0 として評価されます」という記載があります。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 9.1.5 boolean リテラル

空文字は?

最後に空文字ですが、MySQL 5.7以上では、空文字をINT及びBOOLEANフィールドに登録しようとするとエラーになります。

ちなみに、文字列型フィールドに0やfalseを指定すると、「数値の文字列」として登録されるようです。

# BOOLEAN型に空文字を入れると、エラーになる
mysql> INSERT INTO test_table(id, name, flag, num) values(2, 0, '', false);
ERROR 1366 (HY000): Incorrect integer value: '' for column 'flag' at row 1
  
# INT型も同様にエラーになる
mysql> INSERT INTO test_table(id, name, flag, num) values(3, false, 0, '');
ERROR 1366 (HY000): Incorrect integer value: '' for column 'num' at row 1

が、MySQL5.6以下だと、0として普通に登録されます。(下画像参照。なおMySQL5.6の環境が手元にないので、DBFiddle で実行)

これは結構バグの原因になったりするので、気を付けた方が良いと思います。(そういう意味で、5.7からはエラーを吐くように変更されたのかも。)

まとめ

以上、JavaScriptMySQLでのFalysな値の扱いでした。

MySQLはともかく、JavaScriptはうっかり意図しない挙動になりかねないような仕様だと思うので、気を付けないといけませんね。

ただこれに限らず、JavaScriptはそういうのが結構ある言語とは思いますが...

では、今回はこの辺で。

【WSL】WSL2にmysqlをインストールする

今回の内容

今回は、Windows Subsystem for Linux version2(=以下WSL2)にmysqlをインストールし、動かすところまでを説明します。

前提

  • WSL2のインストールは済んでいる前提です。(ここでは記載しません)
  • 外部ホストからmysqlに接続する方法は説明しません。(localhostでの動作確認のみ)

インストール手順

インストール手順ですが、実はMicrosoft Learnにそのままズバリ全部書いてあります。
なので基本的にはここに書いてあるやりかたをそのまま行うだけでOKです。

# パッケージ更新&mysqlインストール
$ sudo apt update
$ sudo apt install mysql-server
  
# バージョン確認(正しくインストールされたかどうか)
$ mysql --version
  
# mysqlを起動する
$ sudo /etc/init.d/mysql start  
  
# セキュリティ スクリプト プロンプトの開始(=rootパスワードやセキュリティ系に関する設定を行うスクリプト)
$ sudo mysql_secure_installation  
  
# もし下記メッセージが出たら、Ubuntuのrootパスワードを入力する。
# mysqlのrootとは無関係です
Enter password for user root:
  
# 最初にrootのパスワードを設定する。
# 下記で、mysqlのrootユーザーのパスワードを設定&再入力する。
The existing password for the user account root has expired. Please set a new password.
New password: 
Re-enter new password: 
  
# その後、下記の質問を聞かれる。(詳細は下表参照)
# すべてyesかどうかで答える(yまたはY以外は全てno扱い)
VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?
  
Remove anonymous users? (Press y|Y for Yes, any other key for No) :
  
Disallow root login remotely? (Press y|Y for Yes, any other key for No) :
  
Remove test database and access to it? (Press y|Y for Yes, any other key for No) :
  
Reload privilege tables now? (Press y|Y for Yes, any other key for No) :
  
# 上記すべて設定&設定の再読み込みをしたら、下記コマンドでmysqlを起動できる(はず)
$ sudo mysql
質問 内容 備考
VALIDATE PASSWORD COMPONENT can be used to...(以下略) VALIDATE PASSWORD COMPONENTを使って、パスワードポリシーを厳格に決めるかどうか。 ・決める場合、LOW/MEDIUM/STRONGの3つからパスワードレベルを設定できる。
・当然レベルが高いほどセキュアだが、その分パスワードに求められる条件は厳しくなる
・これを設定した場合、最初に決めたmysqlのrootパスワードの強度の確認、及びパスワードを変更するかどうかを決められる。(変えなくてもいい)
・パスワードレベルは後で変更できる
Remove anonymous users 匿名ユーザーを削除するかどうか。 セキュリティ的に、削除した方が良いと思う
Disallow root login remotely 外部からのrootユーザーのログインをNGにするかどうか。 NGにしたほうが、セキュリティが高まる
Remove test database and access to it テスト用のデータベースを削除するかどうか。
Reload privilege tables now 特権テーブルの内容を即座に再読み込みするかどうか。 設定を即座に反映させるために、再読み込みするのをお勧め

パスワードでログインするようにする

上記でとりあえずmysqlsudo mysqlで実行できるのですが、この状態だとまだプロンプトで設定したパスワードでは入れません。(mysql -u root -pコマンドでは入れない)

初期状態では認証がauth_socket(=WSLの認証をそのまま使う)設定なのが原因です。

これを修正して、プロンプトで設定したパスワードで入れるようにします。(MySQL WorkBenchなどのクライアントソフトを使用する際に困るので)

やり方は下記の通りです。

# mysqlにログインする
$ sudo mysql
  
# mysqlにログインしたら、下記クエリを入力する。(xxxxにはmysqlのrootのパスワードを入力)
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'xxxx';
  
Query OK, 1 row affected (0.04 sec)
Rows matched: 1  Changed: 1  Warnings: 0
  
# 一度mysqlを抜ける
mysql> exit
  
# 今度は下記コマンドで、rootのパスワードでmysqlにログインできるはず
$ mysql -u root -p
Enter password:
  

クライアントソフト(MySQL WorkBench)をインストールする

mysqlのインストールは完了しましたが、DB操作を便利にするために、クライアントソフトをインストールしてみます。
今回はMySQL WorkBenchをインストールします。

ダウンロードは下記サイトで「Micorsoft Windows」を選択すると現れる「Goto Download Page」のリンク先から行えます。
なお*.msiファイルは2つありますが、自分は「web」がつかない方を選択しました。(「web」の方はインストール中に必要なモジュールが不足している、と出て不安だったので)

また*.msiファイル選択後にOracleアカウントへのログインまたはサインアップを選択する画面が表示されますが、下の方にある「No thanks, just start my download」を選択すればダウンロードが始まります。

MySQL :: Download MySQL Workbench


インストーラでは、下記操作を実施します。

  • インストール方法では「Custom」を選択
  • インストールするツールは「MySQL Workbench」のみを選択。
    • mysql自体はWSL2に入れたので、MySQL Workbench以外は一切インストール不要
  • あとは「Install」ボタンでインストールを実行

その後MySQLを起動したら、Connectionで下記の設定を行い「Test Connection」をクリックし、「Successfully made MySQL Connection」と表示されればOKです。

項目 設定値 備考
Connection Name 任意の一意の名前
Connection Method Standard(TCP/IP)
Hostname localhost
Port 3306 mysqlのデフォルトポート
Username root
Password mysqlのrootのパスワード Store in Vault...ボタンをクリックする
Default Schema デフォルトで表示するデータベース名 未設定でも可(後で選択できる)

お疲れさまでした

ここまで完了したら、とりあえず一通りはOKです。
あとはずっとrootで入るのが気になる場合は、専用のユーザー&パスワードを設定し、GRANT ALL PRIVILEGES...で全特権を付与してあげればOKだと思います。

参考:パスワードレベルを後で変更する方法

「インストール手順」で設定したパスワードレベルですが、mysqlインストール後に変更することもできます。

まずmysqlにログインした後、show variables like 'validate_password%';というクエリを実行します。(root権限でログインした方が良いかも) すると下記のような結果が返ります。

その後、変更したい項目に対して、set global <変更したい項目名>=<変更後の値>を実行すればOKです。

mysql> show variables like 'validate_password%';
+--------------------------------------+--------+
| Variable_name                        | Value  |
+--------------------------------------+--------+
| validate_password.check_user_name    | ON     |
| validate_password.dictionary_file    |        |
| validate_password.length             | 8      |
| validate_password.mixed_case_count   | 1      |
| validate_password.number_count       | 1      |
| validate_password.policy             | MEDIUM |
| validate_password.special_char_count | 1      |
+--------------------------------------+--------+
7 rows in set (0.00 sec)
  
# 例:パスワードの長さを最低4文字にしたい場合
mysql> set global validate_password.length=4;
  
# パスワードポリシーのレベルをLOWに変更したい場合
mysql> set global validate_password.policy=LOW;

参考2:A5:SQL Mk-2について

今回クライアントソフトにMySQL WorkBenchを入れましたが、もちろんA5:SQL Mk-2でも全く問題ないです。

私も初めはA5:SQL Mk-2にするつもりだったんですが、なぜか私の環境では何をやってもA5:SQL Mk-2だとmysqlとの接続がエラーになり、それこそmysqlの設定やiptablesファイアウォールやら何やらの各種設定を変えてみたんですが、結局うまくいきませんでした...

ただブログを見る限り、A5:SQL Mk-2でも問題なく動作した例も多数あるので、たまたま私の環境でうまくいかなかっただけで、A5:SQL Mk-2でも全く問題ないと思います。

今回は以上です。

【速報?】令和4年度 応用情報技術者試験(秋期) 午後 問3(プログラミング問題)を解いてみた

今回の内容

昨日(2022/10/09)に実施された、令和4年度 応用情報技術者試験(秋期) 午後 問3(プログラミング問題)を解いてみました。

少し前までは、応用情報午後のプログラミング問題を解くのが私の中では恒例行事だったんですが、最近なかなかできてなかった&今回3連休だったので、久々にチャレンジしてみました。

なお問題は、下記URLからダウンロードできます。
https://www.jitec.ipa.go.jp/1_04hanni_sukiru/mondai_kaitou_2022r04.html#04aki

注意

  • あくまでも、私の回答です。
  • この答えが100%合っているという保証はどこにもないです。(本当に自分の回答レベル)

(自分の)回答

設問1

  • (1):3 ((5, 1), (3, 4), (4, 4)は通らない)
  • (2):2 ((1, 1)と(2, 1))

設問2

  • イ:paths[sol_num][k]
  • ウ:stack_top - 1
  • エ:maze[x][y]

設問3

  • オ:sol_num

設問4

  • (1):(5, 3)
  • (2):
    • キ:22
    • ク:3

設問4について

1つ目の解が出るまでに行われる移動の8回目以降は以下の通り。(7回目までは問題文の通り)

  • (1, 3)
  • (2, 3)
  • (3, 3)
  • (3, 4)
  • (4, 4)
  • (5, 4)
  • (5, 5) ※1つ目の解
    • この後、(5, 4)での「2. x座標を1増やす」の(6, 4)は外壁なのでvisit()は実施されない
    • 「3. y座標を1減らす」でvisit(5, 3)が実行される

座標(5, 3)からは、下記の順に移動が実施される

  • (5, 2)
  • (5, 1)
  • (5, 2)
  • (4, 2) 1回
  • (3, 2)
  • (3, 1)
  • (2, 1)
  • (3, 1)
  • (3, 2)
  • (4, 2) 2回
  • (5, 2)
  • (5, 3)
  • (5, 4)
  • (4, 4)
  • (3, 4)
  • (3, 3)
  • (3, 2)
  • (4, 2) 3回
  • (5, 2)
  • (5, 3)
  • (5, 4)
  • (5, 5) ※2つ目の解

感想

再帰を使った迷路探索ですね。
「具体的に、どういうことを意図している(=やりたい)コードなのか」が理解&イメージできれば割と簡単だけど、そこまでたどり着けるかどうかがポイントかな、と思いました。(特に進もうとするマスがVISITEDだった場合に、「どうやってpathsにこの経路を追加するのか」とか効率化を考えたりするとハマっちゃうかもしれません)

ましてや結構試験時間もカツカツで焦りもある中、ですからねえ。

もし自分が実際に試験を受けていたら、時間内に解けなかったんじゃないか?と思います。

てか、自分が実際に受験したとき(2016年春期。熊本地震の直後、かつたまたま午後問2(経営戦略)の問題が「大地震発生時のBCP計画について」となっていて話題になった回)も、プログラミング問題始めた時、残り15分強しかなかったような...(確かライフゲームの問題だったかな?あれは解いてて良問だったなあ、と感じた記憶があります。)

それでは、今回はおまけということで、こんな感じで

【VS Code】Remote SSHでSSH接続する

はじめに

現在、仕事でSSHを使用する機会がかなり増えてます。(今まであまりなかった)

それに伴い「SSHで便利なツールないかなー」「できればVS Code上で扱える拡張機能がないかなー」と思っていたら、やはりありました。(てかVS Code拡張機能、マジで何でもありますね)

という訳で、今回はSSH接続を行うVS Code拡張機能「Remote SSH」の紹介です。

Remote SSHの紹介とインストール

Remote SSHは、先述の通りVSCodeSSH接続を行うための拡張機能です。
鍵認証の使用や、また多段SSH接続(=踏み台ホスト経由で目的のホストに接続)にも対応しています。

そしてインストールですが、以下2つの方法があります。
自分の好きな方法でインストールしてください。(どちらを選んでもRemote SSHに差異は全くありません)

  • 「Remote SSH」をインストール
    • これはRemote SSH単体でインストールされる
  • 「Remote Development」をインストール
    • Remote Developmentは、下記3つをまとめてインストールする拡張機能パッケージ
      • Remote SSH
      • Remote Containers
      • Remote WSL

Host設定

次に接続するホストの設定を行います。

インストールを行うと左のタブに「Remote Explorer」アイコン(赤〇)が追加されるのでそれをクリック、しRemote Explorerのリスト(青〇)から「SSHターゲット」を選択します。
そしてリストの下の歯車アイコン(緑〇)をクリックすると「更新するSSH構成ファイルを選択する」メニューが表示されるので、設定を保存するSSHファイルを選択します。

  • ここは環境(OSなど)によって、表示される内容が違います。
  • 一部ファイル(Macのetc/hostsとか)を編集する場合は管理者権限が必要な場合があります。


今回は一番上のユーザー個別の設定ファイルを選択しました。(Macならhome/(ユーザー名)/.ssh/configかな)

該当の設定ファイルを編集しますが、とりあえずSSH接続するだけなら、下記の設定を抑えておけばOKです。

Host hogehoge
    HostName hogehoge.com
    User hoge
    PasswordAuthentication no
    IdentityFile ~/.ssh/id_rsa    
    IdentitiesOnly yes
    Port 22
項目 意味 初期値 備考
Host 任意の一意の名前(識別名)
HostName 接続先ホストのドメインまたはIPアドレス
User 接続する際のユーザー名
PasswordAuthentication 接続時にパスワードによる認証を行うかどうか yes 鍵認証のみで認証する場合はnoにする
IdentityFile 鍵認証で使用する秘密鍵ファイルのパス ~/.ssh/id_rsa または ~/.ssh/id_dsa 鍵認証を使用する場合に指定する
IdentitiesOnly IdentityFileの秘密鍵のみで認証を行うかどうか no yesの場合、ssh-agentに他の鍵情報が登録されていても使用しない
Port SSH接続に使用するポート番号 22 22以外を使用する場合のみ指定する(なので、正確には上記設定にPortは不要)

なお、設定項目の詳しい情報は下記URLにあります。
https://linux.die.net/man/5/ssh_config

接続する&切断する

上記Host設定を行うと、「SSHターゲット」に先程設定を行った「Host」の名前が登録されていると思います。

そのホストを右クリックすると、どのウィンドウで接続を行うか選択できる(新しくウィンドウを開く/今のウィンドウのまま)ので、好きな方を選択します。

認証が通り接続が無事完了すると、VS Codeの左下に「Host」の名前が表示されます。

また接続先ホストのファイル/フォルダをエクスプローラで表示・編集したり、接続先ホストのターミナルを操作することもできます。

切断する際は、左下の「Hostの名前」をクリックすると表示されるメニューから「リモート接続を終了する」を選択すればOKです。

踏み台ホスト経由で接続する(=多段接続)

ここまではシンプルに

  • ローカルPC → 目的のホスト

という前提で書きましたが、実際の開発環境ではセキュリティなどの観点から、

  • ローカルPC → 踏み台ホスト → 目的のホスト

のように、踏み台ホストを経由した接続を行うケースもあると思います。(もちろん、踏み台ホストが複数台あるケースも存在する)

その際は、設定ファイルに下記のように設定します

# ローカルPC → 踏み台ホスト1(bastion1) → 踏み台ホスト2(bastion2) → 目的のホスト(target) という場合
# 秘密鍵を使用するケースは後で説明します
# Userは適宜置き換えてください
Host bastion1
    HostName bastion1.com
    User hoge
    PasswordAuthentication yes

Host bastion2
    HostName bastion2.com
    User hoge
    PasswordAuthentication yes
    ProxyCommand ssh -W %h:%p bastion1

Host target
    HostName target.com
    User hoge
    PasswordAuthentication yes
    ProxyCommand ssh -W %h:%p bastion2

ポイントはProxyCommadで、これに続けて下記コマンドを設定します。

ssh -W %h:%p (踏み台Host名)

これを設定すると「踏み台Host名」のホスト名に接続した際に、自動でこのコマンドを実行してHostのホストに接続を行ってくれます。(例えばbastion1に接続した際に、自動でbastion2への接続を実施してくれる)

また「%h:%p」はそれぞれホスト/ポートで、コマンド実行時には接続先ホストのホスト/ポートが指定されます。

秘密鍵情報を踏み台ホストでも使う(ForwardAgent)

上記「踏み台ホスト経由で接続する(=多段接続) 」はパスワード認証でしたが、これだと踏み台を含めた各ホストに接続する際に、いちいちパスワードを聞かれ、ちょっと面倒です。
しかしForwardAgent(※)を使用すればそういった手間は無くなります。

ssh-agentに登録した秘密鍵情報を接続先ホストでも使用できる仕組み。ざっくり言うとローカルの秘密鍵情報を接続先ホストでも使用可能になる
※ただしセキュリティ的な問題点もあるので、その点はご注意を

もちろんRemote SSHでもForwardAgent(※)を使用して多段接続を行うことができます。
Remote SSHでForwardAgentを使用する方法ですが、非常にシンプルです。

Host bastion1
    HostName bastion1.com
    User hoge
    IdentityFile ~/.ssh/id_rsa
    ForwardAgent yes # これを追加

上記の通り、秘密鍵があるホスト(=ローカルなど)からの接続設定にForwardAgent yesを追加するだけでOKです。
これだけで、接続先のホストで接続元の秘密鍵情報を使用することができます。

また、設定ファイルの全ホストへの接続にForwardAgentを使用する場合、設定ファイルの先頭にForwardAgent yesを追加すれば、どのホストへの接続もForwardAgentを使用してくれます。

# 先頭にForwardAgent yesを定義すれば、全ホストに適用される
ForwardAgent yes
  
Host host1
    HostName host1.com
    User hoge
    IdentityFile ~/.ssh/id_rsa
    
Host host2
    HostName host2.com
    User hoge
    IdentityFile ~/.ssh/id_rsa

Tips:「プロセスが、存在しないパイプに書き込もうとしました」というエラーが出る場合

上記を設定してSSH接続を行っても、「プロセスが、存在しないパイプに書き込もうとしました」というエラーが発生して接続ができない場合があります。
その際によくある原因&対象方法を記載します。

  • 下記に記載したエラーログはたいてい「プロセスが、存在しないパイプに書き込もうとしました」の直前の数行に表示されるので、まずはエラーログを確認してください。
  • 下記ではエラー解消しないケースももちろんあるので、その場合は各自調べてください。(下記はあくまで原因の一例です)
  • 下記以外のエラーももちろんあります。

「Bad owner or permissions on .../.ssh/config」というメッセージが表示される
この場合、

  • Host設定ファイルへの読み取り権限がない
  • Host設定ファイルを読みにいってない(例えばユーザーごとの設定ファイルに設定したのに、OS標準の設定ファイルを読みにいってる、等)

が考えられます。

前者はchmodコマンドなどで権限を付与する事、後者は下記の手順で正しいファイルを読みに行くように設定することで回避できるケースがあります。

  1. 歯車アイコンをクリックし「更新するSSH構成ファイルを選択する」メニューを表示する
  2. 「設定(カスタム設定ファイルを指定する)」を選択する
  3. 設定項目の「Remote SSH: Config File(カスタム SSH 構成ファイルへの絶対ファイル パス)」に、該当の設定ファイルの絶対パスを入力する

「no such identity: (IdentityFileに設定した秘密鍵ファイルのパス) No such file or directory」というメッセージが表示される
この場合、

  • IdentityFileに設定した秘密鍵ファイルへの読み取り権限がない
  • IdentityFileに設定した秘密鍵ファイルがない

が考えられます。

前者は先程と同様、chmodコマンドなどで権限を付与してみてください。
後者はIdentityFileに設定した秘密鍵ファイルが存在することを確認してください。

なおWindowsのWSL(WSL2含む)環境で動作させている場合、Linux形式のパス(/home/(ユーザー名)/...)を指定しているとダメというケースがあるので要注意です。(C:\Users\(ユーザー名)\...など、Windows形式のパスを指定しないといけない)

「this access is currently unavailable ssh」というメッセージが表示される
この場合、そもそも接続先ホストがSSHに対応していないケースが考えられます。
接続先ホストがSSHに対応しているか、確認してください。(レンタルサーバーならSSHが有効になっているか、とか)

その他、Host設定ファイルの設定内容が正しいか、なども要確認です。(実はポート番号が標準の22ではない、等)

まとめ

以上がRemote SSHSSH接続する方法になります。

SSH接続ってなんかすごいハードルが高いと思っていたんですが、めちゃくちゃ簡単に出来てしまって驚きです。
しかも接続先でもVS Codeがそのまま使えて、ファイル編集などもできてしまうので、自分みたいにどうしてもviやvimが苦手...という人にはすごくお勧めです。

とはいえ、SSHとかLinuxのようなコマンドベースOSを触るなら、やはりvimあたりは扱えるようにしておかないといけないんでしょうね...

それでは、今回はこの辺で。

【私事】フリーランスをやめることになりました(2022/8/30追記)

はじめに

私事になりますが、タイトルの通りこの8月(2022年8月)で、一旦フリーランスをやめることになりました。(9月から某企業に正社員として働くことになりました。その辺は実際に働きだしたら、どっかのタイミングで書きます。)

そこで今回は、その経緯やその他諸々を記事にしたいと思います。
(Twitterでも結構リクエストがあったので)

※2022/8/30 「年商と年収の違い」を追記しました。

参考

フリーランスやめるので本当のことを全部書く - ドークツ

なんでやめるの?

一言で言えば、「自分がやりたい業務が、フリーランスだとなかなか携われないから」となります。

具体的には、下記の理由からです。

  • 携われる領域に限界がある
  • 組織の突っ込んだ部分に携われない
携われる領域に限界がある

私は「クラウドのバックエンド部分のアーキテクチャやベースとなる部分の設計」に深く携わりたいと考えていました。(実際、それが得意&好きな分野ですし)

が、そういう分野っていわばそのシステムのコアな部分になることもあり、外部の人が携われる機会がなかなか無かったです。(その部分はすでに決まってて「それに合わせて詳細部分の設計やコーディング・テストなどを...」というケースが多かったです)

もちろん、その点に関してはセルフブランディングや売り込みの仕方など、今考えたら色々反省点もあったりします。

が、やはり自分の力ではどうしようもできない部分もあったりして、いろいろ考えされられました。

組織の突っ込んだ部分に携われない

また、私は単に技術を追求したいというよりも、もっとビジネス・チームビルディング・開発の共通基盤作りなど、組織作りの突っ込んだ部分にも積極的に携わりたいと考えていました。(技術を追求したい気持ちも当然ありますが)

が、これも外部メンバーだとなかなかそういった部分に携われませんでした。

もちろんここは考え方の違いなので、逆に「そんなのどうでもいいから、自分はひたすら技術を追求したい」という人には逆に良かったかもしれません。

が、自分のキャリアを考えた際に、そういった部分にも積極的に携わりたいと感じたので、このままでは問題だなあ...と考えていました。

これが理由じゃないよ

経営が行き詰まった(経済的な理由とか)?

これは100%ないです。

ありがたいことに、まだまだ引き手あまたな状態でしたし、続けようと思えばあと数年は続けられたと思います。

また経営資金がなくなったとか、そういう経営難とかの状態でもありません。

将来が不安だった(安定性とかそういう意味で)

これも理由としてはほとんどないです。

もちろん100%無いなんて事はありませんが、将来の不安が理由で正社員に戻った(=ある程度安定を取った)わけでもないです。

やっぱり年齢の壁?

これは微妙で、たまにSNSとかで聞くような「年齢制限で案件を断られる」ことは、私は一切ありませんでした。(本当は年齢で制限をかけること自体NGですが)

ただ私の考えとして「年齢的に技術がある程度出来るのは当たり前で、加えて+αの能力がないと...」というのがあり、その「+α」を意識しなきゃいけない意味では「年齢」はそれなりに影響したのかもしれません。

これからフリーランスになりたい人へ

逆に、現在「フリーランスなりたい」とか「フリーランスを検討している」人もいると思います。

そんな方に、自分からアドバイスがあるとすれば、こんな感じかなあと思います。

セルフブランディング大事

個人的に、フリーランスはセルフブランディングがめちゃくちゃ重要だと感じます。(もちろん技術力も大事ですが)

フリーランスは自分の希望する業務・報酬等を得るために積極的に自分をアピールしなきゃならないです。(業務内容・報酬にも大きく影響するので)
なので、アピール材料にもつながるセルフブランディングはこまめに行うようにしましょう。

またアピール資料(=ポートフォリオ、その他諸々)も、「(=ただの職歴の羅列ではなく)自分をアピールする材料になっているかどうか」をこまめに確認するとよいと思います。

セルフブランディング次第では、思いもよらなかった好条件・業務内容の案件にアサインされる可能性もあります。

もちろん、だからといってウソを書く(≒経歴詐称)のは絶対ダメです。

人間関係からは解放されない

たまに

  • 会社員は人間関係が煩わしいからフリーランスに...
  • フリーランスは人間関係とかコミュニケーションが苦手でも、技術力さえしっかりしていればよい?

という人がいます。

が、残念ながらフリーランスになったからといって、人間関係から解放されるということはないです。(よほどのことがない限り)

むしろ、

  • 参画したチームでうまくやっていくために、人間関係を構築する
    • 「問題あり」と判断されたら、その時点で契約終了なので...
  • 別の案件に参画したら、また人間関係の構築を一から行う必要がある

ので、その点では下手したらフリーランスの方が面倒くさいかもしれません。

それにプロパー側からしても、例え技術力があっても人間性に問題があるとか、こんな奴と一緒にいたくないと感じるような人物には参画して欲しくない、と考えるのは当然です。(スポット的な短期案件ではあり得るかもしれませんが、中長期の案件ではまずないです)

ただ、そこまで不安にならなくても「社会人として基本的なことがちゃんとできる」レベルであれば、全く問題ないです。(逆を言えば、それすらできない人間が多いのも事実なんですけどね...)

また、そうはいっても人間どうしても合う合わないはあると思いますので、どうしても合わない現場は自ら契約終了を申し出て、次の案件を探すべきだと思います。(こればかりは仕方ないですし、あなたに責任はないです)

デメリットもちゃんと調べる

フリーランスというと、どうしても「手取りが多い」「業務や働き方をある程度自由に選べる」みたいな目先のメリットに目が行きがちになってしまいます。(当然と言えば当然ですが)

が、そういうメリットがある反面、当然フリーランスにはデメリットも存在します。
ドラクエ3ゾーマも言う通り「光あるところ、闇もまたある」のです。

なのでメリットばかりに気をとらわれず、ちゃんとデメリットも調べましょう。
そうしないといざフリーになったとき「こんなはずじゃなかった...」ということになりかねません。

あまり細かくは書きませんが、フリーランスのデメリットとして、例えば下記が挙げられます。

会社員より安定性に欠ける

  • いくら終身雇用が崩壊したとはいえ、やはり会社員より確実に安定性は下がる
  • 何かあった際、真っ先に削られるものの一つが「外注費」(=フリーランスへの報酬含む)
  • 下手したら数か月収入ゼロ...なんてことも十分あり得る

技術以外の活動

  • 営業活動、仕訳、請求書発行など、技術以外の作業である程度時間を取られる
  • 営業活動はエージェントを使う手があるが、それでもある程度時間を取られる。
    • エージェントを使う場合、毎月手数料も発生する。(当たり前だけど)

確定申告

  • これが本当に面倒くさい(と感じる人がかなりいる)
  • 仕訳とか青色申告(=複式簿記)を頑張る必要がある。
    • お金(経費等)の管理はしっかりと
    • てか、マジで仕訳だけはこまめに(1週~2週に1回とか)やった方が良い
  • 税理士に依頼もできるけど、当然それなりにお金が必要
  • 「経費」について勘違いしてる人も多いので補足すると...
    • 「経費」といっても会社員と違い、自分の財布から出すお金
      • 自分のお金が減ることに変わりはない
    • 経費でいろいろ買うのは、節税効果としてはかなり悪い
      • 目安として、使用額の1割くらいが節税額になる
      • 例えば10万節税するためには、約100万使う必要がある。(めちゃくちゃ本末転倒)

ていうか、最近SNSやWebなどでやたら怪しいメリットばかりアピールしてる、あまりにも怪しいフリーランス礼賛記事やアカウントばかりが目につきますので...

こういうやたらメリットばかり挙げてる発言は鵜呑みにせず、ちゃんと自分でも調べましょう。
ちょっと調べれば、フリーランスのメリット/デメリットが色々見えると思います。

もちろん、それを十分踏まえたうえで、

  • それでも自分はフリーランスになりたい
  • 一度しかない人生、チャレンジしてみたい
  • それでも自分にはどうしても会社員は合わない

という人は、フリーランスにとして独立するのは十分ありだと思います。

「年商」と「年収」の違い(2022/8/30追記)

良くフリーランス関連のSNSでの発言や記事で「年商と年収の違いが分からない」とか、明らかに年商と年収の区別がついていない内容があったりしますので、記載します。
確定申告の際の課税額にも関係してきます。

簡潔にいうと、「年商」と「年収」の違いは下表の通りです。

項目 説明 関連する税制度 税制度の説明
年商 売上・報酬額。ざっくり言うと顧客などから口座に振り込まれる金額 消費税 年商が年間1,000万以上で消費税が課税される(※注)
年収 年商から各種経費を差し引いた額 所得税 年収をベースに所得金額や課税される所得金額を算出する

例えば、

  • 契約単価が80万/月(税別)
  • 上記契約で1年間稼働した
  • 年間経費が250万円だった

の場合、

  • 年商:80(万) × 1.1(消費税) × 12(か月) = 1,056(万円)
  • 年収:1,056 - 250 = 806(万円)

となります。(口座には合計1,056万円が振込されているはずです)

たまに怪しいフリーランス礼賛記事やアカウントが「フリーランスなら単価80万(税別)で契約するだけで、1年で年収1,000万!」と謳っていますが、それは「年収」ではなく「年商」1,000万なので、間違えないようにしましょう。

なお、そういう記事やアカウントでよく目にする「年収(実際は年商)1,000万」ですが、(勘のいい方は気づいたかもしれませんが)「年商1.000万(にギリギリ届く)」というのは、実は税金を支払う側の視点で考えると、実は一番おいしくないパターンなのです。

というのも、年商1,000万円以上で消費税の納税義務も発生するので「年商1.000万にギリギリ届く」というのは、ギリギリ消費税も課税されてしまうケースになります。

なので自分も「年商1,000万をギリギリ超えないようにする」か、あるいはいっそのこと「年商1,000万を大幅に超える」という人をよく見ます。

あ、もちろん納税義務はちゃんと果たさないといけないので、虚構申請とかそういうのは絶対ダメですし、年商1,000万以上稼いだ場合は、ちゃんと消費税も払いましょう。

※注 インボイス制度について

...と、ここまで「年商」と「年収」の違いについて書きましたが、2023年10月から導入されるインボイス制度により、どうやら年商1,000万未満でも消費税を支払わなければならない可能性が出てきました。

詳細は各自で調べて頂くとして、とりあえずインボイス制度でフリーランスは以下の選択を迫られそうです。

  1. 課税事業者として登録する(=年商1,000万未満でも消費税の支払い義務あり)
    • 適格請求書を発行できるので、顧客も仕入税額控除が可能
    • 顧客的には問題なし
  2. 免税事業者のままでいる(=年商1,000万未満では消費税の支払い義務なし)
    • 適格請求書を発行できないので、顧客は仕入税額控除が不可能
    • ひょっとして、それを理由に契約できなくなる可能性も出てくる...?

もちろん実際には顧客(やそのビジネス内容)次第なので、一概には何とも言えませんが、インボイス制度については一通り把握しておく必要があるように思います。

ちなみにインボイス制度については、マネーフォワードさんの下記の記事が参考になります。
インボイス制度とは?2023年導入までに消費税免税事業者がとるべき対応をわかりやすく解説 | 会計ソフト マネーフォワード クラウド

まとめ

というわけで、フリーランスやめることになった経緯をまとめました。

あくまでも私事なのですが、フリーになりたい人&フリーになった人にとって何か参考になれば幸いです。

また「〇〇〇にJoinしました!」記事については、実際に入社してある程度したら書こうと思います。

それでは、今回はこの辺で。