OmniAICreator/Qiita-1.07M huggingface dataset:
【アジャイル開発】質とスピードは両立するべし？

どうもこんにちは。

今回は、アジャイル開発の勉強をしている中で興味深いお話があったので紹介します。

読んでいる本はこちらです。

https://www.amazon.co.jp/dp/B088YGLSRJ

# 一般的な感覚

一般的に、
**<font color="red">質を高める</font>ためには<font color="blue">スピードを下げる</font>**
もしくは
**<font color="red">スピードを上げる</font>ためには<font color="blue">質を下げる</font>**
という感覚を持っていると思います。

確かに、大学の受験勉強をしている中で「質の良い勉強をするには時間かかるよ...」と何度思ったことか。でも頭の良い人って「効率良く質の良い勉強」をしているんですよね。もしかして、「**アジャイル開発も同じでは？**」と思いました。

# スピードが質を高める

アジャイル開発において、スピードとは「**リリースの頻度**」です。つまり、「**リリースの頻度を増やすことでシステムの質を高めることができる**」ということです。

書籍で説明されていた例を用いて説明します。

以下のような二つのチームがあるとします。

| | チームA | チームB |
| --- | --- | --- |
| リリース頻度 | 4週間に1回 | 1週間に1回 |
| 前回リリースからの差分 | 大きい | 小さい |
| テストの対象範囲 | 広い | 狭い |
| 影響範囲 | 大きい | 小さい |
| 手戻り発生リスク | 大きい | 小さい |

リリース頻度は4週間に1回のチームAは、一度のリリースに含まれる変更点が大きいため、テストの対象範囲が広くなります。このテストで不具合が発生してしまったら、4週間分の開発したものが全て切り戻されることになります。

一方で、リリース頻度は1週間に1回のチームBは、一度のリリースに含まれる変更点が小さいため、テストの対象範囲が狭くなります。そのため、不具合が発生するリスクは小さくなり、仮に切り戻しが発生する場合でも1週間分の開発分のみを切り戻せば良くなります。

上記の比較からわかるように、**スピードが上がったことで、質も安定する**ことになります。

# 質がスピードを高める

先ほどまでは、「**スピードが質を高める**」というお話でしたが、逆に「**質がスピードを高める**」という観点から説明します。

高い頻度でリリースを行うためには、以下が必要です。

- シンプルな設計を保つこと
- テストが行われていること
- 可読性の高いコードになっていること

## シンプルな設計は難しいけど、開発者にとっては非常にありがたい

システムがシンプルな設計であることで、開発者はよりコーディングやデバッグを行うことができます。（シンプルな設計で多くの要件を満たすシステムを開発するには、優れた設計者が必要です。）つまり、シンプルな設計であることで、高スピードで開発を行うことができます。


## テストが行われていることで質を上げる

次にテストについてです。ここでのテストは、RailsのRSpecやPythonのPytestなどの自動単体テスト、結合試験、総合試験などを含みますが、特に自動単体テストの部分がコードの質を高めると言っても良いと思っています。自動単体テストの質が高ければ、今後のバグの確率も下げることができます。また、プログラミング言語やフレームワークのバージョンアップを行う際にも修正すべきコードを見つけやすくなるため、あらゆる箇所で質の高いコーディング・開発を行うことができます。

## なんだかんだで可読性の高いコードは重要！

最後に可読性の高いコードになっていることです。アジャイル開発において、ソースコードはコードを書いた人のものではなく、チームのものです。そのため、チームの開発者がコードを読んで容易に理解できるコードである必要があります。また、可読性の高いコードであることで、バグが発生する確率を下げることもできます。

上記3点を満たすことで、アジャイル開発の質を高め、スピードを向上させることができます。

# リリース頻度を上げる時の問題

「**リリース頻度を上げることで質を高めることができる**」とお伝えしましたが、もちろん問題もあります。それは「**要件定義・決定のための対話、設計、実装、テスト**」などをそのスプリント内で回す必要があります。

リリース頻度を上げることで範囲は狭くなりますが、その分それぞれの作業が細かくなり、開発フローは慌ただしいものとなリます。

1スプリント内の作業が追いつかなくなることこそ本末転倒となってしまうので、「**どのようにスプリントを回していくか**」はもちろん、「**スプリントが回らなくなってきたらどのように対応していくか**」まで、チームで対話して決めておく必要があります。

# 各スプリントの中で作成物レビューを行うべし

何か新しい機能を開発する際に、短いスプリントを効果的に活かすためには「各スプリントの中で作成物レビュー」を行いフィードバックをもらうことが必要です。

1週間スプリントで開発・リリースを進めていっても、1ヶ月に1回のレビュー・フィードバックだと、**開発し直しのリスクが高まります**。これでは、せっかく短いスプリントで開発をしているのに効果が半減してしまいます。

一方で、各スプリントに対してレビュー・フィードバックの機会を設けても、**システムが動いていない状態ではレビューやフィードバックのしようがありません**。そのため、各スプリントで開発するものは最低限動かすことができるものでないといけません。

# まとめ

今回は、アジャイル開発における「**質**」と「**スピード**」の両立やその問題についてまとめました。

お役に立てたら幸いです。
Blender　辺・面の追加の仕方「"Fキー”と”Jキー”の違い」

## Fキー
- 選択した頂点間に新しい辺や面を作成する
- 2つの頂点を選択してFを押すと、それらの間に新しい辺が作成される
- 3つ以上の頂点を選択してFを押すと、それらの頂点を結ぶ新しい面が作成される
- 既存のエッジループの端を選択してFを押すと、そのループを閉じる新しい面が作成される

## Jキー
- 選択した頂点や辺を最短経路で結ぶ
- 複数の頂点を選択してJを押すと、それらの頂点間に新しい辺が作成される
- 面上で複数の辺を選択してJを押すと、それらの辺を結ぶ新しい辺が作成され、面が分割される
- エッジループを選択してJを押すと、ループに沿って新しい辺が作成され、面が分割される


## 主な違い
| Fキー | Jキー |
|:-:|:-:|
| 新しい面の作成  |  既存の形状を分割する |
| 選択した要素を直接結ぶ  |  最短経路に沿って結ぶ |
| 新しい面を追加するだけ | 面を分割できる |
[Security] CyberAttack

# 攻撃前調査
|名称|詳細|
|:--|:--|
|ポートスキャン|トランスポート層<br>``種類``: TCPスキャン、SYNスキャン、FINスキャン<br>``得られる情報``: ポートの開閉、ポートで稼働しているサービスやバージョン|
|TCPスキャン|３ウェイハンドシェイクを行う|
|SYNスキャン|3ウェイハンドシェイクのうち、SYNだけを送信、SYM/ACKが返るか確認|
|ICMPエコー要求パケット|ネットワーク層<br>``得られる情報``: 稼働しているホスト（ノード、機器、PC等）のIPアドレス|
||![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/64419389-ec7e-35f3-606f-a22016207b22.png)|



