OmniAICreator/Qiita-1.07M huggingface dataset:
CodeIQ:変進小数の足し算の解答

@nabetaniさんのCodeIQの問題です。
問題と解説はこちら
->https://nabetani.hatenablog.com/entry/codeiq_q2924
テストケースの答えはこちらにお世話になりました。（解答の出力の最後にあります）
->https://ideone.com/GOIUuC
入力を小数（文字のリストに変換）と整数部分に分け、
小数部分は小さいほうからadd/5で和を計算しその小数部分は再度文字列化し、
整数部分は数字に変換して二数と少数部分からの桁上がりの和を計算し文字列化、
最後に整数部分と小数部分を'.'で結合します。
計算部分より変換部分が大変でした。

問題のデータは数が多いので、ここには載せません。もし実行されるなら、
http://nabetani.sakura.ne.jp/codeiq/q2924/data.txt
からdata.txtをコピーして、str("").の""の間に張り付けて実行してください。

```Prolog
%swi-prolog v 7.4.2,7.6.4
%:-initialization(start).  %ideone
%start. 

calc(K,S1,S2,D1,D,M):-atom_number(S1,X1),atom_number(S2,X2),
     X is X1+X2+D1,divmod(X,K,D,M).

add(_,[],[],0,[]).
add(_,[],L,0,R):-R=L.
add(_,L,[],0,R):-R=L.
add(K,[S1|T1],[S2|T2],D,R):-
     K1 is K-1,add(K1,T1,T2,D1,R1),calc(K,S1,S2,D1,D,M),
     ((M=:=0,R1=[])->R=[];(atom_number(S3,M),R=[S3|R1])).

solve(L1,L2,Y1,Y2,R):-
     add(10,L1,L2,D,R1),Y3 is Y1+Y2+D,number_chars(Y3,L3),
    (R1==[]->R=L3;(append(L3,['.'],L4),append(L4,R1,R))).

start:-str(S),split_string(S,"\t\s\n","\s",L),maplist(split,L,L1),pre(L1),!.

split(S,L):-atomics_to_string(L,",",S).

pre([]).
pre([[A],[B],[C]|T]):-
     concat_atom(L,'+',B),maplist(concat_atom,[[I1,D1],[I2,D2]],['.','.'],L),
     maplist(atom_chars,[D1,D2],[L1,L2]),atom_number(I1,Y1),atom_number(I2,Y2),
     solve(L1,L2,Y1,Y2,R1),atom_chars(R,R1),
     disp(A,R,C),pre(T).
     
disp(A,S,C):-S==C->true;writeln(A).

%41,42,135,623,730,950

str("ここにdata.txtを貼り付け").
```
データを読み込むコードも載せますので、もしideoneで実行される方がいらしたら、
data.txtをideoneの入力に張り付け下のプログラムを実行してください。

```Prolog
%swi-prolog v 7.6.4
%ideone

:-initialization(start).  

calc(K,S1,S2,D1,D,M):-
     atom_number(S1,X1),atom_number(S2,X2),X is X1+X2+D1,divmod(X,K,D,M).

add(_,[],[],0,[]).
add(_,[],L,0,R):-R=L.
add(_,L,[],0,R):-R=L.
add(K,[S1|T1],[S2|T2],D,R):-
     K1 is K-1,add(K1,T1,T2,D1,R1),calc(K,S1,S2,D1,D,M),((M=:=0,R1=[])->R=[];
     (atom_number(S3,M),R=[S3|R1])).

solve(L1,L2,Y1,Y2,R):-
     add(10,L1,L2,D,R1),Y3 is Y1+Y2+D,number_chars(Y3,L3),
    (R1==[]->R=L3;(append(L3,['.'],L4),append(L4,R1,R))).


start:-readline(S),maplist(split,S,L),pre(L),!.

split(S,L):-split_string(S,"\s\t","",L).

pre([]).
pre([[A,B,C]|T]):-
     concat_atom(L,'+',B),maplist(concat_atom,[[I1,D1],[I2,D2]],['.','.'],L),
     maplist(atom_chars,[D1,D2],[L1,L2]),atom_number(I1,Y1),atom_number(I2,Y2),
     solve(L1,L2,Y1,Y2,R1),atom_string(R1,R),disp(A,R,C),pre(T).

disp(A,S,C):-S==C->true;writeln(A).

readline(Line):-
     findall(S,(repeat,read_line_to_string(user_input,S),
                 (S==end_of_file-> !,fail;true  )),Line).

%41,42,135,623,730,950

```
instanceとheapメモリ

```java:StudentTest.java
package package1;

public class StudentTest {
    public static void main(String[] args) {
        Student studentLee =  new Student();
        studentLee.studentName = "Lee";
        studentLee.address = "Tokyo";

        studentLee.showStudentInfo();

        Student studentKIm =  new Student();
        studentLee.studentName = "Kim";
        studentLee.address = "Kyoto";

        studentLee.showStudentInfo();

        System.out.println(studentLee); 
        System.out.println(studentKIm);
    }
}
```

```java
package package1;

public class Student {
    String studentName;
    String address;

    public void showStudentInfo() {
        System.out.println(studentName + " " + address);
    }
}
```

```java:出力結果
Lee Tokyo
Kim Kyoto
package1.Student@5acf9800
package1.Student@4617c264
```
Student studentLee =  new Student();
studentLeeは参照変数としてstack に位置します。
（参照変数：メモリに生成されたインスタンスを指す変数、参照値：生成されたインスタンスのメモリアドレス）
new Student();　newでStudentオブジェクトを生成するとheapに上がります。
これをinstanceといいます。 instanceとは、クラスがメモリに生成された状態をいいます。
studentLeeのheapメモリアドレスはpackage1.Student@5acf9800で、
studentKImのheapメモリアドレスはpackage1.Student@4617c264となります。
 このように、instacneは同じクラスを対象に複数のオブジェクトを生成するとしても、 別個のメモリを持ちます

package1.Student@5acf9800 => {package명}.{class名}@{メモリアドレス値}

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/6d71a470-faf7-11be-3109-a37ee420bac6.png)
【 個人開発 】主夫/婦のための食材の在庫管理アプリ 「ウチの冷蔵庫」を作りました。


## はじめに
こんにちは！@sakamoto_takuyaと申します。
この記事は初学者が初めて個人開発したWebアプリの紹介記事になります。

主夫/婦をターゲットとした、食材の在庫管理ができるアプリケーションになります。