## 参考リンク
- [R4A1_PM](https://www.ap-siken.com/kakomon/04_aki/pm01.html)

# 攻撃手法
|名称|詳細|
|:--|:--|
|DNSキャッシュポイズニング|DNSキャッシュ機能を悪用し、偽のドメイン情報を覚え込ませることで、利用者が偽のサイトに誘導される<br>`対策`: DNSSECの導入<br>[R6S41](https://www.ap-siken.com/kakomon/04_aki/q42.html)|
|クロスサイトスクリプティング|Webブラウザ上で攻撃者が用意したスクリプトを実行させる<br>`対策`: HTTPレスポンスヘッダに`X-Content-Type-Options`を設定する<br>`対策`: 入力にHTMLタグがある場合、HTMLタグとして解釈されない文字列に置き換える<br>[R3S37](https://www.ap-siken.com/kakomon/03_haru/q37.html)|
|オープンリダイレクト脆弱性|Webサイトへのアクセス時に、自動的に偽Webサイトに遷移させる<br>[R3A44](https://www.ap-siken.com/kakomon/03_aki/q44.html)|
|クリックジャッキング|Webページ上にリンクやボタンを配置した透明なページを重ね、利用者を視覚的に騙して別操作を誘導する<br>`対策`: HTTPレスポンスヘッダに`X-Frame-Options`などを設定する<br>[R3S37](https://www.ap-siken.com/kakomon/03_haru/q37.html)|
|クリプトジャッキング|PCにマルウェアを感染させ、そのPCのCPUを暗号資産の入手するためのマイニングなどに利用する<br>[R2A41](https://www.ap-siken.com/kakomon/02_aki/q41.html)|
|DNSリフレクション攻撃|送信元IPアドレスを偽装することで、攻撃対象に大量のDNS要求を送る<br>[R4A1_PM](https://www.ap-siken.com/kakomon/04_aki/pm01.html)<br>[R4A36](https://www.ap-siken.com/kakomon/04_aki/q36.html)|
|ICMP Flood攻撃<br>Ping Flood攻撃|ICMPエコー要求パケットを大量に送りつける<br>[R4A36](https://www.ap-siken.com/kakomon/04_aki/q36.html)|
|サイドチャネル攻撃|攻撃対象の物理デバイスから得られる物理量（処理時間、消費電流など）やエラーメッセージから、秘密情報を取得する<br>[R4A37](https://www.ap-siken.com/kakomon/04_aki/q37.html)|
|中間者攻撃<br>MITM攻撃|通信者同士の間に、気づかれないように入り込み、通信内容の盗聴・改ざんを行う<br>[R4A37](https://www.ap-siken.com/kakomon/04_aki/q37.html)|



## 参考リンク
- [R2A41](https://www.ap-siken.com/kakomon/02_aki/q41.html)
- [R4A37](https://www.ap-siken.com/kakomon/04_aki/q37.html)
- [R4A36](https://www.ap-siken.com/kakomon/04_aki/q36.html)
- [R6S41](https://www.ap-siken.com/kakomon/04_aki/q42.html)
- [R3A44](https://www.ap-siken.com/kakomon/03_aki/q44.html)
- [R3S37](https://www.ap-siken.com/kakomon/03_haru/q37.html)
[Business Industry] EDI

# EDI規約
Electric Date Interchange
|名称|詳細|
|:--|:--|
|情報伝達規約|通信に用いるプロトコルに関する規約|
|情報表現規約|データ形式など表現方法に関する規約|
|業務運用規約|どんな情報、情報の訂正方法、エラーの扱いなど業務やシステムの運用に関する規約|
|基本取引規約|検収時期、支払時期、支払方法などEDIにおける法的有効性を確立するための規約|

# 参考リンク
- [令和2秋73](https://www.ap-siken.com/kakomon/22_aki/q73.html)
QAエンジニアを経験して

今から**20年近く前**のこと、　**2006年** から **2007年**の頃でしょうか。

私の職種は **「QAエンジニア」** と伝えたところ、相手からは、「Q&Aエンジニア」なんですかとか（そもそもなんだよ？）の仕事ですか？

とか、的を得ない答えだった。

これは無理もない。


当時の **「QAエンジニア求人」**　は、今と比べ非常に少なく
（少ないではなく、ほぼ0に等しい。システム運用と混同されていることもしばしば。運用しながらテストするような。

あとは、雇用形態が **契約社員**や **長期アルバイト**だった記憶が。）

また、**QA＝テスト**をやる人限定と思われていた時代だからである。もっと遡れば、テストをやる人は新卒かプログラミングができない人、**要はスキルがない人**がやるものみたいな風潮であった。
世間の認識になっているので、当時は胸を張ってQAをやっていますとは言いにくかった。

しかし、今は、**開発プロセスも派生＝プロダクトのリリースを急ぐ**あまり、品質に問題があったりと。（金銭的な損失、サブスクだと解約、不具合の多さで開発やCSが疲弊）

そのこともあり（当然他にも要因はありますが）、QAに対しての考え方やQAが存在しないリスクが浸透するようになり、求人サイトでも職種欄にQAエンジニアが登場したりと知名度が徐々に上がってきました。

一般の職種では、まだまだということもあり、10年ほど前から、Qiitaを書き始め、もっとQAを広めていきたいと思っています。（QA普及活動なのかな）

https://qiita.com/jun2014/items/32ec77be1056f546aada

```lang:目次
1.その前に、そもそも私は、何者かというと。
2.何が楽しいのか？
3.インターネット社会、SaaSで提供されているものが多くなり
4.何を目指すのか、キャリアって
5.現在もQAエンジニアという職種についています。
```

# 1.その前に、そもそも私は、何者かというと。

なんだかんだで、**19年近く**続けていますが、当初は、特にQAエンジニアになろうとも思ってもいなく、楽して生きようなどと考えてた時期もありました。
（もしそんなことを続けていたら今頃どうなっていたか・・・・恐ろしいですが）

地元の文系大学卒業後、地元情報系の専門学校に進学し、2年間（大学卒業して専門学校に進学するの人は当時あまりいなく・・当然と言えば当然か。）、Oracleデータベース科を専攻。SQLやらDBパフォーマンスチューニングを。あわせて、UML、C言語、VB、Javaを学び。8iのSilverを取得（SQLとOracle入門）

専門学校2年目の就職活動では、まだ1990年代後半から続くバブル崩壊の余韻があり、1990年代後半から2000年代前半は一般に　**「就職氷河期」**　と言われ、プログラマーの選考を受けどもどこも不合格となる。書類で落ちることも多く。
20代でも、就職できない世の中なのかと思い込んで。

今のように**オンライン面談**も無く、選考ごとに東京に。
（1週間ほど安いホテルを見つけ就職活動していました。1日に3社受けて、計10社ほど）

また当時、24歳では新卒扱いすることは難しいとも言われた時代でした。

所謂、第二新卒と呼ばれ、新卒と一緒に研修を受けることすらできず、そのまま常駐SEとしてキャリアを積み始めました。先輩の下で指導を頂きながら、まずはコード修正（リファクタのような感じ）

がコードを書くより、テストをやっているほうが楽しいかもと思い、数年後、数少ないQAエンジニアとなりました。
（QAエンジニアでは無くただのデバッカーだったのかもしれません。）

前段でも書きましたが、当時のテスト担当者は、開発できない人がやるものという位置づけだった気がします。

で、ECサイトのQAエンジニアやアフィリエイトサイトのバックエンドQAエンジニア、人材評価会社でのQAチームの立ち上げやテスト会社のテストセンターマネージャー、SETエンジニア、セキュリティエンジニアなど、いろいろサービスや立ち位置は変われども、QAの仕事を続けてきました。

QAにも、いろいろな領域があるため、多くのことを挑戦したいですね。
これからもです。

また今は、**採用業務**も担当しています。

売り手市場でも中途採用の質は下げたくない。当然といえば当然です。単に入社させることにKGIを置いているのか。むしろ離職率を増やすKPIになってしまう恐れがあると思います。

リソースが足りないから人だけ採用して、入社してから考えれば良いなんて言語道断だと思う。例えば、プロのサッカーチームで、人が足りないから誰でもいいよ。なんてことにはならないでしょう。正確なパスも出せない、何回シュートしても決められないような選手に来て欲しいとは思わないはず。

チームが求めている基本をクリアしないと。と私は経験上思っています。入社してもミスマッチになるのは、お互いに良くない。また、教育と育成の違いもきちんと理解すべきである。中途採用に教育？では無く育成ではと。

# 2.何が楽しいのか？
開発エンジニアやデザイナーのように作り上げて評価されるものでもなく。

不具合を見つけても、それが仕事だからねと言われ、逃したらマイナス評価と。なかなかシビアだなと最初は思いました。でも、不具合がたとえ１つでも。
無くなってしまえば、私としてはこの仕事をしててよかったな、楽しいなと思います。

これが原因で不自由な人がいるというのが、よくないこと。また、サービスが停止し運悪く、廃業になる可能性も在るわけで。

企画からQAが入り、仕様のレビューやリリース判断もQAがメインとなり行う。


テスト工程の一部を担うのでは無く、プロダクト全てに携わるのがQAであり、ユーザーからはUXやUI、使いやすさ、思い通りの動作。
提供する側から見ると、不具合による損害や解約をどう防ぐかを考える。この両端がQAの課題であり、成し遂げるものであると思います。

# 3.インターネット社会、SaaSで提供されているものが多くなり
QAエンジニアというのは、もっと貴重な人材となるような気がします。
プロダクト品質って何なのか？リリース品質って、コード品質とは？

考えれば考えるほど品質というものは広く深いものです。と呟いてみました。

# 4.何を目指すのか、キャリアって
VPoEであったり、CTOであったり、QA経験者にもこんなキャリアがあっても良いと思います。
また**CQO**という**CXO**がありますが、出会ったことは今までありません。
この**CQO**を目指すのも良いのかも。と思ったり。また、思い切って**起業する**のもありですね。 東証グロース市場上場を1つとしてロードマップを用意するのもいいかなと。と言いつつ、上場できるのも数パーセントなので、どこまでできるかがあっても。

# 5.現在もQAエンジニアという職種についています。
QAだからQAのキャリアアップでは無くてもと。

https://qatest.hatenablog.com/entry/2018/11/23/213711
GoでURLからクエリパラメータを取得する方法

GoでURLからクエリパラメータの値を取得する方法について、取り上げます！

http://localhost:8080/todos?size=3&prev_id=2 
このようなURLからsizeとprev_idを取り出していく方法を見ていきましょう〜

### 全体のコード
```
func (h *TODOHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
		myUrl, _ := url.Parse(r.URL.String())
		log.Println(myUrl)
  
		params, _ := url.ParseQuery(myUrl.RawQuery)
		log.Println(params)
  
		size, err := strconv.ParseInt(params.Get("size"), 10, 64)
		if err != nil {
			http.Error(w, "invalid size parameter", http.StatusBadRequest)
			return
	}
```

では、順番に説明していきますね。

### 1.　URLの分解
```golang
myUrl, _ := url.Parse(r.URL.String())
```

まず、文字列化したURLをurl.Parse()を用いて、URLを要素ごとに分解します。

### 2.　クエリの取得(map型として）
```golang
params, _ := url.ParseQuery(myUrl.RawQuery)
```

次にURLの「?」以降のクエリ文字列部分を取得します。

RawQueryは生クエリを保持しており、string型です。
例えば、http://localhost:8080/todos?size=3&prev_id=2 というURLの場合、
myUrl.RawQueryはsize=3&prev_id=2となります。

url.ParseQueryはこのクエリ文字列（RawQuery) を解析し、キーと値のペアとしてマップに変換します（map[string][]stringの形式）。
上記の例の場合、map[prev_id:[2] size:[3]]がparams変数に代入されます。

### 3.　取得したクエリの値の型変換
```golang
size, err := strconv.ParseInt(params.Get("size"), 10, 64)
```

params.Get("size")で取得できるsizeクエリの値はstring型です。
そのため、strconv.ParseInt()を用いて、int64に型変換をします。


以上がURLからクエリパラメータを取得する処理になります。
場合によっては、3番の型変換は必要ないかもしれませんね。


### 参考

https://pkg.go.dev/net/url#URL.RawQuery

https://pkg.go.dev/strconv#ParseInt
環境変数の登録方法

(1)
```shell
MYENV=xxx
```
・サブプロセスに引き継がれない。
・別セッションに引き継がれない。

(2)
```shell
export MYENV=xxx
```
・サブプロセスに引き継がれる。
・別セッションに引き継がれない。

(3)
```shell
echo 'MYENV=xxx' >> ~/.bashrc
source ~/.bashrc (このセッションで使うために再ロード)
```
・サブプロセスに引き継がれない。
・別セッションに引き継がれる。

(4)
```shell
echo 'export MYENV=xxx' >> ~/.bashrc
source ~/.bashrc (このセッションで使うために再ロード)
```
・サブプロセスに引き継がれる。
・別セッションに引き継がれる。
#ウルティマオンライン のUO職人サイトの錬成成功率計算( #Javascript #プログラミング )を現バージョンに合わせる方法

**本内容を利用した場合の一切の責任を私は負いません。**

# 概要
下記の通り、補正率が合っておらず、合わせるにはHP変換属性無は2.25、有は0.9にする必要がある。
https://x.com/tw388192/status/1837703362680442963
本記事は合わせる方法である。

# 結論
HTMLにHP変換属性無と有の識別コードがあるので、それを変更する。
それぞれ5コで計10ヶ所。
`<option value="1809">HP変換（属性なし）`の1809を822.5に、`<option value="1906">HP変換（属性）`の1906を809に変更する。

# 内訳
補正率は識別コードを利用して保持している。
識別コードの100未満の桁が補正率の10倍値、100以上の桁は表示値換算種別値になっている。
後者は、例えば、HP増なら上限は5、MP増なら上限は8で、この値から現在値の強度割合を計算できるようにしている。
現在値が2の場合、HP増なら40、MP増なら25で計算が異なるため、これを表示値換算種別値で識別している。
HP変換は上限が15で、命中等(表示値換算種別値8)と同じ。

# 参考
twitterのスクショ分

![HP変換属性有補正率.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397476/377ba003-0216-8589-20bc-5f98847efc46.png)

![HP変換属性無計算.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397476/d76875c7-2b1f-0dce-0870-bd43a4af19dd.png)

![Ultima Online - Nah (Izumo) 2024_09_22 4_23_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397476/14386045-f14a-8525-ac5b-cdd157fd83d5.png)

![Ultima Online - Nah (Izumo) 2024_09_22 9_31_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397476/5004b26c-c32d-e1ff-1a48-a187739459ce.png)

![SAプロパ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397476/052ace70-375f-7ca7-9e58-5d75ca9b067f.png)
ローマ字入力厳しいって

# はじめに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690936/0e4473a0-4710-b6d6-c0ae-8f964d20800f.png)
gitを使ったことある人なら誰しもこんな体験したことありますよね。
そう「git」と打ち込んだつもりがローマ字入力になってて「ぎt」と表示されてしまったこと。
今回はローマ字入力になってちょっとだけめんどくさい事を面白く解決してみました。
（※本記事はMacの場合です）。

# 完成形
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690936/cd406bb5-e941-7fcb-7cda-87a337ab9dca.png)
「ぎt」とターミナルに打ち込み、エンターを押すと某メンズコーチを連想させる「ローマジニュウリョクキビシイッテ」と表示され、次の行から、「git」と打ち込まれた状態に、英語入力で打ち込むことができるようにしました。

# 解決法
.zshrcファイルに以下の関数を追加する。
```zsh
function ぎt {
    #アスキーアートの使用
    toilet -f smmono9 -w 2000 ロ-マジニュウリョクキビシイッテ
    
    # 英語入力に切り替え
    osascript -e 'tell application "System Events" to key code 102'
    
    # 次の行にgitと入力した状態にする
    print -z "git"
}
```
#### ミニ解説
`toilet`という日本語（ひらがなとカタカナ）でアスキーアートを作成できるツールを用いて、言葉を表示します。
AppleScriptを用いて英語入力に切り替えます。
最後に次の行にgitと入力します。

## 手順
:::note warn
toiletをインストールしてない場合は以下をコピーしてインストールしてください。
```zsh
brew install toilet
```
:::
### 1 .zshrc ファイルを開く
```zsh
nano ~/.zshrc
```

### 2 関数を追加する
上記の関数をファイルにコピペしてください。

### 3 ファイルの保存と終了
Ctrl + O で保存し、Ctrl + X でエディタを終了します。

### 4 設定の反映
```bash
source ~/.zshrc
```
# まとめ
今回はエンジニアなら誰しも経験したことのある「ぎt」に直面した時のめんどくさい気持ちを、面白く解決してみました。アスキーアートの部分はおもしろ要素なので、それ以外の部分だけでもぜひ使ってみてください！

# 参考にさせてもらった記事


https://qiita.com/Cj-bc/items/c889264c301e404627f6

https://zenn.dev/asato/articles/149acdcbea4452
WebアプリケーションでStripeを実装する際に参考になったサイト

[株式会社TECH LUCK](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)という会社で代表兼エンジニアをしている齊藤です。

DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご相談をいただけますと幸いです。
以下のような問題に対応することが可能です。
- プロジェクトでRailsエンジニアが足りなくて困っている
- Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
- オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい

また、Railsエンジニアも募集しておりますので、興味がありましたら[弊社HP](https://techluck.co.jp/?utm_source=qiita&utm_medium=article&utm_campaign=myarticle)からご連絡いただけますと幸いです。

# 前提

最近Stripeを触る機会があり、Stripeというサービス自体の全体概要の把握やテスト方法など、実装するにあたり経た過程や参考にした記事をまとめました。

# Stripeの全体概要

Stripeの中にはPaymentやBillingやProductなど色々な概念、オブジェクト、サービスがあります。
これらを全体的に把握しておくのはとても大切なので、以下の記事を参考にして全体概要を知っておくのがよいと思います。

https://tech.actindi.net/2021/03/02/083000


# Stripeの決済の種類

Stripeは決済代行サービスなので決済機能があります。ただ、Payment Links、Invoicing、Checkout、Payment Elementとさまざな決済種別が用意されています。
自分たちでサービスの中に組み込みAPIで決済を行う、決済画面をStripe側で用意してもらいユーザーをそちらに遷移させて決済をさせるなど、さまざまな使い分けができます。
決済種別の詳細と使い分けについては、以下の公式の記事がとてもわかりやすかったです。

https://support.stripe.com/questions/choosing-between-payment-links-invoicing-checkout-and-payment-element?locale=ja-JP


以下の記事はPaymentとBillingの違いと実装の種類について詳細に解説があり参考になりました。

https://norando.net/stripe-specification/


以下の記事はStripe CheckoutとCharges APIとPayment Intents APIの違いについて記載があります。
Chargesは古いAPIになっているので、なるべく使わないようにしましょう。

https://dev.classmethod.jp/articles/stripe-charges-for-paymentintents/


# Stripe Billingの実装方法

以下の記事はStripe Billingの実装方法になります。
これらに目を通せば、Stripe Billingでの実装がデいるようになると思います。

https://qiita.com/y_toku/items/235b5e7ee00792edcbbf

https://qiita.com/yukihigasi/items/f373ce711b30fd55ac69

https://qiita.com/hideokamoto/items/b3557f318182c4fa0c2c

https://docs.stripe.com/billing/subscriptions/build-subscriptions?platform=web&ui=elements


# Stripe Elementについて

以下の記事はStripe Elementの実装方法になります。
とても詳細に書かれているので、Stripe Elementで実装する場合には必ず目を通しておくとよいでしょう。

https://qiita.com/y_toku/items/7e51ef7e69d7cbbfb3ca

# 3Dセキュアについて

3Dセキュアの実装方法やテスト方法が記載されています。

https://qiita.com/rawr/items/8f5f5b3802792eb775c9


# 税金の実装について

Stripe TaxとTax Ratesという2つの機能があります。
Tax Ratesは無料ですが、Stripe TaxはTax Ratesよりも機能が充実していますが有料になります。

https://qiita.com/hideokamoto/items/878a92f325f063c1ae77

https://docs.stripe.com/billing/taxes/collect-taxes?tax-calculation=tax-rates

https://docs.stripe.com/billing/taxes/tax-rates?locale=ja-JP

# Stripe Billigでの定期決済失敗時の処理について

Stripe Billigで定期決済に失敗した場合には、Stripeのダッシュボード画面でリトライの回数、リトライまでの日数間隔などを設定することができます。

https://qiita.com/hideokamoto/items/1f74ec18dcc0b99f835a

https://zenn.dev/yoshimo/articles/5185afc4996476

https://select-type.com/blog/membersystem/member-subs-fail/


# Stripe Billigでの定期決済のテストについて

定期決済の実装で面倒なのはテストになります。
というのも、指定された時間までシステムを動かしてテストして決済がなされるのかどうかなどをテストするのは非常に面倒だからです。
ただ、Stripeではありがたいことにテストクロックというもので、定期決済でのテストを行うことができます。

https://qiita.com/hideokamoto/items/634bde6e3cd577f3b292
仮想ドライブソフト ImgDrive のインストール

ImgDriveは CD/DVD のバックアップを作成するソフトウェアです。作成したディスクイメージは仮想ドライブにマウントすることができます。個人は無料で使うことができ、商業利用の場合はライセンスの購入が必要です。この記事では 個人ユーザ向けに ImgDrive のインストール方法を説明します。

![03_imgdrive.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/d9283838-17e9-f201-3e30-2c47740b6b08.png)
## ImgDrive を使う目的
### ディスクバックアップの作成
物理的な CD/DVD/Blu-ray ディスクをISOイメージとしてバックアップすることができます。ただし、オーディオ CD や映画の DVD/Blu-ray のバックアップには対応していません。

### ディスクイメージのマウント
バックアップされたディスクイメージファイルを仮想ドライブにマウントできます。※最新の Windows 10/11 は標準で ISO マウント機能が組み込まれてます。

### 大量のディスクの管理
大量のディスクを物理的に持ち運ぶ代わりに、ISO イメージに変換することで、パソコンに入れて楽に持ち運ぶことができます。

## ImgDrive のシステム要件
ImgDriveのシステム要件は次のとおりです。

- OS: Windows 7/10/11

ここでは ImgDrive 2.1.9 を例にして、Windows 11 へのインストール方法を紹介します。
## ImgDrive のインストール手順
### ダウンロード
窓の杜の ImgDrive の紹介ページにアクセスし、「窓の杜からダウンロード」をクリックします。
https://forest.watch.impress.co.jp/library/software/imgdrive/

![01_officialsite.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/146fada4-33fa-b4e7-7ef0-59b91ffba99d.png)
### インストーラの起動
ダウンロードが完了したら、ファイルをダブルクリックし、インストーラを実行します。

![11_download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/685c0cfa-9798-6ac1-dee8-4b2d7d111778.png)
### ユーザーアカウント制御の確認
ユーザーアカウント制御が表示されたら、「**はい**」をクリックします。

![13_download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/34716844-8481-416b-d7e6-f7a4a8dcb07f.png)
### ライセンスの同意
使用許諾契約の内容を確認して、「**同意する**」を選択し、「**次へ**」をクリックします。

![21_install.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/1e7870ac-a240-18ed-32bd-6372f9ebec56.png)
### インストール先の選択
インストールするフォルダの選択画面が表示されたら、「**次へ**」をクリックします

![23_install.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/ba9fc860-6c86-a295-056e-dfdbeb800a6b.png)
### インストール終了
ImgDrive のインストール完了画面が表示されたら、「**完了**」をクリックします。

![25_install.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/eacac236-19da-4388-93b5-a5bf698bf721.png)
## 参考文献
- Yubsoft > ImgDrive
[https://yubsoft.com/imgdrive/](https://yubsoft.com/imgdrive/)
Ray.remoteがついたメソッド内で親クラスを参照するとエラーになる

## コード
```python: colab.ipynb
import ray
ray.init()

class A: 
    def add_5(self, a:int) -> int:
        return a + 5

class B(A):
    @ray.remote
    def add_5(self, *args, **kwargs) -> int:
        return super().meth(*args, **kwargs)

ray.get(B().add_5.remote(5))
#^^^^^^^^^^^^^^^^^^^^^^^^^^^
ray.shutdown()
```

## エラー
```.stderr
RayTaskError(TypeError): ray::meth():
  File "colab.ipynb", line 10, in meth
TypeError: super(type, obj): obj must be an instance or subtype of type
```

## 解決策
明示的に`self`を渡す
```python: colab.ipynb
# --snip--
b = B()
print(ray.get(b.add_5.remote(b, 5)))
# 10
```

## 原因
メソッドに`ray.remote`をつけると、そのメソッドはラッパー関数に置き換えられてしまいます。そのため、Pythonが`self`を**自動的に渡してくれなく**なり、引数が不足します。今回の例では、引数が可変長引数だったため、`self`の枠に`5`が入り、`super(B, 5)`となりエラーを吐いていました。
また、可変長引数を普通の引数に置き換えると、更にわかりやすいエラーが出ます。
```python: code.py
import ray
ray.init() 

class Sample:
    @ray.remote
    def meth(self, some):pass

print(ray.get(meth.remote(5)))
#                         ^
ray.shutdown()
```
```.stderr
TypeError: missing a required argument: 'some'
```
RealSenseとOpenManipulator-xをROS2 humbleで動かして物体を掴む

# はじめに
こんにちは、しがない高校生をしているBasalte(ばさると)と申します。
今日はROS 2 humbleを使ってマニピュレーションをした話です。
粗いところもありますので、適宜指摘いただけると幸いです。

### 宣伝
普段はPyLoT Roboticsというチームを立ち上げ、RoboCup@Home Eucationという大会に出場しました！
もしよければこちらのリンクも合わせてご覧ください！！

https://qiita.com/basalte/items/f506e36bf1a34628cc39

# 構成
Openmanipulator-xのグリッパーの上にRealSenseを取り付け、画像認識と物体把持を完結できるようにしています。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【MikataArm 6DOF製作マニュアル(draft)】(6/n)<br>グリッパーの製作①(サーボID17, Link7~Link9)<br>Link7~Link9サブアセンブルに含まれるパーツを3Dプリントし、ウルトラサートの熱圧入や滑り止めの装着を行います。<a href="https://t.co/aOR7T2zjga">https://t.co/aOR7T2zjga</a> <a href="https://t.co/LQ6j1DgDNz">pic.twitter.com/LQ6j1DgDNz</a></p>&mdash; Yoshihiro Shibata (@shiba_8ro) <a href="https://twitter.com/shiba_8ro/status/1778723217882157118?ref_src=twsrc%5Etfw">April 12, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# システム
システム構成です。
Openmanipulator-xとRealSenseを扱うノードをそれぞれ立て、物体認識結果からアームの位置を決定して推移するプログラムです。
使用ライブラリはこちら

https://github.com/IntelRealSense/realsense-ros

https://github.com/ROBOTIS-GIT/DynamixelSDK

https://github.com/OUXT-Polaris/detic_onnx_ros2

いずれも少し改造して使っています。(フォークして色々いじってます)

使用ノードはこのようになっています。
realsense-ros + Detic(+ Clip) + 逆運動学(自作) + DynamixelSDK

raelsenseからのデータはimageとdepthが同時に送信できるrgbd topicを使用しています。使い方などはこちらの神記事をご覧ください。

### Detic+Clipでの画像認識

Deticで汎用的な物体認識を行い、どんな物体が来るかわからない未知環境ではClipを追加して認識物体をチューニングする機能を備えています。
Clipは画像と文章との類似度を出力することができ、Deticでbottleとしか出てこないものでも、そのboundingboxの中身をClipに入力して
"A long, thin red metal cylinder","Water in a blue package"
この二つの文章との類似度をとることによって、コーラか水かを見分けることができます。これにより掴むべきものをより簡単に認識でき、チューニングも簡単に行うことができます。(処理は重いです)

https://ar-ray.hatenablog.com/entry/2023/11/30/083000#google_vignette

自分はOUXTのDeticパッケージを改造してRealSenseからのDepthデータも受け取って3次元座標を計算してtopicで出力しています。

### 逆運動学

最初にロボットアームの各モーターの角度から順運動学を計算し、カメラからの3次元座標をアームの根本からの座標に直します。次にアームの根本から物体の座標を逆運動学(自作)関数に投入し、モーターが取るべき角度を計算して出力します。
本来ならオブジェクトの点群からEndEffectorが取るべき角度も計算したいのですが、使用しているロボットアームに十分な自由度がないため難しいです。
(取得している動画が手元になかったのであとで追加します！すいません！！！)

# まとめ
以上のようにロボットアームが物体を取得するプログラムを組むことができます。
今後実際のコードもこちらで紹介したいと考えているので、更新をお待ちください。

今後も改造のしようがあるため、頑張っていきたいです。

また動作がカクカクしているため、もっと滑らかにモーターの動作の経過を調節するコードも書けたらいいなと考えています。
SpringBoot で TiDB Cloud Serverless に接続する

## TL;DR

ローカルの SpringBoot アプリケーションで TiDB を使ってみた。

## はじめに

TiDB は、MySQL 互換の NewSQL データベースで、昨今いろんな企業が導入しているらしい。

- https://pingcap.co.jp/case-study/
- https://www.publickey1.jp/blog/24/newsqltidbpr.html
- https://speakerdeck.com/leveragestech/tidb-user-day-tidbhayin-nodan-wan-ninarunoka-rehatetukunoke-ti-toxin-tanatiao-zhan-tidb-user-day-2024

私が TiDB を知ったのは ServerlessDays Tokyo 2023 のセッションなので 1 年前になるが、今回重い腰を上げて使ってみた。

<iframe width="560" height="315" src="https://www.youtube.com/embed/cXhPKYp5LKE?si=qJs1fq33y0tzxdTf" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

## TiDB の準備

### 登録

以下にアクセスし、右上の `無料ではじめる` から登録できる。

https://pingcap.co.jp/

必要事項を入力したら、さっそくクラスターが作られている状態になる。

### 必要なものをもろもろ作成する

データベースやユーザーなどを作成する。
左のタブから `SQL Editor` を開き、MySQL のコマンドを使用して作成した。

MySQL コマンドの参考になりそうなものを載せておく。

- https://prog-8.com/docs/mysql-database-setup
- https://www.digitalocean.com/community/tutorials/how-to-create-a-new-user-and-grant-permissions-in-mysql-ja

## SpringBoot の設定

MySQL に接続できる設定であれば良い。
開発段階では、MySQL の Docker イメージを使っている。
ローカルで TiDB を起動する方法もあるらしいが、面倒くさいのでやっていない。
ローカル起動を試したい方は以下を参考に。
https://zenn.dev/koiping/articles/01f62e77d047e6

### 依存関係

Gradle の例なので、Maven の場合は読み替えてほしい。
また、Flyway を使用しているため、Flyway の依存関係も載せている。

 ```
 dependencies {
    implementation("org.springframework.boot:spring-boot-starter-jdbc")
    runtimeOnly("com.mysql:mysql-connector-j")
    runtimeOnly("org.flywaydb:flyway-core:10.18.0")
    runtimeOnly("org.flywaydb:flyway-mysql:10.18.0")
}
 ```

### プロパティ

 ```
spring:
  datasource:
    url: jdbc:mysql://[HOST]:[PORT]/[DATABASE]
    username: [USERNAME]
    password: [PASSWORD]
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimum-idle: 2
      maximum-pool-size: 5
 ```

 ローカルで MySQL に接続したアプリケーションが開発できれば準備完了。

## SpringBoot から TiDB に接続

TiDB の画面で、クラスターの Overview ページが開いている状態にする。
右上の `Connect` を押すと、以下のように接続情報が表示される。

![スクリーンショット (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600771/f98c7b7a-5b70-b1a8-61fa-5bb3d5605d88.png)

`HOST`, `PORT` は先ほどのプロパティにそのまま入れる。
`USERNAME`, `PASSWORD`, `DATABASE` は、[ここ](#必要なものをもろもろ作成する)で作成したものをプロパティに入れる。

プロパティを直接書き直すのではなく、環境変数で設定したっていい。
https://github.com/spring-projects/spring-boot/wiki/Relaxed-Binding-2.0

結論、プロパティをローカルの MySQL から TiDB のものに書き換えるだけで良い。

## まとめ

本当に MySQL 互換だった。
Github に ssh でpushする。

## 目的
Github に ssh でpushする。

## 環境
ubuntu

## 手順
```shell
$ ssh-keygen -t ed25519 -C "example@example.com"
$ ls -al ~/.ssh
...
... id_ed25519
... id_ed25519.pub
$ cat ~/.ssh/id_ed25519.pub
xxx (← ここの文字列を Github にコピペする)
$ eval "$(ssh-agent -s)"
$ printenv | grep SSH_
SSH_AUTH_SOCK=xxx
SSH_AGENT_PID=xxx
$ ssh-add ~/.ssh/id_ed25519
$ ssh-add -l
$ ssh -T git@github.com
...
Hi UserName! You've successfully authenticated, but GitHub does not provide shell access.
```

あとはいつも通り下記のようにpushする。
```
git add .
git commit -m "xxx"
git remote add origin git@github.com:xxx/yyy.git
git push origin main
```
EC2 の インバウンドルールで マイ IP を指定したときは、Wifi を変更するとSSH接続できなくなるので注意。

## 躓きポイント
EC2 の インバウンドルールで、マイ IP を指定したが、いつのまにか Wifi が変わっていたためSSH接続できなかった。

## 確認
WSL2 で下記のコマンドで、自分のグローバルIPアドレスを確認できる。
```
$ curl ifconfig.me
```

## 改善
それぞれの Wifi で使用されるグローバルIPアドレスを確認して、EC2 の インバウンドルールで、使用する可能性のある全てのグローバルIPアドレスからのSSH接続を許可しておく。
インデックスを蔑ろにするからNaNが発生したんだ

# 背景
複数のデータフレームからcsvに出力するようにデータをまとめる処理をしていた時に少しハマったトラブルについて。
調べたらすぐわかるような初歩的なことなんですが、意識していなかったなと反省して記事に残します。

### やりたかった処理

データフレーム1のカラムを指定して、その中のデータと同じデータが存在する行だけデータフレーム2から取り出し、新しいデータフレーム3に格納する。

コードに直すと

```python
df3['新しいカラム'] = df2[df2['ALL_ID'].isin(df1['target_ID'])]['代入したいカラム']
```

こんな感じ。
ALL_IDにはかならずtarget_IDで指定したいIDが含まれており、df2のtarget_IDの'代入したいカラム'のデータをまるっとdf3に'新しいカラム'として代入したいのですが、この処理をするとdf3ではNaNが発生して期待通りになりませんでした。


### 改善方法
reset_index(drop=True)を入れるだけです。

```python
df3['新しいカラム'] = df2[df2['ALL_ID'].isin(df1['target_ID'])].reset_index(drop=True)['代入したいカラム']
```

isin()の処理でインデックスが破壊される(というか元のデータフレームのインデックスをそのまま持ってくる)ので、df1とdf2のそれぞれのインデックスが対応せずにNaNが代入されてしまうと言う話でした。

# まとめ
結局この方法は採用していないです。

上の例でいうとデータフレーム1と2をmergeしてから処理する方が可読性的にもコード書く上でも何回もreset_index書く手間が省けるので。

インデックスのこと蔑ろにすると思わぬところでミスると言う戒めになりました。
You複数拠点のPCを丸ごと同期しちゃいなよ（Parallels編）

# やりたいこと
- 2台のM1 Mac Miniを2拠点に設置する
- Parallelsの仮想ディスク（pvmファイル）をOneDriveフォルダに配置する
- オンライン同期の挙動を検証する

# 結論
::: note
- pvmファイルは実はフォルダでした。
- 起動時とシャットダウン時に、差分ファイルだけをうまくアップロードしてくれました。
:::

# 参考経緯
- [以前のエントリ](https://qiita.com/minoden_works/items/83a811334a6e45dfc498)でHyper-VのVHDXファイルで同じことをしたら、常に更新が走ったりと挙動が不安定でした。

# OneDriveに同期
- Mac一号機のほうでOneDriveフォルダにpvmを移動します。
- OS上のCドライブのサイズ上限は32GBにしてあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/0842c515-6c7f-adad-c92c-5d3173b168b5.png)

- 初回はアクセス権のメッセージが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/0b7034a2-e9d6-6f63-e738-48aba74b41ff.png)

- アップロードが開始されます。
- いろいろなファイルが表示されたのでちょっと驚きました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/b4b99630-d6d5-ef19-4a31-50f91ee03c11.png)

- ブラウザのOneDriveで見ると以下のように表示されていました。
- pvmファイルは実はフォルダだったんですね。
- 15分くらいで完了しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/6186e42f-4e84-24eb-880a-97b3423c5ecf.png)


# 仮想マシンを起動
・Mac二号機のほうでpvmファイルをWクリック。
・[前回のエントリ](https://qiita.com/minoden_works/items/89383d7a135c6e1f5731)の経緯もあり、予想通り普通にOSが起動しました。
・pvsファイル（Parallels Desktop Configuration）とlogファイルが削除されるメッセージが出ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/6ec51c93-e44a-7fba-3a09-bf9c54db72c0.png)


# シャットダウン
・仮想マシンをシャットダウンします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/39e395e5-abdb-4ba0-1e81-56a1ee764604.png)

・メモリ関連らしきファイルが削除されるメッセージが出ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/4235a503-35b9-4230-0d86-83cf4ac28d2d.png)


・hddなどいくつかのファイルだけアップロードが開始されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/f98663ab-32ed-019a-e3a8-ea430bf7c303.png)


・ブラウザOneDriveでは、さっき表示していたままにしていたpvmフォルダが表示できなくなっていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/a9fb690c-af73-4a01-92da-f9c5e328be6f.png)

・改めて開きなおすと、キャッシュや差分データらしきもののみ更新されていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/e37d5f62-15ba-45d1-8f5c-807e95e0067d.png)



# まとめ
・Hyper-Vの時に比べ、差分ファイルのみを同期してくれるので最小限の時間で済みそうです。
・本当に起動とシャットダウンのときだけ更新が走るのかは、もう少し運用してみる必要がありそう。
・Parallelsしか勝たん（通算二回目）
EC2インスタンスにSSHでログインできない（Tera Term）

# EC2インスタンスにログインできない
接続はできるのに、認証でエラーがでていた

## 解決策
Tera Termのバージョンを5以上にした

## 原因
Tera Termのバージョン4ぐらいは rsa-sha2-256 および rsa-sha2-512 プロトコルがサポートされていなかったぽい

以下のサイトを参考にした

https://www.cloudbuilders.jp/articles/3200/
個人開発サービス(Q)のインフラ(AWS)アーキテクチャ

## 概要
2024年春から個人でサービス(Q)の開発を行っています。本ページではサービス(Q)のインフラ(AWS)のアーキテクチャを紹介します。

＊サービス自体は非公開としています。

## アーキテクチャ図
サービス(Q)のインフラ(AWS)についてアーキテクチャは下図のようになっています。

![architecture-aws.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628782/b7a48fee-2df8-0cbe-aa39-77a0cb1e1ecc.png)
サービス(Q)のインフラ(AWS)アーキテクチャ図

## ふりかえり
本サービスはまだ開発の初期段階にあります。
本ページで紹介したアーキテクチャの中で一部はTBDとなっている箇所もありますが、
今後も随時アップデートをしたいと考えています。
Linuxの知識(徐々に更新)

# シェルスクリプトに関する知識
## シェルスクリプトにおける引数の扱い

シェルスクリプトで引数を扱う際には、特定の変数を利用して簡単にアクセスできます。以下は、シェルスクリプトにおける引数を表す変数の一覧です。

| 変数名 | 説明 |
|--------|------|
| `$0`   | シェルスクリプトのファイル名 |
| `$1`   | 1番目の引数 |
| `$2`   | 2番目の引数。以下順に `$3`、`$4`、… `$n` となる |
| `$#`   | 引数の数 |
| `$@`   | すべての引数（スペース区切り） |
| `$*`   | すべての引数（区切りは環境変数IFSで指定されたもの） |


# ユーザーに関するコマンド
## 現在ログインしているユーザーを確認
```
whoami
```
現在、ログインしているユーザー名が出力される。

## 定義されているユーザーを調べる
```
cat /etc/passwd
```
Linuxシステムでは、全てのユーザー情報が/etc/passwdファイルに保存されている。このファイルを表示することで、システムに登録されているユーザーを確認することができる。

## ユーザーを追加する
```
sudo useradd -m -s /bin/bash user_name
```
- `-m`オプションは、ユーザー用のホームディレクトリを作成
- `-s /bin/bash`は、ユーザーのデフォルトシェルを`/bin/bash`に設定
- `user_name` 作成したいユーザー名に書き換える。

その後、`user_name`のパスワードを設定する。
```
sudo passwd postgres
```
# SSH接続設定
LinuxサーバーにSSH接続するためにはサーバー側で設定する必要がある。

## SSHサーバーのインストール
大抵はデフォルトでSSHサーバーがインストールされているがない場合は、openssh-serverをインストールする必要がある。インストールされていればこちらの手順は不要である。

- RedHat系のディストリビューションの場合
```
sudo dnf install openssh-server
```
- Debian系ディストリビューションの場合
```
sudo apt install openssh-server
```

## SSHサーバーの起動と自動起動の設定
SSHサービスを起動します。SSHサーバが起動されていればこちらの手順は不要である。
- RedHat系のディストリビューションの場合
```
sudo systemctl start sshd
```
- Debian系ディストリビューションの場合
```
sudo systemctl start ssh
```
SSHサーバーが自動起動するように設定する。SSHサーバーが自動起動する設定になっていればこちらの手順は不要である。
- RedHat系のディストリビューションの場合
```
sudo systemctl enable sshd
```
- Debian系ディストリビューションの場合
```
sudo systemctl enable ssh
```
SSHサーバーが起動された&自動起動されたかを確認する。
- RedHat系のディストリビューションの場合
```
sudo systemctl status sshd
```
- Debian系ディストリビューションの場合
```
sudo systemctl status ssh
```
そうするとこのような画面が出てくる。
![スクリーンショット 2024-09-22 14.20.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/00dcf207-0320-8ec8-db3b-7fde386508c9.png)

- `Loaded` SSHサービスの設定ファイルのパスと、サービスがシステム起動時に自動的に開始されるよう設定されているか（enabled）を示されている。
- `Active` サービスの状態を示します。active (running)はサービスが正常に稼働していることを意味する。since以下にはサービスが起動した日時が表示される。

## ファイアウォールの設定
SSHのポート(デフォルトで22番)を開ける必要がある。まず、どのポートが空いているかを確認する。
- RedHat系のディストリビューションの場合
```
sudo firewall-cmd --list-all
```
- Debian系ディストリビューションの場合
```
sudo ufw status
```
ここでSSHのデフォルトポート(22番)がアクティブになっていなければ、SSHのポートを開ける必要がある。デフォルトポート(22番)のポートを開ける。
- RedHat系のディストリビューションの場合
```
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
```
- Debian系ディストリビューションの場合
```
sudo ufw allow ssh
```

## ssh接続する
クライアント側からサーバー側にSSH接続するためにはサーバー側のIPアドレスを把握していないといけない。サーバー側のIPアドレスを調べるには下記コマンドを実行する。
```
ip addr
```
実行すると、下記のような表示が出るので
```
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:af:8b:b7 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.10/24 brd 192.168.0.255 scope global dynamic enp0s3
       valid_lft 2592000sec preferred_lft 2592000sec
    inet6 fe80::a00:27ff:feaf:8bb7/64 scope link 
       valid_lft forever preferred_lft forever
```
- `inet` IPv4アドレス
- `inet6` IPv6アドレス

IPv4アドレスを使用してクライアント側で
```
ssh ユーザー名@IPv4アドレス
```
を実行するとSSH接続することができる。
Kotlinの「継承」を学ぶ

# 継承とは何か？
あるクラスが他のクラスの機能を引き継ぐ機能のこと。プロパティやメソッドを新しいクラスを作成する際に、拡張したり、機能を上書き（オーバーライド）することができる。

# Kotlinの継承ルール
Kotlinでは、**デフォルト状態ではクラスを継承することができない**。
継承をするためには`open`キーワードを使ってクラスを宣言する必要がある。

### 継承の例
Animalという親クラスを作成し、それを継承するDogクラスを作成した。
`sound()`メソッドをオーバーライドしており、Dog独自の動作を持たせている。

``` kotlin
// 親クラス
open class Animal {
    open fun sound() {
        println("Animal makes a sound")
    }
}

// 子クラス
class Dog : Animal() {
    override fun sound() {
        println("Dog barks")
    }
}

fun main() {
    val myDog = Dog()
    myDog.sound()  // 出力: "Dog barks"
}

```


- `open`キーワード
クラスやメソッドを継承可能にさせるために使用するキーワード。openをつけないとKotlinでは継承を行うことができないため注意。

- `override`キーワード
親クラスのメソッドを子クラスで上書き（オーバーライド）するために使用するキーワード。

## プロパティの継承
メソッドだけではなく、プロパティも継承して、オーバーライドすることができる。

```kotlin
open class Animal {
    open val type: String = "Animal"
}

class Bird : Animal() {
    override val type: String = "Bird"  // プロパティのオーバーライド
}

fun main() {
    val bird = Bird()
    println(bird.type)  // 出力: "Bird"
}

```


### 抽象クラス
完全に実装されていないメソッドを持つ抽象クラスを定義することができる。`abstract`キーワードを使って定義し、直接インスタンス化はできないようになっている。
抽象クラス内のメソッドはサブクラスで必ずオーバーライドする必要がある。

```kotlin
abstract class Animal {
    abstract fun sound()  // 実装されていない抽象メソッド
}

class Lion : Animal() {
    override fun sound() {
        println("Lion roars")
    }
}

fun main() {
    val lion = Lion()
    lion.sound()  // 出力: "Lion roars"
}

```
PyLoT Robotics 2024 -ハードウェア-

# はじめに
こんにちは、しがない高校生をしているbasalte(ばさると)と申します。
今回はRoboCup@Home Educationに出場した機体のハードウェアについての解説です。

こちらに活動の全体をまとめた記事もありますのでもし良ければご覧ください。

https://qiita.com/basalte/items/f506e36bf1a34628cc39

この完成機がどのような構造になっているのかを説明していきます。
![IMG_4816.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1895796/66ab58c7-2589-e757-b81e-01464061817f.jpeg)


# 土台
足回りのルンバとその上を支えている筐体はこのようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1895796/33369c9e-9a3c-d012-5309-82b5aa2e182a.png)

MDFという硬い木の板と塩ビパイプで制作していて、とても軽く、とても安価です。
・ルンバ中古 1万円
・RPLiDAR A1M8 1万円
・塩ビ、MDF 3000円
という構成です。これなら5台ぐらい作れますね。

こちらのようにルンバをと塩ビパイプを接続するための3Dプリンターパーツを印刷し、取り外し可能となっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1895796/604bd887-5db1-da6e-7a62-671195f204fd.png)

また2段目はこちらのようになっており、2DLiDARと中央のカメラのための塩ビパイプの基盤があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1895796/f3982c26-587f-b4d0-ad86-8d5e410e8911.png)




ちなみに色を付ける前はこのようになっていて、規定の位置にドリルで穴をあけ、接着剤でガチガチに留めます。~~これの前の機体は設計図が無く、私が手で合わせて穴を開けていたことを考えると恐ろしいですね。~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1895796/489747cd-68cd-c687-ef7b-83b1c81059f7.png)



# Openmanipulator-x
＠Shiba_ro8さんの協力でOpenmanipulator-Xの改造を行い、RealSenseが接続でき、把持できる物体の大きさが2倍ほどになりました。
こちらでオープンソースとして公開されています。
<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">おじさんが設計した、だいたい3Dプリンターで作れる深層学習研究用マニピュレーターのOnShapeリンクって、前にツイートしてたっけ？<a href="https://t.co/5svbJCIKwI">https://t.co/5svbJCIKwI</a> <a href="https://t.co/0D1wvY837u">pic.twitter.com/0D1wvY837u</a></p>&mdash; Yoshihiro Shibata (@shiba_8ro) <a href="https://twitter.com/shiba_8ro/status/1762067236855144958?ref_src=twsrc%5Etfw">February 26, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# 頭部
ROBOTISの直交2軸サーボを使い、上下左右にカメラを動かすことができます。今のところ、人を追従する際にしか使えていないので、今後の開発で活躍してくれることと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1895796/d5953dc9-06c8-f4f1-a0d5-96dbf535ebe2.png)


# 改善できる点
### 配線
非常停止用の回路は今度公開する記事をご覧ください。
ただ配線を考慮した設計の機構になっていないので、テープで強引に止めている部分が多いです。
ロボットアームのための配線やシリアルが雑な形で配線されているのはあまり良くないことなので、早急に治したいです。(シリアルは外れたらロボットの動作が止まってしまうので)
### アームの昇降
今後OPLなどの上位リーグに出場する場合、アームの可動域が足りないため、軸数を増やしたり昇降機構をつける必要があります。
ロボットアームの重量が上がると台車の荷重を上げたり機構を見直す必要があるため、簡単ではないですが、今後挑戦したいと考えています。
Make における $$(Command) と $(shell Command) の動作の違い 

ちょっと引っかかったので……

次のような `Makefile` において、$$(Command) と $(shell Command) の動作は異なっています。

```Makefile
LATEST_MD ?= $(shell (ls -t *.md 2>/dev/null | head -n 1))
LATEST_MD2 ?= $$(ls -t *.md 2>/dev/null | head -n 1)

testfile.md:
	@touch testfile.md
echo:testfile.md
	@rm -f testfile.md;\
	echo LATEST_MD: $(LATEST_MD);\
	echo LATEST_MD2: $(LATEST_MD2);\
```

手短に言うと
- \\$(shell Command): Makefile の評価時にコマンドが実行され、その結果を変数に代入します
- \\$\\$ (Command\): これはコマンドタスクの中で実行されコマンドがシェルへ渡される際に評価されます

よってこのコードでは、`LATEST_MD`には最新のファイルが表示され、`LATEST_MD2` は何も表示されないはずです。

## 結果

```
$ make && make echo
LATEST_MD: testfile.md # LATEST_MDの定義時には testfile.md は存在する
LATEST_MD2: # この部分が呼び出される時点では testfile.md は存在しない
```
PyLoT Robotics 2024 -ソフトウェア-

# はじめに
こんにちは、しがない高校生をしているbasalteと申します。
今回は私が1からチームを作りRoboCup@Home Educationに出場したPyLoT Roboticsで開発したソフトウェアについて解説します。
こちらに活動の全体をまとめた記事もありますのでもし良ければご覧ください。

https://t.co/QZzCm7T8UX

# 画像認識
基本的にYolov8を使って開発していました。こちらは簡単に骨格検出と個体識別のトラッキングができるのでとても便利です。
私たちはタスクで使用するバッグと椅子を当日の会場でアノテーションし、学習していました。
また人を追従するための人体識別はYolov8のtrack機能を使用し、背景にいる人の誤検出が起きないようにしていました。

# Openmanipulator-x
大会期間までに開発したのは固定モーションの設定だけでした。
現在は以下のようなロボットアームの制御ができています。
こちらのデモの解説は今後別途記事を書こうと思います。
<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">ハンドトラッキングからロボットアームのテレオペ！ <a href="https://t.co/Hdm2sjRluT">pic.twitter.com/Hdm2sjRluT</a></p>&mdash; basalte(ばざると) (@basalte1199) <a href="https://twitter.com/basalte1199/status/1837067065573974025?ref_src=twsrc%5Etfw">September 20, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

大会期間中はバッグを掴むタスクを行おうとしましたが、認識が不安定で断念しました。大会当日に提示されたバッグの大きさが思ったより大きかったのも原因にあります。


# 音声の入出力
音声入力はWhisperとVoskの二つ、音声出力はtts_rosを使っていました。
いずれもオープンソースになっているものを利用させていただきました。こちらにリンクがあります。

https://github.com/mgonzs13/whisper_ros

https://github.com/redchillipadi/ros2_vosk

https://github.com/mgonzs13/tts_ros

# 中央管理職(笑)
上で作ってた色々をまとめてタスクに落とし込むプログラムのことを中央管理職と呼んでいました。基本的にsurviceでやりとりできるようにして、必要な時だけ同期処理で呼び出すという形を取っていました。
しかしこちらは開発時間の不足や各機能の完成の時間が遅いなどが原因であまり形にならず終わってしまいました。
現在はレストランタスクと呼ばれる注文を受けてデリバリーするタスクを文化祭で実演するなど、状態機会の設計はできています。(でも映像はありません。ごめんなさい)

# マネジメントの反省
あまり大会で良い結果を残せなかった原因には自分の開発計画に不備が大いにあったことが挙げられます。
そもそも私がロボット開発を0から100までやった経験がなく、あまりメンバーを導くことができませんでした。
また、ロボット開発以外のチーム運営や資金集めなどに時間が取られてしまい、ソフトウェアにかける時間が少なくなってしまいました。
今後はメンバーを増やすなど開発リソースを増やす工夫も必要だと感じました。

# まとめ
初めて出場したRoboCup@Homeで、ロボットを動かすことができてとりあえず良かったと感じています。
今後ソフトウェアの練度を上げて再度挑みたいと考えています。
【SwiftUI】Identifiableプロトコルとは？

# 概要
iOSアプリ開発経験はあるのですが、
SwiftUIはあまりやったことがなく修行中・・・！

その際「Identifiable」というプロトコルに出くわした際
理解が難しかったので記事にしました。

## 開発環境
・macOS Sonoma
・Xcode16
・iOS 18


## きっかけ

下記のコードを記載した際にとあるエラーが出てきました。

```sample.swift
// エラーが出たコード
import SwiftUI

struct User {
    let id: Int
    let name: String
    let age: Int
}

struct ContentView: View {
    var users: [User] = []
    
    var body: some View {
        VStack {
            ForEach(users) { user in      // <- ここでコンパイルエラーになる
                Text("\(user.name)")
            }
        }
    }
}
```

そしてコンパイルエラー内容は

```
Referencing initializer ‘init(_:content:)’ on ‘ForEach’ requires that ‘Book’ conform to ‘Identifiable’
```

## Identifiableが必要な理由
どうやらListやforEachの性質にヒントがあったみたいです。
(ヒントになった記事↓)

https://qiita.com/greeny-ryotaro/items/cf363cdda4e7b99bd39c

https://developer.apple.com/documentation/swift/identifiable

実はforEachのような繰り返し処理の場合、SwiftUIはデータの中身を見ないそうです！！

### じゃあどうする？
ではSwiftUIはどのように判別するのでしょうか？

それはデータの中身を見に行くのではなく、
IDなどで識別可能にしておき、
それぞれの要素にアクセスすることが可能となります。

そこで、Identifiableの出番です！

## 改善後のソースコード
Identifiableプロトコルに準拠させることで解決します。

```sample.swift
// IdentifiableでUser構造体のデータを判別させる
struct User:Identifiable { 
    let id = UUID() // 独自のidを実装
    let name: String
    let age: Int
}

struct ContentView: View {
    var users: [User] = []
    
    var body: some View {
        VStack {
            ForEach(users) { user in      // コンパイルエラーが消える
                Text("\(user.name)")
            }
        }
    }
}

```

## Identifiableプロトコルについてもう少し

```Swift
public protocol Identifiable<ID> {

    /// ① 
    /// A type representing the stable identity of the entity associated with
    /// an instance.
    associatedtype ID : Hashable

    /// ②
    /// The stable identity of the entity associated with this instance.
    var id: Self.ID { get }
}
```

①ではIDという名前の関連型を定義しており、
このID型がHashableに準拠している必要があることを意味しています。

:::note warn
Hashable: 
一意性の比較やコレクション（例：SetやDictionary）に使用するため、
IDがハッシュ可能である必要があります。

ハッシュ可能なると、高速なデータ検索や同一性の確認ができます。
:::

②では各インスタンスが一意の識別子を持っていることを保証しています。


やることはシンプルですが、仕組みが少々複雑でしたので
一旦まとめてみました。
MQL4/MQL5の備忘録



# 文字列
## 文字数問題

## なんかよくわからんが駄目
次のワンライナー的書き方は、真似してみたが駄目ポイ　↓　

    ArrayResize(data, StringToCharArray(body, data, 0-1, CP_UTF8)-1 );
WebRequest()で文字化けみたいな結果となることがあった。
配列 data が作り変えられてるということなのかな？

同じ値でも分けて書き直したらば問題なかった↓

    StringToCharArray(body, data, 0,-1, CP_UTF8);    
    ArrayResize(data, ArraySize(data) - 1); 


## SHA1について

* 空文字からの生成は正常にできなさそう。（空文字を渡せないというか）
拙者  空文字で動作チェックしようとして沼ったでござる。

# 通信関連
## socket
* MT5上でのURL登録必須
* ストラテジーテスタ上では使えない

## パイプ （FileOpen）
MT5標準関数では作成はできない。（？？）

## WebRequest()
※ 使ったのは7引数のほう

* MT4上でのURL登録必要
未登録の際のエラーダイアログは出るときと出ないときとある。

* headersに複数ヘッダーを入れる際のセパレータは「\r\n」すなわちCRLF。
参考になりました　→　https://note.com/junico02_se_blog/n/n0eb436a0d493
（実用に耐える条件で現物を載せてくれるのが一番助かります。）
ROS2でハンドトラッキングしてロボットアームをテレオペしてみた

# はじめに
こんにちは、しがない高校生をしているBasalteと申します。
今回は画像認識で手をトラッキングし、ロボットアームをテレオペレーションするデモを解説します。
該当の動画はこちらになります。
<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">ハンドトラッキングからロボットアームのテレオペ！ <a href="https://t.co/Hdm2sjRluT">pic.twitter.com/Hdm2sjRluT</a></p>&mdash; basalte(ばざると) (@basalte1199) <a href="https://twitter.com/basalte1199/status/1837067065573974025?ref_src=twsrc%5Etfw">September 20, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# システム構成
こちらのシステムのハードウェアは
RealSense + Openmanipulator-X
の二つで構成されています。

ソフトウェアはROS2 Humble上で構成されています。
realsense-ros + mediapipe + 逆運動学(自作) + DynamixelSDK
のような構成になっており、この順番にデータが流れていきます。また、使用しているROS2 ノードの数と一致していて、このノード間の通信はtopic通信を使用しています。

# realsense-ros
使用しているrealsense-rosのリポジトリはこちらにあります。

https://github.com/IntelRealSense/realsense-ros

RealSenseからのimageとdepthを同時に受け取ることができるrgbd topicを使用しています。詳細はこちらの神記事をご覧ください。

https://ar-ray.hatenablog.com/entry/2023/11/30/083000

# mediapipe
RealSenseから出てきたデータから手を認識するためにmediapipeという手のランドマークをたくさん認識できるライブラリを使用しています。処理も特段重いわけではなく使い勝手は良いと感じています。

ここでは大きく二つの計算をしています。
・手のboundingboxの面積からGripperの幅を計算
・手の3次元座標からロボットアームのEndEffectorの目標座標を計算

手のboundingboxを出す機能はないので、認識結果の20個ほどあるランドマークの中からx,y最大値とx,y最小値を出すコードを書いています。
この結果からカメラからの距離と合わせてcm単位の四方の辺の長さを計算し、その面積をGripperの幅に線形分布させています。一応Dゲインを入れていますが、あまり振動は治りませんでした。

また手の三次元座標はカメラの視野角とdepth情報があれば求めることができるため、depthを安定させるために複数のランドマークから取るなど工夫をしました。
その情報を手の初期位置との差分をとって、ロボットアームの原点からの座標に変換して出力しています。
tf2などは使用してないです。(わざわざ座標系を合わせるメリットはないので)

# 逆運動学(自作)
以下のように元々物体をPickするために逆運動学を解くコードはできていたので、入力に合わせて対応させるだけで動きました。
<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">コントローラーで逆運動学！ <a href="https://t.co/eZObrplVuI">pic.twitter.com/eZObrplVuI</a></p>&mdash; basalte(ばざると) (@basalte1199) <a href="https://twitter.com/basalte1199/status/1837054777999675455?ref_src=twsrc%5Etfw">September 20, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Mediapipeを実行しているノードから送られてきた目標座標を逆運動学を実行する関数に入力して各モーターの目標角度を出力しています。
Mediapipeの実行周期に依存しており、また計算に時間がかかってしまっていてあまり制御周期を出せていないため少し動作がカクついているように見えます。こちらは今後改善したいです。
またGripperの角度も固定していますが、今後手の角度を取得してそちらも目標座標として送る情報に含めたいです。

DynamixelSDKは送られてきた目標角度をモーターに入力しているだけなので、特に書くことはありません。

# まとめ
今回はハンドトラッキングからロボットアームを動かすデモについて解説しました。
今回作成したプログラムは今後公開する予定がありますので、更新をお待ちください。

また説明に不備があったり不足しているなどしていた場合はコメントなどで教えていただけると幸いです。ありがとうございました。
palworldbreed.com 最新かつ最も包括的なパル（Pal）の配合検索ツールをご紹介します。

「Palworld」ファンの皆様に朗報です！最新かつ最も包括的なパル（Pal）の配合検索ツールをご紹介します。それが[パルワールド 配合検索ツール](https://www.palworldbreed.com/ja)です。

このウェブサイトは、「Palworld」におけるパルの配合に関する情報を簡単に検索できる優れたツールです。ゲーム内の全てのパルの組み合わせ結果を網羅しており、効率的な配合戦略を立てるのに役立ちます。

主な特徴：

1. 直感的なユーザーインターフェース
2. 全てのパルの配合結果を網羅
3. 日本語対応で使いやすい
4. 最新のゲーム情報に基づいて定期的に更新

[PalWorld Breed](https://www.palworldbreed.com/ja)を使えば、希望するパルを効率よく生み出すための最適な親の組み合わせを素早く見つけることができます。また、珍しいパルや強力なパルを入手するためのヒントも得られるでしょう。

パルワールドの世界をより深く楽しみたい方、効率的なブリーディングを目指す方には、このツールが大変役立つはずです。ぜひ一度[PalWorld Breed](https://www.palworldbreed.com/ja)をチェックしてみてください。あなたのパル育成戦略が一気に進化するかもしれません！
読書管理アプリを作ってみた(2) タイムライン機能追加

# タイムライン機能の紹介：書籍の世界を時系列で探索

以前作成した読書管理アプリに「タイムライン機能」を追加しました。

以前の記事についてはこちらから。
https://qiita.com/Hutonman/items/9ccff1856a069ea8fda7

タイムライン機能は、物語の登場人物の時間軸を視覚的に理解することを可能にするツールです。
ストーリーの整理やミステリーの考察に役立てることができます。

## タイムライン機能とは

タイムライン機能は、作品内の出来事や登場人物の行動を時系列で整理し、視覚化するツールです。読者は物語の流れを一目で把握し、複雑なストーリーラインを簡単に追跡できます。

### 主な特徴

1. **キャラクター管理**: 各作品ごとに登場人物を色分けして登録可能
2. **タイムライン管理**: 登場人物の出来事を日単位のタイムテーブルで管理
3. **イベント管理**: タイムテーブル二表示する登場人物の各イベントを管理
4. **柔軟な表示形式**: カレンダービュー（年表示/月表示/日表示）、リストビューの切り替えが可能

## タイムラインの使い方

### タイムライン管理画面
1. 書籍詳細ページから「タイムライン一覧」ボタンをクリック
![](https://storage.googleapis.com/zenn-user-upload/a134bdef162d-20240922.png)

2. タイムラインの一覧を表示

年表示
![](https://storage.googleapis.com/zenn-user-upload/d9a568370019-20240922.png)

月表示
![](https://storage.googleapis.com/zenn-user-upload/3b5282aab51a-20240922.png)

日表示
![](https://storage.googleapis.com/zenn-user-upload/003f770ea8a0-20240922.png)

リスト表示
![](https://storage.googleapis.com/zenn-user-upload/71089a99c46f-20240922.png)


### タイムラインの作成

1. 「新しいタイムラインを作成」ボタンをクリック
2. タイトルと日付を入力して作成

![](https://storage.googleapis.com/zenn-user-upload/73b7303d21b3-20240922.png)


### タイムライン詳細画面

1. 作成した日付の各キャラクターのイベントを管理

![](https://storage.googleapis.com/zenn-user-upload/819511f9440b-20240922.png)

### キャラクターの追加

1. 「キャラクター管理」ボタンをクリック
2. キャラクター名と色を設定
3. 「追加」をクリックして保存
![](https://storage.googleapis.com/zenn-user-upload/f9bc76e50ec3-20240922.png)

### イベントの追加

1. タイムライングリッド上の任意の位置をクリック
2. イベントのタイトル、内容、開始・終了時間を入力
3. 関連するキャラクターを選択
4. 「保存」をクリックしてイベントを追加
![](https://storage.googleapis.com/zenn-user-upload/0ae431a83a88-20240922.png)

## タイムラインの活用方法

1. **物語の全体像把握**: 長編小説や複雑な物語構造を持つ作品の全体像を簡単に理解できます。

2. **キャラクター分析**: 特定のキャラクターに焦点を当て、その行動や成長を時系列で追跡できます。

3. **伏線の発見**: 物語の伏線や重要なポイントを視覚化することで、より深い読書体験が可能になります。

4. **執筆補助ツール**: 作家やストーリーテラーにとって、物語の構造を整理するツールとなります。

## まとめ

タイムライン機能は、読書体験を豊かにし、物語への理解を深める強力なツールです。視覚的に時系列を追えることで、複雑な物語構造も簡単に把握でき、新たな洞察を得ることができます。

ぜひタイムライン機能を活用して、お気に入りの書籍を新しい視点で探索してみてください！
きっと、これまで気づかなかった物語の側面を発見できるはずです！
BFFのAPI設計に必要なもの

## はじめに

BFF（Backend for Frontend）がAPI設計を進めるうえで必要な
フロントエンド（モバイルアプリ、ウェブアプリなど）と
バックエンドの情報を整理する。

## BFF単独で決められること
#### 非機能要件
- パフォーマンス要件
- スケーラビリティ要件
- 可用性要件
#### エラーハンドリング
- エラーレスポンス設計
- エラーメッセージ設計
- エラーログの要件
#### ロギングとモニタリング
- ログフォーマット設計
- モニタリング設計
- アラート設計
#### デプロイメントと運用
- デプロイ手順設計
- CI/CDパイプライン設計
- 運用ガイドライン
#### テスト計画
- テストケース
- テストスクリプト
- テスト環境設計

## BFF単独で決められないこと（= BFF開発に必要な入力）
登場する〇と△は以下のとおり
〇は、入力として有効であり変更（仕様・スケジュール）可能性が低い
△は、入力として有効であるが変更（仕様・スケジュール）可能性が高い

### フロントエンドの成果物
#### 開発スケジュール
- スプリント計画（△）
- WBS（△）
#### UIデザイン
- アプリ要件定義書（〇）
    - アプリの画面設計や機能要件を詳細に記述した文書
- ワイヤーフレーム（△）
    - 低詳細度のレイアウト図
- モックアップ（△）
    -  高詳細度のデザイン図
#### 情報設計（Information Architecture）
- サイトマップ（〇）
    - アプリケーションの全体的な構造を視覚的に表現した図
- ナビゲーションフロー（〇）
    - ユーザーがどのようにページ間を移動するかを示す図
- データ要求仕様書（〇）
    - データの種類、形式、構造、取得方法を記載した文書
#### ユーザシーケンス
- ユーザーストーリー（〇）
    - ユーザーが特定のタスクを完了するためのシナリオ
- ユーザーフロー図（〇）
    - ユーザーがアプリケーションをどのように使用するかを示すフロー図
- シナリオ（〇）
    - ユーザーの行動を詳細に記述した文書

## バックエンドの成果物
#### 開発スケジュール
- スプリント計画（△）
- WBS（△）
#### 情報設計（Information Architecture）
- データモデル図（〇）
    - データベースのスキーマを視覚的に表現した図
- ERD図（〇）
    - データベースのエンティティとその関係を示す図
- APIエンドポイント一覧（〇）
    - 既存のAPIエンドポイントのリスト
#### ユーザシーケンス
- ユーザーストーリー（〇）
    - バックエンドサービスを利用するユーザーのシナリオ
- シーケンス図（〇）
    - APIの呼び出し順序やデータフローを示す図
- ユースケース図（〇）
    - ユーザーとシステムの相互作用を示す図
#### 認証認可の要件
- 認証フロー図（〇）
    - 認証プロセスを視覚的に表現した図
- 認可ポリシー文書（〇）
    - 認可に関するポリシーを記述した文書
- セキュリティ要件定義書（〇）
    - セキュリティに関する要件を詳細に記述した文書

## では、何を作成したらよいか
フロントエンド～BFF～バックエンドを通したAPI一覧を作成する。
項目は以下を想定。

#### フロントエンド
 1. 呼び出し元:
画面だったり画面のボタンを記載
 1. 呼び出しAPI名:
BFFのAPI名を記載

#### BFF
 1. tags:
APIのタグを記載
 1. URL:
BFFのAPIのURLを記載
 1. エンドポイント:
APIのエンドポイントを記載
 1. HTTPメソッド:
使用するHTTPメソッド（GET, POST, PUT, DELETEなど）を記載
 1. フロントエンドからBFFへの引き数:
フロントエンドからBFFに渡される引き数（パラメータ）を記載
 1. BFFからフロントエンドへの戻り値:
BFFからフロントエンドに返される戻り値を記載
 1. 説明:
APIの機能や目的を簡潔に説明
 1. 作成者:
APIの作成者や担当者の情報を記載
 1. 更新履歴:
APIの更新履歴や変更点を記載

#### バックエンド
 1. BFFからバックエンドへの引き数:
BFFからバックエンドに渡される引き数（パラメータ）を記載
 1. バックエンドからBFFへの戻り値:
バックエンドからBFFに返される戻り値を記載
 1. API名:
バックエンドのAPIの名前を記載
 1. URL:
バックエンドのAPIのURLを記載
 1. エンドポイント:
APIのエンドポイントを記載
 1. バージョン:
バックエンドのAPIのバージョン情報を記載
 1. HTTPメソッド:
使用するHTTPメソッド（GET, POST, PUT, DELETEなど）を記載


## まとめ
BFFが開発を進めるには、フロントエンドとバックエンドの情報が必須。
ここでの開発とは、「工数見積り」、「開発スケジュール作成」、「実際の設計・開発」を含む。
得られないレベルにもよるが、
フロントエンドとバックエンドの情報が得られない場合に考えられる対策は以下の通り。
1. コミュニケーション強化
1. 仮設計（プロトタイピング）の実施
1. 仮スケジュールの作成
1. リスク管理と代替案の検討
1. エスカレーション