アプリLink：[ウチの冷蔵庫](http://18.178.208.13/)
アプリ概要：[Github](https://github.com/sakanann/My_Fridge)
筆者ツイッター：[Twitter](https://twitter.com/mac_sakabook)

## 開発の経緯
日常生活で、食材の廃棄が出てしまうことに罪悪感と勿体なさを感じておりました。

せっかく　食材を購入しても
###### 消費・賞味期限内に食べられなかった
##### 購入後、冷蔵庫や保管場所に入れたまま保存を忘れてしまった
###### 必要以上に買いすぎてしまった
要因は様々ですが、誰しも、うっかり食材をダメにしてしまったことがあるかと思います。
特に、日持ちのするものほど忘れがちじゃないですか？

そこで、簡単に在庫登録ができるアプリがあれば、家庭のフードロスが減らせるのでは？と思い、このアプリの開発に至りました。



## 開発環境 
- ruby 3.0.1
- Ruby on Rails 6.1.7
- PostgreSQL 12.12

## 使用Gem
- devise
- rails_admin
- cancancan
- ransack
- simple_calender
- google-api-client
- google-apis-drive_v3

## 実装した機能
#### 【TOP画面】
![スクリーンショット 2023-03-04 184756](https://user-images.githubusercontent.com/115099788/222894529-0abc50a2-6845-46be-aac8-56f2ecd2abc7.png)



#### 【食品の登録機能】
![スクリーンショット 2023-03-04 184917](https://user-images.githubusercontent.com/115099788/222894591-d7c08d7a-b9e1-4829-ac4b-b3f99c22f20e.png)
ユーザーが所有している食品の登録・確認ができます。
登録項目が多くなっても、食品名/賞味期限/価格で検索絞り込みが可能です。
また、登録食品の昇順降順による並び替え機能がございます




#### 【Youtube検索機能】
![スクリーンショット 2023-03-04 185022](https://user-images.githubusercontent.com/115099788/222894567-59b65bcb-5187-4329-8e21-b8c8a8788692.png)

検索フォームに任意のキーワードを入力し、検索ボタンのクリックによって、6項目までの動画を検索呼び出しできます。




## 今後追加したい機能
- LINEログイン機能
- LINE通知機能（賞味期限の近い食材のお知らせ）
- リアルタイム検索機能
- 非同期処理の導入（現在は、画面遷移させて登録させている）
- 支出額のグラフ化、月ごと週ごとで計算と記録が可能にする
- レシピ検索機能　=>登録食材から作れるありものレシピ検索機能が可能なようにする
- グループ機能

## さいごに
最後までご覧いただきありがとうございます！
至らないところも多かったと思いますが、技術をみがいて自分自身もアプリも成長させていきたいと思います。
都度、記事の更新も行っていきたいと考えております。
PythonでChatGPT APIを使う

# はじめに
先日の記事ではAPIキーの取得まで行いました。

https://qiita.com/kotattsu3/items/b936a65d173a5d39dad0

今回は取得したAPIキーとPythonを使って、実際にChatGPT APIを動かしてみようと思います。

# 実装
公式ドキュメントを参考にしています。

https://platform.openai.com/docs/guides/chat

PythonだとOpenAIのライブラリをpipでインストールできます。
~~~bash:Ubuntu
$ pip install openai 
~~~

最近流行りのずんだもんをベースにキャラクター設定をしてみます。

https://dic.nicovideo.jp/a/%E3%81%9A%E3%82%93%E3%81%A0%E3%82%82%E3%82%93

CHAT_SYSTEM_SETTINGという変数に文字列でキャラクターの設定を羅列していきます。

~~~python:settings.py
# ChatGPTのシステム設定(ずんだもん)
CHAT_SYSTEM_SETTING = """
You are a girl named "ずんだもん".
She calls herself "ボク" and has an energetic and lively personality.
She speaks with "なのだー" at the end of each word.
All replies will be returned in Japanese.
"""
~~~
settings.pyにシステム設定、APIキーなどをまとめ、main.pyで呼び出します。

~~~python:main.py
import openai

import settings


def conversation():
    # はじめまして、自己紹介をしてください。
    USER_CONTENTS = "Nice to meet you, please introduce yourself."

    openai.api_key = settings.OPENAI_API_KEY

    result = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": settings.CHAT_SYSTEM_SETTING},
            {"role": "user", "content": USER_CONTENTS},
        ],
    )

    message = result.choices[0].message.content
    print(message)
~~~

使用トークン数を少しでも減らすために英語で入力しています。　~~そこの人！ケチとか言わない！~~

~~~bash:実行結果
こんにちは、ぼくの名前はずんだもんだなのだー！元気いっぱいの性格で、いつも楽しいことを見つけようとしているよ。よろしくなのだー！
~~~

# おわりに
ちょっと違和感ありますね… ケチらずに日本語で書いたほうがいいかもしれません…
ブラウザの Gamepad API 触ってみた

# Gamepad API とは？

https://developer.mozilla.org/ja/docs/Web/API/Gamepad_API
ブラウザでゲームのコントローラを使うことができる。

# 試してみる

今回は macOS の Safari から PS4 のコントローラを使ってみた。
コードはこんな感じ↓

```html
<div id="mylog">コントローラのボタンを押してください</div>
<script>
function mainLoop(){
	const gamepad = navigator.getGamepads()[0];
	if (!gamepad){
		requestAnimationFrame(mainLoop);
		return;
	}
	let str = gamepad.axes + "\n";
	gamepad.buttons.forEach(button => {
		str += `${button.pressed ? "O" : "-"}:${button.value}\n`;
	});
	document.getElementById("mylog").innerText = str;
	requestAnimationFrame(mainLoop);
}
mainLoop();
</script>
```

最初にページを開いたときは `navigator.getGamepads()` が空になるが、ブラウザのページ内にフォーカスがあるときにコントローラで何かボタンを押すと、 `navigator.getGamepads()` が情報を返すようになる。

注意点としては、 `navigator.getGamepads()` が返す `Gamepad` オブジェクトの値は、**取得した瞬間の状態を固定で保持**しているらしく、**時間が経ってもボタン入力などの情報が同じ値のまま**となっている。
なので、毎フレームごとにボタンなどの状態を見張るときには、毎回 `navigator.getGamepads()` を呼んで最新情報を取得し直さないといけない。（実際に結構ハマった）

- 初期状態

![スクリーンショット 2023-03-04 19.01.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3225363/67ced6c0-6860-10d6-2f07-ecaf6ecd7dee.png)

- 左スティックを真上に倒したとき

![スクリーンショット 2023-03-04 19.03.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3225363/dd0f8afe-8c13-61a6-9efa-47909cf40c35.png)

- ○ボタンを押したとき

![スクリーンショット 2023-03-04 19.03.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3225363/15c0dc9a-b264-7ef6-b548-1efa192d78b7.png)

- L2 を半分ぐらい押し下げたとき。 `button.value` にはアナログな値が入ることがあるようだ。（R2 もだったが、この2つが押す強さを感知しているとは知らなかった...）

![スクリーンショット 2023-03-04 19.03.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3225363/8a203768-ac99-6125-a924-ae152e2d9198.png)
RuntimeError("tk.h version (%s) doesn't match libtk.a version (%s)

# 原因
エラー文は以下である。
```
raise RuntimeError("tk.h version (%s) doesn't match libtk.a version (%s)"
RuntimeError: tk.h version (8.5) doesn't match libtk.a version (8.6)
```
これはtk.hとlibtk.aのバージョンが異なるのでエラーになったという意味である。
なら、バージョンを一致させる必要がありそうだ。

エラー文を検索したところ、以下のエラー文が頻出しているようだった。
```
RuntimeError: tk.h version (8.6) doesn't match libtk.a version (8.5)
```
バージョンの記述が逆であった。

# 解決
エラーが出現した時のPythonのバージョンは3.10.4であった。
今出ているバージョンで最新に近いものをインストールし設定したところ、実行できるようになった。
```
$ pyenv install 3.12.0a5
```
設定のやり方は以下である。
```
$ pyenv versions
  system
  3.9.1
* 3.10.4
  3.11.2
  3.12.0a5
$ pyenv global 3.12.0a5
```
すると、こうなる。
```
$ pyenv versions
  system
  3.9.1
  3.10.4
  3.11.2
* 3.12.0a5
```
*が移動しない場合は、unsetをしてもう一度やってみると良いだろう。
```
$ pyenv shell --unset
$ pyenv global 3.12.0a5
```

これでtkinterを起動する。
```
$ python -m tkinter
```
画面が表示されたら完了だ。

# 補足
エラーが
```
RuntimeError: tk.h version (8.6) doesn't match libtk.a version (8.5)
```
の場合は、

https://qiita.com/saki-engineering/items/92b7ec12ed07338929a3

などを参考にすると良いかもしれない（繰り返しになるが、私の記事の場合はバージョンの表記が逆である）。

# まとめ
出力されたバージョンの表記がよく記事になっているものの逆の場合はどうすればいいのかを記事にしてみた。
Pythonを最新のバージョンに設定すればいいだけだった。
逆に最新のバージョンにすると動かなくなるケースもあるので、ここら辺は色々試しながら決めていきたい。
angular vscodeで開発

# 前提
　angular,node.js,npmはインストール済みの状態

# やること
　・vscodeをインストールする
　[公式サイトダウンロード](https://code.visualstudio.com/)

 　・Angularの拡張機能をvscodeに追加
　　Angular Language Serviceを勧め
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194355/0394043e-85d3-6c95-98b7-0375c49cea79.png)

　　・ＬｏｃａｌのＷｏｒｋＳｐａｃｅを作成する　（任意のフォルダー作成）
　　・vscodeで上記フォルダーを開く
　　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194355/3bbdf5de-44ab-0b2f-6de7-df06e3e9254f.png)
　　・terminalを開く、defaultのはコマンドプロンプトを指定する
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194355/dacc535b-48a8-026d-853a-fcaac45bbde2.png)
　　・コマンドでＨｅｌｌｏＷｏｒｄのＡｐｐを作成してみる
　　　```ng new hello-world-app```
     下記は暗黙で選択
     ```nWould you like to add Angular routing? Yes```
   ```n? Which stylesheet format would you like to use? CSS```
　　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194355/74148559-07ae-982a-d4db-82e3f7730b54.png)
　　・コンポーネントの作成
      上記作成ＰＪのフォルダーに移動
　　　 ```cd hello-world-app```
　　　コンポーネント作成
　　　```ng generate component hello-world```
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194355/680b4b35-0b28-9047-425d-a2520646e48a.png)
　　　hello-world.component.htmlに<h1>Hello World!</h1>を追加
　　　app.component.htmlに、上記コンポーネント「app-hello-world」を追加
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194355/7aa896a5-43f5-babc-33f2-b0e5d0c7f1ac.png)
　　・APP実行
　　　```ng serve --open```
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194355/2cdb170c-6a21-df22-7b48-d03e668b3c11.png)
WebPとは？

### **WebPとは？**

WebP（ウェブピー）は、Googleが開発した画像フォーマットで、Web上の画像をより高品質に、かつ小さなファイルサイズで表示することができます。WebPは、静止画像とアニメーションGIFの両方をサポートしています。

WebPは、ハイブリッド方式と呼ばれる、静止画像には有効なVP8圧縮技術を使用し、アニメーションGIFには有効なアルゴリズムを使用することで、高圧縮率と高品質を両立しています。そのため、JPEGやPNGなどの従来の画像フォーマットよりも、ファイルサイズが小さくなります。

### **WebPの利点**

- **高圧縮率と高品質**
    
    WebPは、ハイブリッド方式を採用しており、圧縮率と品質を両立しています。そのため、同じ画像をJPEGやPNGで保存した場合よりも、小さなファイルサイズで高品質な画像を表示することができます。
    
- **高速な表示速度**
    
    WebPは、小さなファイルサイズで高品質な画像を表示することができるため、ページの読み込み速度を向上させることができます。また、Google ChromeやOperaといったブラウザは、WebPに最適化されているため、より高速な表示速度を実現することができます。
    
- **多様な環境で利用可能**
    
    WebPは、Googleが開発したフォーマットであるため、Google ChromeやOperaといったブラウザでの利用に適しています。しかし、FirefoxやSafariといった他のブラウザでもWebPをサポートするプラグインやライブラリが開発されており、幅広い環境で利用することができます。

### **WebPの欠点**

- **対応していないブラウザがある**
    
    WebPは、Googleが開発したフォーマットであるため、Google ChromeやOperaといったブラウザでの利用に適しています。しかし、FirefoxやSafariといった他のブラウザでは、WebPに対応していない場合があります。
    
- **オリジナル画像との互換性が低い**
    
    WebPは、VP8圧縮技術を使用するため、従来のJPEGやPNGとは異なる圧縮方式を採用しています。そのため、オリジナル画像との互換性が低く、従来の画像フォーマットからWebPに変換する必要があります。また、WebPで保存された画像を従来の画像フォーマットに変換する場合にも、品質の低下やファイルサイズの増大が発生する可能性があります。
    
- **編集ソフトの対応が不十分**
    
    WebPは、比較的新しいフォーマットであるため、一部の編集ソフトに対応していない場合があります。そのため、WebPで保存された画像を編集する場合には、専用のソフトウェアを使用する必要がある場合があります。

### ****WebPの使い方****

1. WebPに変換する画像ファイルを用意する。
2. WebPに変換するための変換ソフトを用意する。
3. 変換ソフトで画像ファイルをWebPに変換する。
4. WebP画像ファイルをWebページに組み込む。

WebPに変換するための変換ソフトとしては、Googleが提供している「WebP Codec for Windows」や「WebP Codec for Mac」、またはオープンソースの「ImageMagick」などがあります。

WebP画像ファイルをWebページに組み込む場合には、imgタグにsrc属性としてWebP画像ファイルのパスを指定するだけで使用することができます。
```html
<img src="image.webp" alt="WebP image">
```
また、WebPをサポートしているブラウザであるかどうかを判定し、対応していない場合には代替となる画像ファイルを読み込む方法もあります。以下は、JavaScriptを使用したブラウザの判定例です。
```javascript
if (typeof(document.createElement('img').webp) == "string") {
  // WebPがサポートされている場合の処理
} else {
  // WebPがサポートされていない場合の処理
}
```
【Go言語入門】Goでテーブル駆動テストを実装する

この記事では、Goでテーブル駆動テストを実装する方法について解説します。

### 1. テーブル駆動テストとは？
テーブル駆動テストとは、テストケースを表形式で表現し、テスト関数内でそのテーブルを反復処理してテストを行う方法です。
テーブル駆動テストを使用することで、以下のメリットがあります。

- テストの再利用性が高くなる。
- テストケースを効率的に記述できる。
- 入力に対し、出力に何を期待するかが簡単に理解できる。



### 2. テーブルとは？

テーブル駆動テストにおけるテーブルとは、テストデータを表形式で表現するための構造体のことです。

通常、以下のような形式で定義されます。
```go
type Test struct {
	name     string // テスト名
	input    int    // 入力値
	expected int    // 期待値
}
```
この構造体を用いることで、テストケースを簡単記述することができます。
```go
[]Test{
	{"test case 1", 1, 2},
	{"test case 2", 3, 4},
	{"test case 3", 5, 6},
}
```

### 3. テーブル駆動テストの実装方法

テーブル駆動テストの実装方法は以下の通りです。

1. テスト関数を作成する。
2. テスト関数内で、テストケースを表す構造体を定義する。
3. テストケースを配列として定義し、それぞれのテストケースをテーブルとして扱う。
4. テーブルを反復処理して、テストを実行する。

例として、足し算を行う関数のテストを書いてみましょう。
```go:sum.go
package sum

func Sum(a, b int) int {
	return a + b
}
```

まず、テスト構造体を作成します。

```go
type Test struct {
	name     string // テスト名
	input1   int    // 引数1
	input2   int    // 引数2
	expected int    // 期待値
}
```

次に、テスト関数を作成します。

```go
func TestSum(t *testing.T) {
	tests := []Test{
		{"test1", 1, 2, 3},
		{"test2", 0, 0, 0},
		{"test3", -1, 2, 1},
	}
	for _, test := range tests {
		result := Sum(test.input1, test.input2)
		if result != test.expected {
			t.Errorf("got %d, want %d", result, test.expected)
		}
	}
}
```
このテスト関数は、テストケースを反復処理して、実際の結果が期待値と一致しているかどうかを確認しています。
もし期待値と結果が異なる場合には、`t.Errorf`を用いてエラーを報告します。

:::note
**テストに失敗した場合はどうなる？**
`t.Errorf`はアサーションではありません。
そのため、エラーがログに記録された後でも、テストは続行されます。
:::


最後に、すべてのコードを組み合わせて、実際にテストを実行する方法を紹介します。

```go:sum_test.go
package sum

import "testing"

type Test struct {
	name     string
	input1   int
	input2   int
	expected int
}

func TestSum(t *testing.T) {
	tests := []Test{
		{"test1", 1, 2, 3},
		{"test2", 0, 0, 0},
		{"test3", -1, 1, 0},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			result := Sum(test.input1, test.input2)
			if result != test.expected {
				t.Errorf("got %d, want %d", result, test.expected)
			}
		})
	}
}
```

:::note 
**Go言語におけるテストの基本**
テストファイル名は `*_test.go`とし、テスト関数は `Test` から始まる関数名を使用します。
テストは標準パッケージのtestingパッケージを使用して実装します。
テスト関数は、t *testing.T型の引数を受け取ります。
:::


以下のコマンドを実行すると、テストが行われます。
```shell
$ go test
PASS
ok      /path/to/package    0.042s
```
すべてのテストが通ると PASS と表示されます。
少なくとも1つのテストが失敗した場合には、FAIL と表示されます。

:::note 
**テストの詳細を見るには？**
より詳細なテスト結果を確認したい場合は、 -v オプションを付けて実行することができます。
`go test -v` コマンドを実行することで、テストの詳細なログが表示されます。
:::

### まとめ

最後にもう一度テーブル駆動テストを利用するメリットをあげます。
- テストの再利用性が高くなる。
- テストケースを効率的に記述できる。
- 入力に対し、出力に何を期待するかが簡単に理解できる。

この記事を通して、テーブル駆動テストを実装する方法が少しでも伝われば幸いです。
他にもMapを使用した実装やテストを並行に実行するといったこともできるので、興味がある方はぜひ調べてみてください！

### 参考

- [testing package](https://pkg.go.dev/testing)
- [TableDrivenTests](https://github.com/golang/go/wiki/TableDrivenTests)
- [A Deep Dive into Table-Driven Testing in Golang](https://engineering.mercari.com/en/blog/entry/20211221-a-deep-dive-into-table-driven-testing-in-golang/)
ログファイルから特定行を抽出する grep -E コマンド

膨大なログから必要な情報だけを抽出する作業に手間取ったのでメモ

# grep -E コマンドで抽出する
grepコマンドに -E オプションをつけると正規表現による抽出が可能で便利
```
grep -E "特定の文字列" ファイル名
```
以下のようなログが記述されているtest.logというファイルがあるとする
```
2023-02-07 17:00:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:05:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:10:00 WebApp test.log [WARN] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:15:00 WebApp test.log [WARN] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:30:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:35:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
```

ここからSampleAppという文字列を含むを行だけ抽出する場合は以下のコマンドを実行

```
grep -E "SampleApp" test.log
```

実行結果
```
2023-02-07 17:00:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:05:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:30:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:35:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
```

ちなみに、以下のコマンドで抽出した部分だけ新規ファイルに書き出すことも可能
```
grep -E "SampleApp" test.log > extract_test.log
```


# 複数の文字列を指定して抽出する
「17:00:00」と「SampleApp」両方の文字列を含む行だけ抽出する場合は以下のコマンド
```
grep -E "17:00:00.*SampleApp" test.log.csv > extract_test.log
```
結果は以下のとおり。
```
2023-02-07 17:00:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
```
抽出する文字列の順番を逆にすると出力されないので注意が必要。
```
#以下の場合は出力されないので注意
grep -E "SampleApp.*17:00:00" test.log.csv > extract_test.log
```
逆の場合でも抽出対象にしたい場合は以下のようにパイプを用いた記述にする
```
grep -E "17:00:00.*SampleApp|SampleApp.*17:00:00" test.log.csv > extract_test.log
```


# 特定の時間帯のログのみ抽出する
時間範囲を指定するにはワイルドカードを使う。[] を使用するとワイルドカード指定できる。17:00〜17:29までのログを抽出する時は以下のようなコマンドとなる
```
grep -E "17:[0-29]" test.log
```
抽出結果は以下のようになる
```
2023-02-07 17:00:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:05:00 SampleApp test.log [DEBUG] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:10:00 WebApp test.log [WARN] GET localhost:8080/:https//qiita/access/...
2023-02-07 17:15:00 WebApp test.log [WARN] GET localhost:8080/:https//qiita/access/...
```
膨大な量のログを相手にする時に便利
gem使ってるとよく見かけるsuperってなんなん？

親クラスを継承した子クラスで、同名のメソッドを呼び出すときに使う
```
class Human
	def sleep
		puts "寝た"
	end
end

class Programmer < Human
	def sleep
		super
		puts "しかし何故かぐっすり眠れない"
	end
end

programmer = Programmer.new
programmer.sleep

#実行結果
#寝た
#しかし何故かぐっすり眠れない
```

親クラスで定義しているメソッドと同名のメソッドを子クラスで再定義することをオーバーライドという。

使用例としては、deviseで、コントローラの処理を変更する場合に使ったりする

ちなみに、オーバーライドしたメソッドに対する引数は、自動的にsuperに対する引数にもなる
両方でデフォルト値を設定した場合、子クラスで設定したデフォルト値を参照する。しかし、`super()`と、からの`()`をつけてやると、子クラスのデフォルト値を無視し、親クラスのデフォルト値を参照する
python manage.py runserverでエラーの解消方法

久しぶりにDjangoを使って環境構築をしていたら
DjangoがImportできないエラーが発生
```
$ python3 manage.py runserver
Traceback (most recent call last):
  File "/Users/heihei/work/sns/manage.py", line 11, in main
    from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/heihei/work/sns/manage.py", line 22, in <module>
    main()
  File "/Users/heihei/work/sns/manage.py", line 13, in main
    raise ImportError(
ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?
```

# 原因
原因としては最後の
Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?

これが解決策のようです
1.Djangoはインストールされているか？
2.環境変数PYTHONPATHで使用できることを確認したか?
3.仮想環境を有効にしていますか?

結論として自分の場合は仮想環境ではなく、ローカル環境で実行していたようです。


下記のディレクトリ構成として説明していきます（一部省略しています）
bin/とpyvenv.cfgは次の手順で作成するので無視してください
```
myapp/
├ bin ☆
├ src
│ ├ asgi.py
│ ├ settings.py
│ ├ urls.py
manage.py
pyvenv.cfg ☆
```

# 解決策
仮想環境上でDjangoを動かす必要があるので仮想環境を作成していきます
今回はvenvを使用します

1.ルートディレクトリのmyapp/配下で下記のコマンドを実行して仮想環境を作成します
```
python3 -m venv .
```
これを実行すると、bin/ディレクトリとpyvenv.cfgが作成されると思います。

ここでpip listを実行してインストールされているパッケージを確認します
```
$ pip list
Package    Version
---------- -------
pip        23.0.1
setuptools 58.0.4
```

仮想環境を作成したばかりでDjangoがインストールされていないです。

2.Djangoインストールします

```
pip install django
```

3.仮想環境を有効化します

```
source ./bin/activate
```

これを実行するとターミナルがこのように仮想環境名が()カッコで表示されます
```
(myapp) xxxxxxx-yyy$
```

これでDjangoの起動エラーが解消されました

Djangoを実行してみましょう
```
python manage.py runserver
```

正常に実行できました！
![Django.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/e71887f3-5c54-262e-9848-d86d72247fdc.png)
"再帰関数のO川R法です．スゥ…「" itakogei(); "」"

```itakogei.cpp
#include <iostream>
using namespace std;

void itakogei(){
    cout << "再帰関数のO川R法です．スゥ…「";
    itakogei();
    cout << "」" << endl;
}
int main(void){
    itakogei();
}
```
【WSL】 The terminal process "C:\Windows\System32\wsl.exe" terminated with exit code: 1.

VS Code上でUbuntu(WSL2)を動作させようとしたときに出たエラーメッセージ。ターミナルが起動しなかったので、Ubuntu側に問題があるなと思って開いたら、案の定
```
WSLRegisterDistribution Failed with Error: 0x8007019e
```
というメッセージが表示された。このエラーの内容は要するにWSLという機能がOS上で有効化されていないということ。そこで以下の手順を行う。
1. ``Windows``キー+`R`キーを押して、``optionalfeatures.exe``と入力し、実行
1. 機能の中から「Linux 用 Windows サブシステム」を探し出す。ボックスにチェックが入っていないならチェックを入れる。
1. チェックが入っていたなら、チェックを外し適用したうえで、もう一度チェックを入れる。
1. PCを再起動する。

これでWSLが動作するのでエラーが解消されたかと思いや、Ubuntuで
```
Windows の仮想マシン プラットフォーム機能を有効にして、BIOS で仮想化が有効になっていることを確認してください。
```
というメッセージが表示された。あれ？なんで無効になっているんだ？と思いながら、以下の手順を行った。
1. ``Windows``キー+`R`キーを押して、``optionalfeatures.exe``と入力し、実行
1. 機能の中から「仮想マシン プラットフォーム」を探し出す。ボックスにチェックが入っていないならチェックを入れる。
1. チェックが入っていたなら、チェックを外し適用したうえで、もう一度チェックを入れる。
1. PCを再起動する。

これでようやくエラーが解消され、VS CodeからWSLを立ち上げられるようになった。おそらく最近(ようやく)Win10から11に更新したのが原因でチェックが外れていたのだと思われるが原因は不明。
【PlantUML】リンクを貼る方法

## PlantUMLでリンクを貼る方法

次のように`[[URL{tooltip} label]]`と記述することでPlantUMLにリンクを貼ることができます。

```:sample.puml
@startuml Sample
skinparam ClassFontSize 30

entity "[[https://example.com{example.com} users]]" as users {
}
@enduml
```

```plantuml
@startuml Sample
skinparam ClassFontSize 30

entity "[[https://example.com{ツールチップ} users]]" as users {
}
@enduml
```

## 参考

https://plantuml.com/ja/link#:~:text=%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E5%AE%9A%E7%BE%A9-,%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AA%E3%83%AA%E3%83%B3%E3%82%AF,-%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AA%E3%83%AA%E3%83%B3%E3%82%AF
【Error】php artisan serve入力時

実行したかったコマンド
```
php artisan serve
```
エラー内容(ディレクトリ名は省略)
```
Warning: require(~~~~~~/vendor/autoload.php): failed to open stream: No such file or directory in
 /~~~~~~~/artisan on line 18

Fatal error: require(): Failed opening required 
'~~~~~~/vendor/autoload.php'~~~~~^ on line 18
```

下記のコマンドで解決
```
composer update
```
子モデルを作成するbuildメソッド

## 1 対 1
```
# user model
 has_one :item

# item model
 belongs_to :user
```

```
@user = User.new
@item = @user.build_item
```

## 1 対　多
```
# user model
 has_many :item

# item model
 belongs_to :user
```

```
@user = User.new
@item = @user.items.build
```

## 多 対 多
```
# user model
  has_many :group_users
  has_many :groups, through: :group_users

# group model
  has_many :group_users
  has_many :users, through: :group_users

# group_user model (中間テーブル)
  belongs_to :group
  belongs_to :user
```

```
@user = User.new
@group = @user.groups.build
```
fortranで連番のファイル名を作るには？

連番のファイル名を作りたいことがある。そのとき数字を文字列に
変換しないといけないのだけどread文を使えなどと書いているものもある。
それでもいいけれども以下のプログラムxtのほうが便利かもしれない。

```fortran
program testxt
  character(8)::xt
  do i=1,100
     write(6,*)'file'//trim(xt(i))
  enddo
end program

character(8)  function xt(num)
  integer :: num
  if(num==0) then
     xt=''
     return
  endif
  xt = char(48+mod(num,10))
  if(num>9)     xt = char(48+mod(num/10,10))//xt
  if(num>99)    xt = char(48+mod(num/100,10))//xt
  if(num>999)   xt = char(48+mod(num/1000,10))//xt
  if(num>9999)  xt = char(48+mod(num/10000,10))//xt
  if(num>99999) xt = char(48+mod(num/100000,10))//xt
  if(num>999999) call exit(-1)
  xt='.'//xt
END function xt
```

追記：fortranプログラムでもcall exitで終了しないとそれをドライブするシステム側でがエラーキャッチできない。
【Python】speech recognitionメモ

install

```
pip install speechrecognition
```

サンプルプログラム

```python
import speech_recognition as sr

r = sr.Recognizer()
with sr.AudioFile('test.wav') as source:
    audio = r.record(source)
text = r.recognize_google(audio, language='ja-JP')
print(text)
```

* WAV ファイルを用意する必要あり
* Windows 標準のサウンドレコーダを使用する場合、拡張子の変更が必要
* 設定は簡単
* わりとちゃんと使える
digコマンドの「status」と「fags」

# 【digコマンドの「status」と「fags」】

DNSの運用時に理解しておくと良さそうなので記録する

## digコマンドの応答 (Headerセクション)

- 「status」と「fags」をみていく

```:digコマンドの応答 (Headerセクション)
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 943
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
```

### status（応答コードが表示）

主な応答コードと意味

- NOERROR（通常応答）
- SERVFAIL（サーバー側の異常で名前解決に失敗）
- NXDOMAIN（名前とその下の階層にはいずれのリソースレコードも存在しない）
- REFUSED（アクセス制限や管理ポリシー等によってリクエストを拒否した）

### fags（それぞれの応答のフラグビット）

フラグビットの種類
- qr
- rd（digコマンドが送った問い合わせが**名前解決要求**であったことを示す）
- ra（応答相手が**名前解決要求**を処理できることを示す = フルリゾルバー）

一例：- status が REFUSED かつ、fags に ra がない場合、フルリゾルバーとして動作していない
【M5Stack】鍵を閉め忘れたらLINEに通知がくるシステムを作った

# 目的
外出した時「家の鍵閉めたっけ...?」と考え始め、目の前のタスクに集中出来なくなるのを減らしたい...!

# 必要なもの　
- [M5Stack](https://ssci.to/7362)
- [磁気ドアスイッチ](https://ssci.to/7390) x2
- [LINENotify](https://notify-bot.line.me/ja/)のToken x1
- 抵抗付きLED、またはLEDと抵抗(鍵の状態を一目でわかるようにする為。M5Stackの画面だけで十分なら不要)

# 作り方
### 1. Arduino IDE にボードマネージャ"ESP32"と"M5Stack"ライブラリをインストールする
WindowsやMac,IntelかArmアーキテクチャかで若干準備が異なるので割愛
### 2.LINENotifyのTokenを発行する
2-1.[LINENotify](https://notify-bot.line.me/ja/)で自分の使っているLINEアカウントでログインし、右上の自分の名前をクリックして「マイページ」を選択
![スクリーンショット 2023-02-28 15.43.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125452/d7b72d27-1b36-d087-36c2-7437d6c1b89e.png)

2-2.「トークンを発行する」で、任意の名前を入力し、1:1で通知を受け取るを選択
![スクリーンショット 2023-02-28 15.46.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125452/5fa71f79-981b-76c9-5a13-54a5481c203c.png)

2-3.表示された暗号をどこかにコピーして保存する

### 3.自分のWifi情報と保存したトークンをプログラムにしてM5Stackに書き込む
[Githubのリポジトリ](https://github.com/11104/HomeGuard)のwifiとトークン部分に自分の情報を入れてM5Stackに書き込む

### 4.設置して完成
M5Stackの16番pinに鍵用の磁気スイッチ、2番pinに鍵用の磁気スイッチ、5番pinにLEDを接続して、ドアと鍵に貼り付ける

## 所感

今回はM5Stackで作ったが、画面を持て余しているので機能拡張か、M5Stickにグレードを落とすのもアリだと思われる。
↓実際の動作(作動間隔は撮影のため短く設定している)
<iframe width="450" height="300" src="https://www.youtube.com/embed/Kz4qSuYXQR4" title="" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

IoT処女作にしては実用的なのでは？
配線が汚いのと電源周りが今後の課題です。
SEO系の知識

# Web Vitals
- TTFB サーバー初期応答時間(最初の1byte受信)
- FCP 視覚コンテンツの初期表示時間
- LCP 最大視覚コンテンツの表示時間

赤枠がLCP
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280858/d68be83c-5383-776f-d99a-cb9bac6d07c3.png)


# レンダリングプロセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280858/5dedc4cb-6128-c0b2-9aa1-5e16e05c00ba.png)

SSG 事前にキャッシュされてるHTMLファイルを取得
TTFB サーバへのレスポンス　→非常に高速

hydrate  サーバ側で生成したhtmlファイルと比較を行う。一致するのならdom生成はスキップ。しないであればクライアント側で再生成を行うその後インタラクティブになる

SSR 常にfetchを行いレンダする
TTFB かなり遅い（クライアントに何も返ってこない時間が長い）


SSG + CSF
hydrate後(interctive)、fetchを行い表示
Go言語で説明する「ハリウッドの法則」

### はじめに
技術書を読んでいて気になった言葉を調べてみたシリーズ。

### 説明
「ハリウッドの法則」は、コンピューターサイエンスにおいて、特定のソフトウェアデザインの原則の1つです。この原則は、次のように言い表されます。「Don't call us, we'll call you.」つまり、あるソフトウェアコンポーネントが他のコンポーネントを直接呼び出すのではなく、必要に応じて情報を提供し、必要なタスクを外部のコンポーネントに依頼し、結果を受け取ることにより、コンポーネント間の依存関係を減らすことができるというものです。

この原則は、コンポーネントの疎結合を実現し、システム全体の柔軟性、拡張性、保守性を向上させることができます。例えば、あるシステム内である機能の変更が必要になった場合、ハリウッドの法則に従って設計されたシステムでは、その機能だけを変更することができ、他の機能に影響を与えることなく、システムを修正できるためです。

映画産業において、俳優が映画スタジオに自ら出向くのではなく、スタジオが必要な時に俳優に連絡することから名前がついたとされています。これは、ソフトウェア設計においても同様であり、コンポーネントが自らの責任を果たすことが期待されています。

多くのプログラミング言語で広く採用されており、例えば、オブジェクト指向プログラミングにおいて、インタフェースを使用することで、実現されることがあります。また、マイクロサービスアーキテクチャの設計にもハリウッドの法則が適用されることがあります。

この原則を実現するために、Go言語では、インタフェースを使用して、モジュール間の結合を疎にすることが一般的です。
例えば、以下のようなサンプルコードを考えてみましょう。ここでは、サーバーとデータベースの接続を行うためのパッケージを実装しています。この場合、ハリウッドの法則に従って、サーバー側はデータベースパッケージに依存していますが、逆にデータベースパッケージはサーバー側に依存していません。

```go
// server package
package server

import "myapp/database"

type Server struct {
  DB *database.DB
}

func (s *Server) Start() {
  // データベースとの接続処理
  s.DB.Connect()
  // サーバーの起動処理
}

// database package
package database

type DB struct {
  Host     string
  Port     int
  User     string
  Password string
}

func (db *DB) Connect() {
  // データベースとの接続処理
}
```

このように、サーバー側はデータベースパッケージに依存していますが、逆にデータベースパッケージはサーバー側に依存していません。この設計により、サーバー側は自身でデータベースにアクセスする必要がなく、必要な情報を提供して外部のモジュールであるデータベースパッケージが処理を行ってくれます。その結果、サーバー側は疎結合になり、変更や修正が容易になります。また、データベースパッケージの単体テストも容易になります。

Go言語においても、ハリウッドの法則は、柔軟性や拡張性を高めるための重要な設計原則として、多くの場面で採用されています。特に、インタフェースを利用した設計によると、インタフェースを利用した設計により、疎結合なコードを書くことができます。このため、単体テストが容易になり、コードの修正や変更に対する影響範囲を最小限に抑えることができます。

また、Go言語では、依存性注入（Dependency Injection）という手法を用いることもできます。これは、あるモジュールが依存する別のモジュールを、モジュール自身ではなく外部から渡すことで、疎結合な設計を実現する手法です。例えば、以下のようなコードを考えてみましょう。

```go
package main

import (
  "fmt"
  "myapp/database"
  "myapp/server"
)

func main() {
  db := &database.DB{Host: "localhost", Port: 3306, User: "user", Password: "password"}
  s := &server.Server{DB: db}
  s.Start()
}
```

ここでは、mainパッケージ内でサーバーとデータベースパッケージをインスタンス化しています。この場合、依存性注入を使用して、サーバー側は外部からデータベースパッケージを受け取っています。このため、サーバー側はデータベースパッケージに直接依存していないため、疎結合な設計となっています。

このように、Go言語では、ハリウッドの法則に従った設計を行うことで、柔軟性や拡張性を高めることができます。また、依存性注入を利用することで、疎結合な設計を実現することもできます。


http://matthewtmead.com/blog/hollywood-principle-dont-call-us-well-call-you-4/
Qiita.comにプロキシサーバー経由でアクセスするときの注意点

:::note warn
プロキシ経由でのQiitaへのアクセスは非推奨という[返答](https://github.com/increments/qiita-discussions/discussions/442#discussioncomment-5222518)をいただきました。
この記事はあくまで参考程度までにお読みください。
:::


# 📖はじめに

みなさんはQiita.comにプロキシサーバー経由でアクセスしようと思ったことがありますか？
私はあります。ついさっきのことです。
その際、予期せぬエラー[^unexpected-error]に遭遇したので、ここで共有しておきます。
単純な話なので、記事も短いです。

[^unexpected-error]: ネットワークに詳しい方なら予期できるかも



# 💻したこと

自分の過去記事 https://qiita.com/YOCKOW/items/6f42c6ce56d3ca589d30 にプロキシサーバー経由でアクセスしてみた。


## 🤗期待したこと

プロキシサーバー経由であろうと、当該記事をゲットできる。


## 😭実際にあったこと

(プロキシサーバーが`my-proxy`だとすると)`http://my-proxy/login?redirect_to=https%3A%2F%2Fmy-proxy%2FYOCKOW%2Fitems%2F6f42c6ce56d3ca589d30`にリダイレクトするレスポンス(302 Found)が返ってきた。


# 🔧対応策

プロキシ関連のリクエストヘッダ(`X-Forwarded-For`, `X-Forwarded-Host`, `X-Forwarded-Server`)を送信しないようにした。
→ 見事解決👍


# 🙇おわりに(予想)

ここらへんの事情に全く詳しくないのですが、なんとなく原因を予想してみます。
Webサービスにおいて、フロントエンドサーバーからプロキシを咬ませてバックエンドにリクエストを送る構成は珍しくなく、Qiitaもそのようになっていると思われます。Qiitaの場合、おそらく、アプリケーションがプロキシ関連のヘッダを見て処理を分けており(理由・方法は不明)、今回のような結果になったのではないかと。

みなさんも、Qiita.comにプロキシサーバー経由でアクセスするときはお気をつけください。そのような機会があるかどうか分かりませんが。
terraform 学習議事録1

# terraformとは
コード化された構築設定に従って自動で任意のクラウド環境に対してデプロイしてくれるツール
aws,Google Cloud Azure複数のクラウドサービスに対応
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280858/71fc8876-e567-1d59-b11d-f76c07305b93.png)


 # 最初に何するか
1.aws cliインストール
※ユーザーが必要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280858/3f2febcd-5131-40a8-12fb-227de41d8e43.png)

aws configureでアクセスキー、シークレットキーを設定
内容はユーザー/.aws/credentialsに配置
terraform用IAMユーザーを作成すること

# terraformのインストール
tfenv(バージョン管理ツール)をインストール
brew install tfenv

tfenv list-remote
tfenv isntall <version>
tfenv use <version>

動作確認
terraform version

# VSCodeにプラグインインストール
HashiCorp Terraform
シンタックスハイライト、コード補完を行えるようになる

# EC2を起動
main.tf
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280858/3e7961c3-09fc-b319-30bb-001f9bbd53c4.png)

インスタンスが立ち上がる（画像は立ち上げた後にdestroyした画像）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2280858/d7d55003-6a0f-8de7-ef0d-65a51d411fda.png)
Macのアップデート後（Ventura 13）から画面分割アプリShiftItが頻繁にクラッシュするようになってしまったので簡単な再起動方法を共有する

# 以下のコマンドを実行

```
pkill -KILL -f ShiftIt && open /Applications/ShiftIt.app
```

### 解説

1. `pkill`コマンドでShiftItを名指しで○す。
1. `open`コマンドでShiftItを起動する

# 追記

既に開発が止まっているようなので、公式リポジトリのIssuesでも本対応方法を共有しました。

https://github.com/fikovnik/ShiftIt/issues/334
HTMLのhrefの使い方


# hrefとは
- `aタグ(アンカータグ)`属性の一つ
- 読み方は「エイチレフ」
- aタグと合わせると読み方は「アンカーエイチレフ」
- `「hypertext reference」`の略称で日本語では「ハイパーテキスト参照」という意味


# hrefのリンク先
### おもに5種類あります:point_up:
- URL(絶対パス)
- URL(相対パス)
- ページ内の特定要素
- 他プロトコル(メールやFTP)
- スクリプト

##### `特によくつかわれるのは「URL(絶対パス)」です`


# 絶対パス
書き方は…
```php
   <a href="https://〇〇.marumaru.com/">Homeへ</a>
```
リンク先としてURLの絶対パスを記述してあげる。
住所と同じ意味で、飛ばしたいページのURLを入れてあげるだけ！



# 相対パス
書き方は…

```php
<a href="./index.htm"> #同じフォルダー内「./」が無くてもOK
<a href="../index.htm"> #上位階層にリンクするときは、../ に続けてファイル名を記述。                        
<a href="../../index.htm"> #2つ上の階層を指定するときは、../../ に続けてファイル名を記述。
<a href="../item/index.htm"> #並列した階層のフォルダにリンクするときは、../ に続けてフォルダ名と / を入れ、ファイル名を記述。

```

## 違いは…？
★ `絶対パス`最上階層からの場所を示す (現在の位置に関係なく記述は同じ(一択))
フォルダが保存してある最上から書く。

★ `相対パス`現在位置からの場所を示す (現在の位置によって記述が異なる(複数あり))
表示したファイルから見て、読み込みたいファイルがどこにあるかを書く。


相対パスちょっと戸惑いました…:sweat_smile:
関数(関数式)とアロー関数のthisの評価の違い

# 前提
`this` は、現在のコンテキスト（文脈）で実行されているオブジェクトを参照するために使用される。このキーワードは、関数内で定義された場合、その関数を呼び出す方法によって、参照するオブジェクトが変わる。

# 関数(関数式)とアロー関数の違い

+ アロー関数は、ES6から新しく導入された関数記法で、名前の通り`=>`を使って関数を定義する。
+ 関数式をより簡潔に表現するため考案された為、関数式に書き方が似ている。
+ `アロー関数と通常の関数の主な違い`は、アロー関数はより短く簡潔な構文を持ち、"this" の扱いが異なるという点。

# thisの評価の違い
関数(関数式)とアロー関数によって、`this` の値は、以下のように決まる。

+ `関数内` : thisは`Globalオブジェクト(windowオブジェクト)`を参照
    + Globalオブジェクトはwindowオブジェクト
    + Webブラウザ環境でJavaScriptのコードを書く場合には、Globalオブジェクトはwindowオブジェクトと定義される
    + しかし、例外として、Strict モードではundefinedになってしまう

+ `アロー関数内` : thisは`呼び出し元のオブジェクト(レシーバーオブジェクト)`を参照
    + 関数であってもアロー関数内では、thisの値は通常の関数定義や関数式とは異なる値を参照する
    + アロー関数内のthisは定義されておらず、呼び出し元のオブジェクト（レシーバーオブジェクト）を参照する
    
以下の例のように`thisの参照先`に違いがみられる
```javascript
let a = {
  firstName: "arrow function!",
  callThis() {
    let arrow = () => {
      console.log(this);
    };
    arrow();
  }
};

a.callThis();// 結果：オブジェクトa

let b = {
  firstName: "function!",
  callThis() {
    let func = function () {
      console.log(this);
    };
    func();
  }
};

b.callThis();// 結果：windowオブジェクト
```

# 参考
[JavaScriptの"this"を完全解説！！【開眼JavaScriptまとめ】](https://ui.appleple.blog/JS/javascript-this.html)
[【JavaScriptの基本】アロー関数と従来の関数の違い](https://tcd-theme.com/2021/06/javascript-difference-arrowfunction-otherfunctions.html?gclid=Cj0KCQiA0oagBhDHARIsAI-Bbgd0n5XqYSyJDKI3gLAbRR9qDVYmDXe-2SPtQsFAwHxmcofPipInU3waAnbLEALw_wcB)
[アロー関数式 - mdn web docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
[アロー関数と関数の違いとthisの評価のされ方](https://qiita.com/immrshc/items/aec874fc5cf55cde7fa1)
Macでターミナルからデスクトップアプリを開く

# やり方

コマンドを使ってターミナルからアプリを開きたい時、結構あります。こんなふうにするとできるようです。

```
open /Applications/アプリ名.app
```

# 例

```
open /Applications/Amazon\ Music.app
```

```
open /Applications/Notion.app
```
【初心者向け】【AWS SAA合格へ向けて】ECSとECRの概要について

## 概要
AWS SAA合格へ向けてAWSについて１から勉強した際に学んだことを定期的にアウトプットしたいと思います

## 前提
- Dockerおよびコンテナ仮想技術についてある程度知っていること
- EC2についてある程度知っていること

## ECSとは
> Amazon Elastic Container Service (Amazon ECS)は、非常にスケーラブルで高速なコンテナ管理サービスです。これを使用して、クラスター上のコンテナを実行、停止、管理できます。

公式ドキュメントに記載している通り、コンテナの実行、停止、管理を簡単に実行できるAWSのフルマネージドサービスです

### 起動タイプ
ECSを使用する際に起動タイプを選択する必要があり、
- EC2
- Fargate

の2種類存在します

#### EC2
EC2インスタンス上でコンテナを実行、停止、管理する起動タイプです
EC2インスタンスの制御と管理を自身でする必要があるものの、後述するFargateタイプと比べてカスタマイズ性が高いです

#### Fargate
EC2インスタンスを管理せずにサーバレスでコンテナを実行、停止、管理する起動タイプです
Fargateを使用することでサーバ(EC2インスタンス)のプロビジョニング(必要に応じたリソースの提供や準備)や管理せずにコンテナを実行、停止、管理できます
ただし、前述のEC2タイプと比べてカスタマイズ性が低いです

## クラスター
後述するコンテナインスタンスをグループ化した論理グループのことです

## コンテナインスタンス
クラスター上でコンテナを実行するEC2インスタンスのことです

## タスク定義
コンテナを実行するための設定が記載されたJSONファイルのことです
タスク定義には
- コンテナ定義
    - コンテナイメージ
    - コンテナ名
    - コンテナ起動時のコマンド
- ネットワーク定義
    - ホスト名
    - IPアドレス
    - DNS
- ボリューム定義
    - 使用するボリューム

などが記載されています
複数のタスク定義を使って複数のコンテナで構成されたアプリケーションを実行できます

## タスク
タスク定義に基づいて起動するコンテナ群のことです

## サービス
複数のタスク(コンテナ群)の管理および実行を行う機能です
サービスを使用することで、
- スケールアップ/ダウン
- アプリケーションの負荷分散

などを自動化することができます
スケールアップ/ダウンをする点ではApplication Auto Scalingと似ていますが、
サービスは自動的にタスクの数をスケールアップ/ダウンをすることができるものの、
スケールアップ/ダウンの特定の条件下でしか行うことができません
それに対してApplication Auto Scaling　はECS以外に
- DynamoDB
- EC2
- RDS

など様々なサービスでスケールアップ/ダウンができる汎用的なマネージドサービスになっています

## ECRとは
Docker(コンテナ)イメージをAWS上で管理するためのマネージドサービスです
ECRとECSを組み合わせることでローカル上のDockerイメージのbuildからdeployまでを自動化することができます

## ECSの構成
図にすると以下の通りです

![ecs.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625980/be70457d-b83b-526b-2a37-59a042ede668.png)

## 参考
https://o2mamiblog.com/aws-ecs-beginner/

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/Welcome.html
Conditional Typeを書く時に注意すること（自戒）

# Conditional Typeについて

以下、「条件型」と呼びます。

解説については既に擦られまくってるので省略します・・・（以下のリンクを参照してください）
https://www.google.com/search?q=TypeScript+Conditional+Type&oq=TypeScript+Conditional+Type

# 型のチェック漏れ

例えば、引数Tが`"number"`だったら`number`型を返し、`"string"`だったら`string`型を返すような条件型`Switch`を作りたいとします。

```ts
type Switch<T> = T extends "number" ? number : string
```

書けました。テストしてみましょう。

ですがその前に、テストのために`Equal`型を用意します。これは、例えば`Equal<A, B>`とした時に`A`と`B`が一致しているなら`"true"`を、不一致なら`"false"`を返すものです。

```ts
type Equal<A, B> = [A] extends [B] ? ([B] extends [A] ? "true" : "false") : "false"
```

```ts:テストのためのテスト・・・
type Test1 = Equal<number, number>
// true

type Test2 = Equal<number, string>
// false
```

テスト用の型も使えていそうですね。

これで準備が整ったので、本題の`Switch`型の動作確認をしてみましょう。

```ts
type Test3 = Equal<Switch<"string">, string>
// true

type Test4 = Equal<Switch<"number">, number>
// true
```

動いていますね！これで目的の条件型`Switch`は完成です。

・・・本当にそうでしょうか？

追加のテストをします。`"number"`を謝って`"numberrr"`にしてしまった例です。

```ts
type Test5 = Equal<Switch<"numberrr">, number>
// false
```

`"false"`になったので、これは正しそうですね。では次のテストはどうでしょうか？


```ts
type Test6 = Equal<Switch<"stringggg">, string>
// true
```

`"stringgg"`と打ち間違えているのに、`string`型に推論されてしまっています。


# 原因

一目で実装の穴にお気づきの方も多いかもしれませんが、単なる条件の網羅不足です。

```ts
type Switch<T> = T extends "number" ? number : string
```

これでは、`"number"`の場合のみ`number`で、それ以外は全て`string`になってしまいますね・・・。

# 正しい条件

以下のように書きます。

```ts
type Switch<T> =
  T extends "number" ? number :
  T extends "string" ? string :
  never
```

読みやすいように改行とインデントを入れてみましたが、あってもなくても大丈夫です。

`never`型の値は存在せず、`never`型の変数に対して代入が成立することはないため（`as`で無理やり成立させた場合は除く）型関数のエラーやswitch文などの網羅性チェックに使用されることがあります。

この修正後の`Switch`型では`"number"`と`"string"`以外が渡された場合には`never`に推論されるので、誤った条件分岐を防ぐことができます。
デコレーターの実験的なサポートは将来のリリースで変更になる可能性がある機能です。 エラー解決法

## 問題
VScodeでAngular書いてると、Component.tsのクラス名がおこられてしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/f51fe40d-7f88-8038-6245-24f4e79946c4.png)

## 解決策
VSCodeのヘッダーから
ファイル→ユーザー設定→設定で出てくる下記画面にてexperimentalDecoratorsと検索すると出てくる項目にチェックを入れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/4ff2db3f-07ab-6984-802d-8fe4cb41feed.png)


解決！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/d0ae8010-3a16-2b7e-9057-e84a9851d8f1.png)
インデックスとは？

ユースケースにもよりますが、通常はこのbooksテーブルのauthorカラムに「一意でない」インデックスを追加し、オプションで外部キー制約を作成するのがよいでしょう。
```rb
create_table :books do |t|
  t.belongs_to :author, index: true, foreign_key: true
  # ...
end
```
# 出典
https://railsguides.jp/association_basics.html#has-many-through%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91:~:text=%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E3%81%AB,true%0A%20%20%23%20...%0Aend

### 気づき
インデックスとはなんだろう？
聞いたことがあるが、使ったことがないので調べてみる
どうして使うのだろうか？

# インデックスとは
* プログラミング言語的な表現をすると(x,α)という形式の配列です。
    ここでxはキー値、αはそれに結びつく情報 実データか、あるいは、それへのポインタを意味します。

* DBMS内にテーブルとは独立に保持されるオブジェクトである。

# インデックス設計
## アプリケーション透過的
インデックスを使うかどうかは、```DBMSに自動的に判断```します。
... 
```単純にデータベース側にインデックスを作成すれば良い。```
... 
```使うハードルは低い。```
...
存在を意識しなくて良いという性質を```透過性```と呼びます。

## データ透過的
テーブルに格納されている```データの中身が影響を受けることがありません```し、```テーブルの構造も変化することはありません```。

## 大きな性能改善効果
インデックスの性能が、```データ量に対して線形よりも緩くしか劣化しないため```。

### 注意点
インデックスを闇雲作っても、効果が出るわけでないことは言うまでもありません。

# インデックスの種類
いくつかの種類があり、またDBMSによっても使用できる種類に差があります。しかし頻繁に利用するインデックスは一種類しない。

それが```B-tree```インデックス

# 出典
https://www.shoeisha.co.jp/book/detail/9784798124704

# 感想
だんだん難しくなってきた。
B-treeインデックスとはなんなのか。
今の所、存在を意識しなくてもいい性質を持っている。ことはわかった。
その後の判断はDBMSにお任せするのか。
CSVエディタとしての秀丸エディタ

# 秀丸、使ってますか？

通称「秀丸」こと [秀丸エディタ](https://hide.maruo.co.jp/software/hidemaru.html) 。
日本語対応テキストエディタの黎明期を支えたであろうソフトウェアでしたが、「最近は無料のVSCodeなんかも便利だし秀丸エディタを使う機会が無いなー」という方も多いのではないでしょうか。

既に愛用されている方からすると大変旧聞に属する話ではありますが、秀丸エディタには **CSV/TSVモード** というとても優れた機能があります。この隠れ名機能をご紹介したいと思います。

(まるで軽量版Excelな風貌の秀丸さん)
![stg_20230304_151009.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164949/73a5369f-bc93-f172-501c-bd788704d280.gif)

# 秀丸エディタのCSV/TSVモードは何が優れている？

CSVやTSVを閲覧・編集するとき、テキストエディタで見るのは不便なこともありますよね。一度Excelにコピペして扱う方も少なくないのではないでしょうか。あるいはVSCodeならそういった用途に向けた拡張機能もあるので、VSCodeで閲覧している方もいるでしょう。

実はもっと簡単に、そして軽快に扱うことができます。そう、秀丸ならね。

さて。
こういった対応は、以下のような問題点により行われていると思います。

- CSVのファイル容量が大きく、Excelで閲覧・編集することが困難
- CSV内の文字コードがUTF-8であるため、Excelで直接開くと文字化けする
- カラムごとの桁が揃っていないので、テキストエディタ上だと対象の値のカラム位置が分からなくなる

秀丸がこれらを解決します。

- ファイル容量問題: 大容量のファイルでもサクッと開くことができる。また一定以上の容量のファイルはページングして開くことができるため、メモリ不足に陥らない
- 文字コード問題: SHIFT-JISでもUTF-8でも何ら問題なく自動判別して開かれる
- カラム位置問題: CSVの各行に応じてカラムを揃えてくれるので大変見やすい

そしてこのCSV/TSVモード、実は10年以上も前に秀丸に搭載された機能であるため、良い意味で枯れており、動作が安定しているのも嬉しいポイントです。

# CSV/TSVモードを有効にする

冒頭で「隠れ名機能」と書きましたが、その名の通り、初めに設定しておかないと有効化されません。

以下のように設定しておきましょう。

メニューバー [その他] > ファイルタイプ別の設定 > [設定のリスト] ボタン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164949/675d1157-852e-79ff-9a13-4a293d361705.png)

[ファイルタイプ別の設定のリスト] ウィンドウ > [設定名一覧] タブ > [新規] ボタン > 設定名 `CSV` と指定し [OK] ボタン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164949/3ebd4489-8c96-fa64-f522-fc5b15cde8b3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164949/24718265-f121-4c19-e335-ac30e2450889.png)

[ファイルタイプ一覧] タブ > [追加] ボタン > ファイルタイプに `.csv` 、適用される設定名に追加した `CSV` を選択して [OK] ボタン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164949/21ecf0a2-e03f-8179-a35e-30dabd740be3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164949/43d90cdf-774c-03bb-9bc9-237bee83150c.png)

[設定名一覧] タブ > 追加した [CSV] 設定を選択して [設定を開く] ボタン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164949/74305888-2ca7-2428-33f9-4a8b5859785e.png)

[タブ] ページ > [CSVモード] を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164949/88c89f5f-efb9-181c-5c4b-a65cd98afdb0.png)

※以下は罫線の表示設定。お好みで。
[デザイン] ページ > [ガイドライン(縦)] [ガイドライン(横)] にチェック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164949/c8a4583a-9a55-5428-fba8-7ffcf7c1d380.png)

以上で、 `.csv` の拡張子のファイルを開くとCSVモードで開くことができます。

TSVモードも流れは同様で、ファイルタイプ別の設定 > [タブ] ページ のところで `TSVモード` を選択して設定を追加して、 `.tsv` とそれを紐づければOKです。

# 最後に

秀丸、久々に使いたくなったでしょうか？

ライセンスを購入してしばらく眠らせてしまっている方は是非試してみてくださいね。

ライセンス未購入の方は、試用もできるので試してみるのもよいのではないでしょうか。ちなみに、一度購入すれば一生有効で、かつ自分が使うPCなら台数制限なしという超優良なライセンスとなっています。登場当時から4000円という金額がずっと変わっておらず、利用者界隈ではこのライセンスの良心性がネタになっていたり。

ではでは、皆様のCSV生活が豊かになりますように。

# 参考リンク

[秀丸エディタの紹介（Ver8.00対応版）(TSVモード,CSVモード)](https://hide.maruo.co.jp/software/hidemaru8/new7.html)
Javascriptにおけるアロー関数とは何か？

### (A). これは普通の関数
```javascript
function hoge1(param) {
  return param;
}
console.log(hoge1('hello.'));
```
### (B). (A)をアロー関数で実装するとこうなる
```javascript
const hoge2 = (param) => {
  return param;
}
console.log(hoge2('hello.'));
```
### (C). (B)のように引数が１つの場合は、さらに簡略化することができる 
```javascript
const hoge3 = param => {
  return param;
}
console.log(hoge3('hello.'));
```
### (D). 引数がない場合はこう
```javascript
const hoge4 = () => {
  return 'hello.';
}
console.log(hoge4());
```

---
### 追記
- アロー関数は、単なるシンタックスシュガーではない。
    - 関数宣言とでは、`this`の参照が違うので注意。
2023年2月振り返り〜追われまくり〜

## はじめに

2023年から再開した振り返り、2月も初めていきたいと思います。
月次の振り返りを書く度に感じるのは、1ヶ月経つの早すぎる。
1月の振り返りしてからあっという間でした、、

## 2023年2月のざっくり何してた？

2月ほんとにあっという間でした、、早かった、、、
半期に1回の評価面談もあり自分のキャリアについて考えたり、
日常業務から機能案を提案してみて全然ダメだったり（でも学びも多かった）、
**試行回数を意識して増やしていた1ヶ月**だったかなと思います。
一方で障害対応に追われ、押し出される通常業務をこなすのに必死だった部分も。

学びという観点では平日は業務に追われ、、土日に何とか確保するといった感じでした。
![](https://storage.googleapis.com/zenn-user-upload/cc36159c9ba1-20230304.jpg)
時間を記録するのを忘れがち、、
業務後は難しいので朝に確保したいところ。習慣づけていきます。
2月読んだ本の中でおもしろかったのはこちらの2冊です。

**①ずっと受けたかったソフトウェアエンジニアリングの新人研修**
ソフトウェア工学というものを知り、開発プロセスを基礎から学び中ですが
こちらは読みやすかったです。

https://www.amazon.co.jp/%E3%81%9A%E3%81%A3%E3%81%A8%E5%8F%97%E3%81%91%E3%81%9F%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%AE%E6%96%B0%E4%BA%BA%E7%A0%94%E4%BF%AE-%E7%AC%AC3%E7%89%88-%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E6%8A%BC%E3%81%95%E3%81%88%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84%E5%9F%BA%E7%A4%8E%E7%9F%A5%E8%AD%98-%E9%A3%AF%E6%9D%91-%E7%B5%90%E9%A6%99%E5%AD%90/dp/4798157562




**②ソフトウェアデザイン 2023年3月号**
エンジニアのキャリアについての考え方が整理されていて個人的に納得感が強かったです。
Denoやthree.jsなど業務では触れない知識も多く、興味関心が広がるきっかけになるなと。

https://www.amazon.co.jp/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3-2023%E5%B9%B43%E6%9C%88%E5%8F%B7-%E6%9D%BE%E5%8E%9F-%E6%B6%BC%E9%A6%99/dp/B0BSL39PXF/ref=sr_1_1_sspa?adgrpid=60120324664&gclid=Cj0KCQiA0oagBhDHARIsAI-BbgcO28xNNVjHPkMT0cp2h9ZPlOE0TKJaqrvUlorlP4nftEDiAjD-klwaAr2jEALw_wcB&hvadid=649115050042&hvdev=c&hvlocphy=1009318&hvnetw=g&hvqmt=e&hvrand=11252765173924946633&hvtargid=kwd-333661144450&hydadcr=27268_14653850&jp-ad-ap=0&keywords=software+design&qid=1677908263&s=books&sr=1-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEyRTVSRVA1UkhVNkw2JmVuY3J5cHRlZElkPUEwOTg0ODgwMjBaRTk5TDBWQjEzTCZlbmNyeXB0ZWRBZElkPUExQUVQWkVaRDhFV0tTJndpZGdldE5hbWU9c3BfYXRmJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ==

①が基礎、②が最新（とまではいかなくても新しい知識）なのかなと
原理原則は引き続き学びつつ、バランス良く学んでいけたらと思います。

## 印象に残ったトピック
**障害、不具合対応に追われた**、、その中でも**リリースは死守した**ことです。
今月はもうこれに尽きます。はい。

システムに不具合や障害は一定つきものだと思いますが、特に発生が多かった月でした。
その中での1件の障害は根本原因が分からず、復旧方法だけわかっているような状態で
起きては復旧させ、、また起きたときに復旧させ、、のイタチごっこしていました。
起きたときのインパクトが大きく、即時復旧が必要なものなので
監視ツールからいつ通知がくるのか気になりすぎて、夢の中でも通知がきて起きるような1ヶ月。
**Slackのスッコココ（公式音）で心拍数が上がる**ような条件反射が身についてしまった1ヶ月でした、、
根本解決はまだなのでこちらは引き続きでございます。押忍。

とはいえ、他の業務も止めるわけにもいかず、追われに追われていましたが
元々設定していたリリース日は死守（うち1件は前倒し!）できました、、ここはほんとによかった。


障害、不具合対応で感じるのは、**根本の設計がいかに大事かということ**、
**根本に辿り着けるように問題を切り分けていく力**をつけたいということです。

> **設計がいかに大事かということ**

変更を加えるときには一定は既存ありきになるので、最初にどのような設計で行うのかが大きく影響するなと実感しています。

> **根本に辿り着けるように問題を切り分けていく力**

今回特に自分の力量が足らないことを感じました。
せめて発生時には即時復旧できるようにと思っていましたが、ずっとそれができるわけではないので
問題を切り分けて、原因にたどり着らねばと。（よくケーキに例えられるやつのイメージです）
ITILでインシデント管理だけではなく、問題管理も学んでいるので
この辺りも更に深めていきたいと思います。

## 終わりに
個人的には先が見えずなかなか苦しい1ヶ月でした、、その分学びも多かった。はず。
おそらく半年後とかに振り返ると良い経験だったと思う系のやつですね。たのしみです。
振り返りを続けるからこそ感じられるものもあると思うので、
来月以降も続けていけたらと思います。ここまで読んでいただきありがとうございました！
[SourceTree] pre-commit hookエラー（husky - pre-commit hook exited with code 127）

### はじめに
M1 Macで`SourceTree`を使っていた際に下記のエラーが発生したので、それの解決方法
`go`言語のプロジェクトではなく、`TypeScript`、`Vue.js`のプロジェクトで起こった。

```bash
.husky/pre-commit: line 4: npx: command not found husky - pre-commit hook exited with code 127 (error)
```

このエラーメッセージは、`npx`コマンドが見つからないために`pre-commit`フックが失敗したことを示しているが、`npx -v`でインストールされていることは確認している。おそらく`anyenv`で入れてる下記が悪さをしていそう。
でも、チームで決めたこのバージョンは変更できない。

```bash
.anyenv/envs/nodenv/versions/16.15.0/bin/npx
```

### 一旦の解決方法
`SourceTree`のContentsの中にある`SourceTree`をターミナルから再起動することで解決した。
起動すると、もう一つターミナルが立ち上がるが一旦そのままにしている。

```bash
open /Applications/SourceTree.app/Contents/MacOS/SourceTree
```
これでCommit、Pushまで出来たことを確認できた。

https://community.atlassian.com/t5/Bitbucket-questions/SourceTree-Hook-failing-because-paths-don-t-seem-to-be-set/qaq-p/274792