OmniAICreator/Qiita-1.07M huggingface dataset:
【Notion API × Python】request モジュールで databases、pages、blocks から情報を取得

#
### __【初めに】__
Python の requests モジュールを使用して、Notion API を用いて databases、pages、blocks から情報を取得する手順で詰まったので情報をまとめる。

#

### __【前提】__
https://developers.notion.com/docs/create-a-notion-integration
上記 Notion API 公式ページにて、下記 3step が完了していること。
Step 1: Create an integration
Step 2: Share a database with your integration
Step 3: Save the database ID

Notion API　における databases、pages、blocks の概念の違いはここらへんを参考にしてください
https://developers.notion.com/reference/intro
https://developers.notion.com/docs/working-with-databases

#

### __【ハマりやすい注意点】__
具体的なコード紹介の前に、注意点を紹介
・database ID と page ID は異なる。 
-> ざっくり説明すると、database は各 page の集合体。親:database / 子:page ってイメージ
   取得した json データを見ると、parent / children という情報があると思うのでチェックしてみてください

・databases, pages, blocks のどこから情報を取得したいかで URL が異なる
-> 詳細は下の具体例で確認してください。ここが一番ハマったポイント

・databases は POST、 pages と blocks は GET メソッドを用いる
-> ここもハマったポイントです。よくわからない人は REST API で調べてね

#

### __【databases から情報を取得する方法】__
```python:get_databases.py
import requests
import json

DATABASE_ID = "xxxxx" #Step 3 の方法で取得した　database ID
KEY = "yyyyy" #Step 1 で取得した secret

url = "https://api.notion.com/v1/databases/" + DATABASE_ID + "/query"
headers = {
    "Accept": "application/json",
    "Notion-Version": "2022-06-28",
    "Authorization": "Bearer " + KEY
}

data = {} #ここを上手く使えば一部の情報のみ取得などもできるっぽい。無知なので空白
response = requests.post(url, headers=headers, json=data)

#json 形式の出力を python の辞書型に変換
result = response.json() 

#python の辞書型から json 文字列に変換、その際整形
format_result = json.dumps(result, indent=2, ensure_ascii=False) 

print(result) 
print(format_result)
```

#

### __【pages, blocks から情報を取得する方法】__
```python:get_pages_blocks.py
import requests
import json

PAGE_ID = "xxxxx" #Step 3 の方法で取得した page ID
KEY = "yyyyy" #Step 1 で取得した secret

page_url = f"https://api.notion.com/v1/pages/{PAGE_ID}"
block_url = f"https://api.notion.com/v1/blocks/{PAGE_ID}/children"
headers = {
    "Accept": "application/json",
    "Notion-Version": "2022-06-28",
    "Authorization": "Bearer " + KEY
}

page_response = requests.get(page_url, headers=headers)
page_result = page_response.json()
format_page_result = json.dumps(page_result, indent=2, ensure_ascii=False)

block_response = requests.get(block_url, headers=headers)
block_result = block_response.json()
format_block_result = json.dumps(block_result, indent=2, ensure_ascii=False)

print(page_result)
print(format_page_result)
print("==================================================")
print(block_result)
print(format_block_result)
```

#

### __【終わりに】__
databases, pages, blocks はそれぞれ出力結果が異なるので、
どこの情報の取得が必要かを判断して適切に使い分けてください。

※Notion公式のpythonモジュール 「notion-client」 もあるらしい。
試してみたい方は是非。
(Python3.7 以降のサポート)
https://pypi.org/project/notion-client/
Windows 11 で既定のターミナルを Windows Terminal にしていると PowerShell の WindowStyle -Hidden オプションが動作しない

## 概要
長いタイトルですみません。
**既定のターミナル が Windows Terminal** の場合、PowerShell の **`WindowStyle -Hidden` オプションが動作しない**
という問題が [microsoft/terminal の Issue](https://github.com/microsoft/terminal/issues/12464) に報告されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499004/a70bd025-39e7-948d-6818-c734316962b9.png)

本記事では、既定のターミナルを変更せずに、従来のコンソールホスト(DOS窓)で PowerShell を開くことで、この問題を回避する方法を紹介します。

## 実行コマンド
`conhost.exe powershell -WindowStyle Hidden -command YOUR_COMMAND_OR_FILE`

## 解説
`cmd.exe` や `powershell.exe` を実行すると、内部で 既定のターミナル が呼ばれますが、`conhost.exe` を直接実行することでこの問題を回避しています。

`YOUR_COMMAND_OR_FILE` 部分には、非表示で実行したいコマンドや `.ps1`ファイル へのパスを指定してください。

この方法でいかなる問題が発生した場合も、一切その責任を負いません。ご了承ください。

## 参考記事
[ASCII.jp：Windows 11では標準コンソールの変更が可能になったのでWindows Terminalを設定する](https://ascii.jp/elem/000/004/079/4079062/)
Leetcode 46. Permutations

https://leetcode.com/problems/permutations/description/


## アプローチ
- Backtracking


```java
class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        helper(new ArrayList<>(), new boolean[nums.length], nums, result);
        return result;
    }

    public void helper(ArrayList<Integer> arrayList, boolean[] isVisited, int[] nums, List<List<Integer>> result) {
        if (arrayList.size() == nums.length) {
          result.add(new ArrayList<>(arrayList));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
            if (isVisited[i]) {
                continue;
            }

            isVisited[i] = true;
            arrayList.add(nums[i]);
            helper(arrayList, isVisited, nums, result);

            isVisited[i] = false;

            arrayList.remove(arrayList.size() - 1);
            // arrayListの最後を要素を削除し、次の数値が入れられるようにする            
        }
    }
}
```


### 下記の動画を参考にしました
https://www.youtube.com/watch?v=25alMWqAOLo
CreateProcessによるファイル出力先の引継ぎと対処法

# 経緯
とあるexe(**Called.exe:C#**)でJsonを生成している。そのexeは他のexe(**Called.exe:C#**)から実行される。
以下フローチャートだと、**Called.exe:C#** ではなく、**Call.exe:C++** のディレクトリにJsonファイルが生成される。
(相対パスで生成)
##### Json生成までのフローチャート。
```mermaid
flowchart TB
  call[Call.exe:C++]-->|CreateProcess| called[Called.exe:C#]
  called-->|Load|dll[クラスライブラリ:C#]
  dll-->|create json|.json
```
# 原因
CreateProcessで実行されたプロセスは、引数によって実行元プロセスの作業ディレクトリを引き継ぐため。
lpCurrentDirectoryがNULLだと、作業ディレクトリを引き継いじゃいます。

https://learn.microsoft.com/ja-jp/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa

# 対処法
今回はクラスライブラリでJSONを生成するため、dllをロードしてる**Call.exe:C#**　のディレクトリに生成したい。
方法はいくつかありそうだが、AppDomain.CurrentDomain.BaseDirectoryを使用

https://learn.microsoft.com/ja-jp/dotnet/api/system.appdomain.basedirectory?view=net-7.0#system-appdomain-basedirectory

```cs
string fileName;
string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,fileName);
```

他の方法を使用する状況に直面したら追記するよ。
UnityのImageでImageTypeやFillが見つからないとき

<style>
    .youtube_wrap{
        padding-top: 56.25%;
        width: 100%;
        position: relative;
    }
     
    .youtube_wrap iframe{
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0px;
        left: 0px;
    }
</style>

<h2> 1. はじめに </h2>
<p>UnityのImageを使ってスタミナゲージみたいなものを作ろうとしたところ、<br>
ImageのInspectorからFillの項目が見つからず表示させるのに苦戦していたのでどう出したかを備忘録として残そうと思います。</p>

<img width=300 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600193/2f7ab71f-2d9b-c08c-a63c-e5999e406572.png">

<img width=400 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600193/0eee2e7e-c05c-c7e6-7356-877eb364efcc.png">


<h2>2. 結論</h2>
<p>色々いじってみた結果、Source Imageを設定しないとImage Typeの変更はできない仕様らしいです...</p>

<p>冷静に考えてみれば画像がなければ画像の種類の変更もできないと考えたら、Source ImageがないとImageTypeも変更できないのは妥当かな、という感じです。<br>
こんなくだらない見落としで小1時間かかってしまったためもし同じことで迷ってる方がいればこの記事が参考になれば幸いです。</p>
<p>一緒に自分が作ったスタミナバーのコードど挙動も貼っておくのでもし参考になれば幸いです。ただ、Photonを使用しているためオフラインゲームを開発しているのであればそちらは無視していただいて大丈夫です。</p>

<img width=600 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600193/67d21cac-70ea-a188-fa7c-fe2e65531889.png">
<div style="position: relative; width: 100%; padding-bottom: 56.25%;">
    <iframe width="560" height="315" src="https://www.youtube.com/embed/2CdoTRrJTqI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe>
</div>
ASUS ROG STRIX X670E-F GAMING WIFI のライン入力の音量が不安定になる事象

# 結論
公式のファームウェアアップデートを当てよう！
https://rog.asus.com/jp/motherboards/rog-strix/rog-strix-x670e-f-gaming-wifi-model/helpdesk_bios/
![ASUS ROG STRIX X670E-F GAMING WIFI サポートページ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3328036/7f473d96-fe45-0c11-cfa1-6860a7aaddbc.png)


# 経緯 (読まなくて良い)
新しく組んだPCのお話です。
別のPCの音声をROG STRIX X670E-Fのラインインに入れていたのですが、人の声や音楽の音量が大きくなったり小さくなったりする事象に出会いました。
仕事しつつ、1日格闘して、余計なソフトをアンスコしたり、ドライバを再インスコしてみたりしたのですが、改善せず……
びっくりするぐらい情報が出てこなくて、(初期不良かな……やだな……)と思い始めた頃に、なんとなく公式のBIOSページを見に行ったら、ファームウェアの項目でアップデートが出ていた、というオチです。(ドライバと別ページだった……灯台下暗し。)

頑張ってドライバを探していたのに、ファームウェアの方だったなんて……
あまりに情報がなく絶望してたので、メモとして残しておきます。(マザボが高すぎるというのと、ライン入力を使う人があまりいないというのは要因としてありそう。まあ、私の調べ方が下手だっただけだと思いますが。)

P.S.
(初めてのQiita記事がこんなのでいいのか……？)
NSError. localizedDescriptionの文字列をカスタマイズする

`NSError.localizedDescription`のデフォルトのフォーマットは以下です。

> The operation couldn’t be completed. (\<domain\> error \<code\>.)

日本語だとこうなります。

> 操作を完了できませんでした。（\<domain\>エラー\<code\>）

```swift
let error = NSError(
    domain: "HogeErrorDomain",
    code: 1000,
    userInfo: ["key1": "value1", "key2": "value2"]
)
print(error.localizedDescription)
```

```
The operation couldn’t be completed. (HogeErrorDomain error 1000.)
```

`userInfo`のキーに`NSLocalizedDescriptionKey`が含まれている場合、その値が`localizedDescription`の値になります。

```swift
let error = NSError(
    domain: "HogeErrorDomain",
    code: 1000,
    userInfo: [NSLocalizedDescriptionKey: "value1", "key2": "value2"]
)
print(error.localizedDescription)
```

```
value1
```

<br>

よければこちらも合わせてご参照ください。

https://qiita.com/takehilo/items/cf384e5a3ab2c22163d7

# 参考
https://developer.apple.com/documentation/foundation/nserror/1414418-localizeddescription
DockerでTerraform + Ansibleが動く環境を構築する

## 目的
色々な環境下でTerraformやAnsibleをいちいち構築するのは大変なので、今回はそれらをコンテナ化する。

## 構築
### docker-compose.yml
```yml
version: '3.9'

services:
  terasible:
    build:
      context: .
    image: "terasible:1.0"
    container_name: "terasible"
    working_dir: /etc/terasible
    tty: true
    volumes:
      - "/work/:/etc/terasible"
```


### Dockerfile

```Dockerfile
FROM ubuntu:22.04
RUN apt -y update && apt -y install software-properties-common && apt-add-repository --yes --update ppa:ansible/ansible && apt -y install ansible wget unzip
RUN apt -y install sshpass genisoimage nano vim
RUN wget https://releases.hashicorp.com/terraform/1.5.4/terraform_1.5.4_linux_amd64.zip
RUN unzip terraform_1.5.4_linux_amd64.zip
RUN cp terraform /usr/local/bin

RUN echo "" | echo "" | echo "" | ssh-keygen
RUN cat ~/.ssh/id_rsa.pub

ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" /dev/null

RUN sshpass -p hiyiir ssh-copy-id -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa.pub root@172.24.20.3
RUN sshpass -p hiyiir ssh-copy-id -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa.pub shoma@172.24.20.3
```

## 確認
### ansible
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/1450535b-c0fc-6194-e7d1-85e467624812.png)


### terraform
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/779d9006-c997-5f42-d75b-50878e85253d.png)
4年目SEが「政府情報システムにおけるクラウドサービスの適切な利用に係る基本方針」を読むPart1

## はじめに
初めまして。mirankoと申します。
X(Twitter)でバズっていた、「政府情報システムにおけるクラウドサービスの適切な利用に係る基本方針」について、官公庁向け業務アプリ開発4年目の私から読んでの感想などなどまとめていきたいと思います。
ページ数が多いため、何パートかに分けて投稿します。
本文の引用は最低限としますので、資料を読みつつ見て頂けるととても嬉しいです。

## 参照資料
https://www.digital.go.jp/assets/contents/node/basic_page/field_ref_resources/35d67755-c4ca-4534-94f1-b3c0b51a46fa/4de7c084/20230726_policies_development_management_outline_02.pdf

## 「１ はじめに」セクション

#### ・システム開発に対する知識、それを説明する力の高さ
>一方でクラウドへの移行そのものが目的化されてしまい、必ずしもクラウドサービスの利用メリットを十分に享受できていないといった例も散見された。

この文を読んで、初っ端ですが私は衝撃を受けました。**クラウドサービスのメリットを享受できていないことを情報として何件も持っており、それを課題として認識している**点、それを**分かりやすく簡潔に述べている**点です。クラウド化自体、対障害性の向上などインフラ面が違うというだけの点での利点は勿論ありますが、資料で述べられている通りサーバを必ずしも用意する必要がない、インフラやセキュリティ管理をマネージドサービスに移管するなどの大幅なコスト・工数削減を実現できる利点も大きいです。そういったレベルの話を、国の文書でありながらここまで分かりやすく書いていることに感銘を受けました。システム開発に関する総合的な知識、サービスとして検討する知識が十分ある人の集まりなのでしょう。私もここまでの視点を持てるようになりたいです。


#### クラウドサービスのメリットについて旧新それぞれ説明
旧方針策定時にメリットとしていた可用性、柔軟性などの点と、それからサービスが拡張された現在のメリットをそれぞれ述べています。これがとても読みやすい。従量課金について週末は利用者が少なくコストを削減できるなど、具体例も交えた説明でものすごく説得力があります。
本番サービスの話だけでなく、テストや検証環境についてもかなり述べられていて、**クライアントしてでなくデベロッパー目線まで包括した方針であると感じました。** 今までは「必要経費」としてクライアント側からすると見えにくい検証環境などの費用が、クラウド化によって明確化していくのだろうと思います。同時に、クライアント側もここまでの観点をもってプロジェクトの精査を行う必要があるのでしょう。


## 「２ 基本方針」セクション

#### クラウド・バイ・デフォルト原則は浸透できるか
クラウド上での構築を原則とする、聞こえはいいですが、中々難しいと考えています。その理由は個人情報、機密情報の管理です。先日のニュースでもありましたが、「この情報はここまで晒していい」「この情報はこの頻度で使うからこの置き方がいい」といった仕分けは、国のシステムのような複雑で、簡単に変えられないものだとより難しいです。なぜなら**誰も答えを知らない** 、からだと考えます。
（私の開発しているシステムでもたびたびあります…）
検討するにあたって、「昔から出している情報だけどどのくらい使われているか分からない」など、利用者側と開発者側ですり合わせる必要がある問題が膨大です。しかも、どれをすり合わせなければいけないかは開発する中でどんどん増えていくことでしょう。
クラウド化するにあたって、**情報の扱い方を100%間違わないようにする**ことは切迫した課題だと思われます。


#### モダン技術の利用はどの規模で？
モダン技術、はどの規模で導入を検討するのか、と考えた時、まず考えられるのは新サービスや利用者の限られるサービスでしょうか。新しいサービスや利用者が少ないサービスでは、既存仕様・既存ソースに縛られることなく比較的柔軟に技術選定ができるはずです。ただ、サービスは往々にしてそれ単体で成り立つことは少なく、別のサービスと連携して真価を発揮します。そういった場合、**別サービスとの連携インタフェースはモダン技術が使えるのか、別サービス側の古いフォーマットを踏襲しなくてはいけないのか、といった事象が発生するのではないか**と考えました。
システムはいっせーので変わるものではないですから、こういった古い方に足をひっぱられ、それが技術負債となる問題は解決が一朝一夕ではいかなそうです。

## 「３ 具体方針」セクション
#### SaaSの利用料が増大する場合が追記されている
想定していた利用量とコストの計画が実際と乖離していると、予想外にコストがかさむ恐れがあります。「特に利用料が高額なSaaS」って何なんでしょう？高い処理性能を持つプランやビッグデータ分析インスタンスなどでしょうか？何か事例がありそうです。

#### ベンダーロックインやめろ！
ベンダーロックイン、初めて読んだ単語でしたが、
>ベンダーロックイン（英: vendor lock-in）とは、特定ベンダー（メーカー）の独自技術に大きく依存した製品、サービス、システム等を採用した際に、他ベンダーの提供する同種の製品、サービス、システム等への乗り換えが困難になる現象のこと。(Wikipediaより引用)

とのことです。なるほどこれは本当にやめてほしい。よくあるオープンソース製品の仕様に則っていないベンダ製品は新人目線だと本当に悪です。ネットに情報が全然ないし、妙な独自コマンドを使わないといけないし、かゆいところに手が届かないせいで無駄に独自実装が増えます。デベロッパは自社製品を使うことで「仕様を知っているのはウチだけ」状態にできるので、全部を自社製品で囲い込みます。そうすると変な独自仕様が増え、オープンソースの製品に変えるにしてもコストがかかるのでなかなか踏み切れず、レガシーな仕様が残り続ける悪循環です。
ベンダがSIなど担当する以上発生はするでしょうが、せめて仕様は有名オープンソースと揃えてほしいものです。

#### マルチクラウドやめろ！
これもすごく分かる。会社側の開発基準の都合で、「これを使えと言われたけど現場ではこれが必要」といったケースが発生し、結果別クラウドを立てて中継するといった無駄な作業が発生します。
>技術的な合理性と経済的な合理性を持たないマルチクラウドは厳に避ける必要がある。

とありますが、親会社の都合など必ずしも最適でない理由で乱立するケースは少なくないと思います。
別クラウドどうしをつなぐサービス自体もお金がかかりますし、誰も幸せにならないのでやめたいですね。


## おわりに
Part1はここまで。
ご意見ご感想等コメント頂けますと幸いです！
Rubyのoptparseライブラリの使い方

# はじめに

　Rubyの学習としてカレンダーを作成した際に、オプションで月を指定できるようにするために`optparse`ライブラリを使用したので、使い方をまとめました。

# optparseとは

　`optparse`は、Rubyファイル実行時にオプションを指定できるようにするライブラリです。

# 使い方

### 基本パターン
1. optparseをrequireする
2. OptionParserオブジェクトを生成する
3. onメソッドを用いて、オプションを指定するためのブロックを作成する
4. parseメソッドを用いて、与えられたARGVをparseする

```sample.rb
require 'optparse'
opt = OptionParser.new

opt.on('-a') {|v| p v }
opt.on('-b') {|v| p v }

opt.parse(ARGV)
p ARGV
```
```:実行結果
$ ruby sample.rb 
#=> []

$ ruby sample.rb -a foo -b bar
#=> true
#=> true
#=> ["-a", "foo", "-b", "baz"]
```

### オプションに引数をつける
　onメソッドのオプション定義の末尾に文字列を追加することで、オプションに引数を指定できるようになります。[]で囲った文字列を追加した場合は、引数は任意指定となり、文字列のみを追加した場合、引数は必須指定となります。

```sumple.rb
require 'optparse'
opt = OptionParser.new

#引数を任意指定にする場合(引数として"[VAL]"を追加)
opt.on('-a [VAL]') {|v| p v } 
#引数を必須指定にする場合(引数として"VAL"を追加)
opt.on('-b VAL') {|v| p v }

opt.parse(ARGV)
p ARGV
```

```:実行結果
$ ruby sample.rb -a foo       
#=> "foo"
#=> ["-a", "foo"]

$ ruby sample.rb -a     
#=> nil
#=> ["-a"]

$ ruby sample.rb -b bar       
#=> "bar"
#=> ["-b", "bar"]

$ ruby sample.rb -b   
sample.rb:9:in `<main>': missing argument: -b (OptionParser::MissingArgument)
```

### ARGVの機能
　`optparse`をrequireするとARGVに`OptionParser::Arguable`の機能が加わり、getoptsメソッドを使用して以下のような書き方もできます。

```sample.rb
require 'optparse'
params = ARGV.getopts("a:b:")
p params
```

```:実行結果
$ ruby sample.rb -a foo -b bar
#=> {"a"=>"foo", "b"=>"bar"}
```

# 参考文献

https://docs.ruby-lang.org/ja/latest/library/optparse.html#optionarg


https://docs.ruby-lang.org/ja/latest/class/OptionParser=3a=3aArguable.html
RSpecの基本 モデルスペック

# RSpecとは
RSpecはRubyで作られたテスティングフレームワークです。単体テストや結合テストなどを自動で行うために使います。

## 特徴
RSpecは主に以下の3つの特徴があります。

**可読性**

RSpecのシンタックスは自然言語に近い形でテストケースを記述することが可能であり、結果的にテストケースがそのままドキュメンテーションとしても機能します。

**柔軟性**

RSpecはRubyのフレームワークとして、テストを記述するための多くの方法を提供しています。これにより、開発者はプロジェクトのニーズに応じてテストをカスタマイズすることができます。

**明示的なテストケース**

RSpecは「describe」と「it」を使ってテストケースを明示的に分類し、それぞれのテストケースが何をテストしているのかを明確にします。

## 最も簡単な例
```ruby
describe Calculator do
  describe "#add" do
    it "returns the sum of its arguments" do
      expect(2 + 1).to eq(3)
    end
  end
end
```
ここで、2行目のdescribeはテストの対象となるクラスやメソッドを説明しています。
3行目のitはテストの説明で、RSpecでは1つのテストケースをexampleとも呼びます。
4行目が具体的なテストの内容です。ここで使われるexpectとto、そしてeq（マッチャー）の組み合わせが一つのテストを構成します。

**マッチャー**
expectの返り値をどのように比較するかを定義します。以下にいくつかの例を示します。

eq: 期待する値と実際の値が等しい場合にテストがパスします（==と同じ意味）。
include: 配列などのイテラブルなオブジェクトが特定の要素を含んでいるかをチェックします。
be_valid: モデルのバリデーションが正しく行われている場合にテストがパスします。
be_empty: 配列やハッシュなどが空である場合にテストがパスします。
be_hogehoge: モデル内に真偽値を返すhogehogeというメソッドが存在する場合、それをマッチャーとして使えます。

## モデルスペック
最も基本的なスペック（テストの種類）としてモデルスペックを紹介します。
モデルスペックは`rails g rspec:model user`のようにコマンドで作成できます。

モデルスペックは以下の3つを主にテストします。

- 有効な属性で初期化された場合にモデルの状態が有効になっていること
- バリデーションを失敗させるデータの場合にモデルの状態が無効になっていること
- クラスメソッドとインスタンスメソッドが期待通りに動作すること

以下に、バリデーションをチェックする簡単な例を示します。

```ruby
require 'rails_helper'

RSpec.describe User, type: :model do
  it "is not valid without a name" do
    user = User.new(name: nil)
    expect(user).to_not be_valid
  end

  it "is not valid without an email" do
    user = User.new(email: nil)
    expect(user).to_not be_valid
  end
end
```
1行目はRSpecを書く上で必須です。
それぞれのitブロック内では、name属性とemail属性がnilの場合のUserインスタンスを作成しています。`expect(user).to_not be_valid`はuserインスタンスが有効でない場合にテストをパスするという意味です。このテストがパスするためには、Userモデルに`validates :name, presence: true`のようなバリデーションが正しく設定されていなければなりません。

# 参考文献
Everyday Rails - RSpecによるRailsテスト入門
https://leanpub.com/everydayrailsrspec-jp

以上がRSpecの基本的な説明となります。他にも様々なマッチャーやスペックの種類がありますが、ここでは基本的な部分だけを紹介しました。



## おまけ
User
どこ直した？
ChatGPT
大きな修正点は次のとおりです：

「RSpecはRubyのフレームワークとして、テストを記述するための多くの方法を提供しています。これにより、開発者はプロジェクトのニーズに応じてテストをカスタマイズすることができます。」といった部分では、誤解を招く表現を修正しました。元の文章では「RSpecがRubyのフレームワークである」という誤解を生む可能性がありました。しかし、正しくは、「RSpecはRubyで作られたテスティングフレームワーク」という表現が適切です。

マッチャーの説明で「be_hogehoge」の説明を少し変更しました。元の文章では「モデル内に真偽値を返すhogehogeというメソッドがあるとマッチャーとして使ってくれる」とありましたが、これは完全には正確ではありません。マッチャーは「be_◯◯◯」という形式であり、これは「◯◯◯?」という名前のメソッドが対象のオブジェクトに対して真を返す場合にテストが成功する、ということを意味します。なので、「モデル内に真偽値を返すhogehogeというメソッドが存在する場合、それをマッチャーとして使えます」と改善しました。

RSpecのコード例に言語指定（```ruby）を追加しました。これにより、コードがRubyであることを明示し、シンタックスハイライトが適用されるようになります。

モデルスペックの部分で、コマンドを新しい段落に移動しました。これにより、文が見やすくなり、読みやすくなりました。

全体的に文法や句読点を修正し、文章が自然に流れるようにしました。
AWSのEC2について

AWSサービスの「EC2」について勉強をしたので自身の理解・復習また文章力の向上のためアウトプットさせていただきます。

<h1>EC2とは</h1>
EC2(Elastic Compute Cloud)とは仮想サーバーサービスで、物理サーバーの構築なしで手軽に仮想サーバーを提供できることが強みになります。LinuxやWindowsの仮想サーバを数分で作成可能でスペック変更や削除も容易できます。従量課金で、サーバの起動時間に応じて料金が発生するので必要な際に起動したり不要な際は停止できる点はサービスの強みです。

<h1>EC2の基本的な設定について</h1>
EC2には様々な設定項目が存在しますのでEC2の基本的な設定について説明したいと思います。

<h2>名前とタグ</h2>
インスタンスにはタグを付けることができ、識別・整理するのに役立ちます。

勉強で触った際は「Name」を使用しました。

<h2>インスタンス数</h2>
一度に複数のインスタンスを作成できます。

<h2>クイックスタート</h2>
EC2のインスタンスを簡単に構築するための「クイックスタート機能」があります。
OS・仮想化・サーバー・ストレージが簡単に構築出来ますので面倒な設定の省いてインスタンスの構築が可能です。

<h2>インスタンスタイプ</h2>
インスタンスタイプはCPU、メモリ、ストレージ、ネットワークキャパシティなどを組み合わせたもので、様々なタイプがあります。インスタンスタイプによって価格が変動するため、用途に合わせて適切なタイプを選ぶことが重要です。

インスタンスの作成後でもタイプの変更が可能です。
料金については<a href="https://aws.amazon.com/jp/ec2/pricing/on-demand/" target="_blank">こちら</a>を参照してください。

<h2>キーペア</h2>
安全な接続をするために必要なキーであるpemキーを扱います。

これを使用してインスタンスへの接続が可能です。またインスタンスに接続したい人にこのpemキーを渡せば接続することができます。

<h2>ネットワーク設定</h2>
<h4>ネットワーク</h4>
どのVPCにインスタンスを作成するか選択できます。

<h4>サブネット</h4>
どのサブネット上にインスタンスを作成するか指定します。

*この時に「パブリックサブネット」を選択しないと自動割り当てパブリックIPの設定をしていてもインターネットへのアクセスはできません。

「サブネット」については僕が書かせて頂いた<a href="https://qiita.com/hiro_10/items/4c28b532f6fa12da76d4" target="_blank">AWSのサブネットについて</a>を読んでみてください。

<h4>自動割り当てパブリックIP</h4>
この設定を有効にすると、パブリックIPアドレスをインスタンスに割り当てることができます。また、「Elastic IPアドレス」を割り当てるとインスタンス作成後でもパブリックIPアドレスを保持できます。

ただし、「プライベートサブネット」を指定した場合は「パブリックIPアドレス」を使用できません。

<h4>セキュリティグループ</h4>
セキュリティグループはインスタンスのトラフィック制御に使用されます。同じサブネット内でもインスタンスごとにインバウンド・アウトバウンドのルールの設定できます。

<h2>ストレージ</h2>
インスタンスにはEBS(Elastic Block Store)と呼ばれるストレージをアタッチできます。EC2とセットで利用するのが一般的で、EC2で扱うデータはEBSに保存する構成が基本と言われています。作成後に追加のEBSをアタッチしたり、別のインスタンスに移動させることも可能です。

<h1>思ったこと</h1>
今回はEC2の勉強内容について書かせて頂きました。

とても便利なサービスだなという印象です。
いろんな設定ができ便利な面がありますが反対にタイプ別の起動時間の料金の違いやインスタンスの各設定の方法など理解しないと不本意な料金が発生してしまったり、インターネットにアクセスできなくなりサービスが提供できないなど理解・勉強が必須の内容に感じました。

最後まで読んでいただいた方、ありがとうございました。
manim で区分求積のアニメーション

# はじめに
速さと距離の関係をアニメーションにして示したかったので、manimで作ってみました。

コードはjupyter notebook（あるいは、google colab（後述））で動かしてください。notebook以外では1行目のマジックコマンド（%%で始まるやつ）が使えません。

# gif
![RiemanIntegral.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3525137/c906b717-7ec2-5baa-34ad-4bb944488485.gif)

（色がおかしく見えるので、youtubeのリンクを貼っておきます。
https://www.youtube.com/watch?v=KiGbJkFSgHw ）

# コード
自分の環境がある人はコピペするだけで使えます。

```python:RiemannIntegral
%%manim -qm RiemanIntegral

class RiemanIntegral(Scene):
    def construct(self):
        axes = Axes(
            x_range=[-0.5, 5],
            x_length=8,
            y_range=[-0.5, 10],
            y_length=7
        ).add_coordinates()
        
        axes_labels = axes.get_axis_labels(
            MathTex("t").scale(1), MathTex("v").scale(1)
            )

        graph = axes.plot(
            lambda x: 0.4*(x-1) * (x-3) * (x-4) +6,
            x_range=[-0.5, 5],
            color=YELLOW
        ) 
        
        graph_label = axes.get_graph_label(
            graph=graph,
            label=MathTex("v(t)")   
        )        
        
        self.add(axes, graph, axes_labels, graph_label)


        #dividing setting
        dx_list = [4, 1, 0.5, 0.3, 0.1, 0.05, 0.01]
        rectangles = VGroup(
            *[
                axes.get_riemann_rectangles(
                    graph=graph, 
                    x_range=[0, 4],
                    dx=dx,
                    stroke_width=0.1,
                    stroke_color=WHITE, 
                )
                for dx in dx_list
            ]
        )

        


        first_area = rectangles[0]
        for k in range(1, len(dx_list)):
            new_area = rectangles[k]
            self.play(Transform(first_area, new_area), run_time=2)
            self.wait(0.5)

        self.wait()
```
コードの説明については、私も完全に理解しているわけではないので省略します。pythonの文法を知っていればなんとなくわかると思います。
質問があればぜひしてください。私がわかる範囲で頑張って答えます。

# google colabで使うために
自分のパソコンに自分の環境を作るのは少し手間がかかるので、google colabでの使い方を説明します。
google colabを使うにはgoogleアカウントが必要なので持っていない方は作成してください。


https://docs.manim.community/en/stable/installation/jupyter.html#google-colaboratory に書いてあるコードをコピペしてgoogle colabで実行するだけです。
>以下、引用
>```:
>!sudo apt update
>!sudo apt install libcairo2-dev ffmpeg \
 >   texlive texlive-latex-extra texlive-fonts-extra \
 >   texlive-latex-recommended texlive-science \
 >   tipa libpango1.0-dev
>!pip install manim
>!pip install IPython==8.21.0
>```
このコードを実行した後、新しいセルで次のコードを実行する：
>```
>from manim import *
>```


実行した後はセルに上のセクションのコード（RiemannIntegral)をコピペして実行してください。




# 参考文献
manimの公式サイトに使い方は載っています。

https://docs.manim.community/en/stable/reference.html

かなりお世話になったyoutubeチャンネルです。ただし、少しversionが古いので使えないものもあります。公式サイトできちんと確認しておくようにしましょう。

https://www.youtube.com/@BrianAmedee
【React】トーストUIの作り方

## トーストUI


```tsx:Toast.tsx
import {
  CheckCircleIcon,
  XCircleIcon,
  XMarkIcon,
} from '@heroicons/react/24/solid'
import IconButton from '../Buttons/IconButton'

type Props = {
  isOpen: boolean
  children: React.ReactNode
}

export default function Toast({
  isOpen 
  children,
}: Props) {
  if (!isOpen) {
    return null
  }

  return (
    <div
      className="flex items-center fixed bottom-0 left-0 md:bottom-7 md:left-7 w-full px-6 py-4 md:max-w-sm md:px-4bg-gray-900 text-white md:rounded md:shadow-lg md:shadow-gray-500"
    >
        <div className="mr-3 inline-flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md bg-emerald-100 text-emerald-700">
          <CheckCircleIcon className="h-6 w-6" />
        </div>
        {children}
        <IconButton type="button" className="ml-auto" onClick={onClickXMark}>
          <XMarkIcon className="h-5 w-5" />
        </IconButton>
    </div>
  )
}

```

```tsx:sample.tsx
import { useState } from 'react'
import Toast from '@/components/Toast'

export default Sample() {
  const [isToastOpen, setIsToastOpen] = useState(false)

  return (
    <button onClick={() => setIsToastOpen(true)}>トーストを表示</button>
    <Toast isOpen={isToastOpen}  onClickXMark={() => setIsToastOpen(false)}>
      トーストのサンプル
    </Toast>
}

```
Ctrl + Alt + 矢印キーで画面が回転する【PhpStorm】

![shortcut_phpstorm_windows.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/d701cf53-940e-ce26-fa09-b605e9cd7638.png)


ショートカットキーが競合するので無効化しましょう


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/ca83664d-6c3b-a6fd-d09a-24ad9719ab67.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/829c7e26-e381-51eb-d93b-76f1ad38891e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/3cabc5ef-e5d3-d44f-6328-6f083c2da3e0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/7a554344-fd53-613d-a3f5-df025934ce0d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/cff0619d-a0c2-39ab-d638-1caeb4d74795.png)



https://manabisystem.com/how-to-disable-intel-hd-control-panel-shortcut/
enumが列挙型だから、enumのコンストラクタは暗黙的にプライベートになり、外部からのインスタンス化ができない件について



# :mag_right:enumが列挙型だからと言われてもピンとこない




:::note
**enumは列挙定数を表現するために使用されることが多く、その定数はプログラム内で固定された値として利用される
新しいインスタンスを生成することができると、enumの特性を損なう可能性がある**
そのため、enumのコンストラクタを暗黙的にプライベートにして、外部からのインスタンス化を禁止している
:::

例えばこんなenumがあったとする
```java
enum DayOfWeek {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
}
```

> enumは列挙定数を表現するために使用されることが多く、その定数はプログラム内で> 固定された値として利用される

例のenumは曜日を表現するものであり、定数は固定された値である

> 新しいインスタンスを生成することができると、enumの特性を損なう可能性がある

もし新しいインスタンス（曜日）を生成できてしまうと困るよねということ

> そのため、enumのコンストラクタを暗黙的にプライベートにして、外部からのインス> タンス化を禁止している

新しい謎曜日が増えてしまうことを防ぐためにもこうなっている


</details>
時系列データの分割

# この記事の目的
時系列データの分析をするとき、「ルーティン作業から出てくる時系列データを、各ルーティン毎のデータに分けたいな…」いう悩みが職場で声が上がったので、pythonを使ってちょちょいのちょいって感じで解決したので記録として残します（すぐ忘れそうなので）。

# 具体的にはどのようなデータ？
例えば、製造業では製品を作る際、プラントが稼働しています。超ざっくりですが、1回分の製造過程のことを１バッチといい、１バッチの製造ではいろんな工程が存在します（反応工程、濾過工程など）。
この各工程には工程Noといって番号が振り分けられています。この番号を使って、大量の時系列データからバッチ毎のデータを横並びにしよう！というのが今回です。
じゃあ、どのようなデータなのか？ということで今回もサンプルデータを作成してみましょう。

```python
import pandas as pd
import numpy as np
# カラム名を決める
column_names = ['date', 'AA', 'BB', '工程No']
# 時系列データの期間を設定
dates = pd.date_range(start='2020-05-23 00:00:01', end='2020-05-25 00:00:01', freq='S')
# 'AA'と'BB'にはランダムなfloat型の数字を生成
np.random.seed(0)  # for reproducibility
AA = np.random.rand(len(dates))
BB = np.random.rand(len(dates))
# 工程Noには1から15の数字を連続で入力し、それを繰り返す
工程No = np.tile(np.arange(1, 16), len(dates) // 15 + 1)[:len(dates)]
# データフレームを作成
df = pd.DataFrame(data=zip(dates, AA, BB, CC), columns=column_names)
df
```
今回は自力で作成しました。
どのようなデータか見てみましょう。

![koutei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/6ef29488-a85d-8d61-6a34-6e3d685dbbba.png)

このように'工程No'というカラムは1から15までの数字が連続して入っており、15が入力されたあとは再び1から番号がついているというデータです。
本当はもっと複雑ですが、今回はイメージしやすいようにこのようなデータとしました。
この工程Noが15→1に切り替わる瞬間がバッチが切り替わる瞬間と捉えていただければと思います。
では、このデータをバッチ毎に横方向に並べていきましょう。

# コードを書いていく

まずは必要なライブラリをインポートして、データを読み込みましょう。
```python
import pandas as pd

data = pd.read_csv('ファイルのパス')
```
今回はバッチ処理を行うため、データセットを小さなチャンクに分割し、各チャンクに対して処理を行い、最後に結果を結合します。

```python
def shift_rows_optimized(df):
    dfs = []
    
    while len(df) > 0:
        df_diff = data['工程No'].diff().abs()
        shift_index = df_diff[df_diff >= 4].index

        if len(shift_index) == 0:
            dfs.append(df)
            break

        first_shift_index = shift_index[0]
        remaining_df = df.loc[first_shift_index:]
        df = df.loc[:first_shift_index - 1]   # -1を入れてエラーが出たら消してください。

        dfs.append(df)
        df = remaining_df

    return dfs

dfs_batches = shift_rows_optimized(data)
dfs_batches
```
ここでは、工程Noのデータの各行で差分を取り、その絶対値が4以上のとき1バッチ分としてdfsというリストに追加しています。
絶対値が4以上とした理由は、工程Noが連番でない場合を想定して、大きめに設定しているだけです。
実行することで、各バッチのデータが得られます。

次は、これを横方向に結合します。
```python
dfs_dropped = [df.dropna().reset_index(drop=True) for df in dfs_batches]
df_concat_dropped = pd.concat(dfs_dropped, axis=1)
df_concat_dropped
```
各バッチに分割しましたが、インデックスが維持されたまま、分割されるので欠損値を含むデータになってしまいます。
例えば、2バッチ目のデータは、元データのインデックスを維持したまま、2バッチ目の部分のみ抽出してくるので、1バッチ目と3バッチ目以降のデータは欠損値となります。
そのため、欠損値を削除したうえで結合する必要があります。

# 完成

![kansei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/f9cbc010-d4e7-358c-1997-5678afee4cb1.png)

ということで完成しました。
バッチ毎に分割できていますね。
これで、問題が発生したバッチデータを見つけやすくなりますし、バッチ毎の特定の工程のデータをフィルタリングしやすくなりました。
カラム名とかは適宜変える必要がありますけどね…
お疲れさまでした！！！

# まとめ
ここまでご覧いただきありがとうございます。
今回書いたコードですが、以前はopenpyxlを用いて処理していました。
そのコードもほとんどは同僚が完成させたものだったので、ほかの方法を見つけたいといったのがきっかけです。
私自身pandasしかやってないので、なんとしてもpandasを使いたかったってのもあります。

結果が同じであれば、どっちでもいいとは思いますが、コードを管理していく上では理解があるものを手元に置きたかったのです。

ということで今回は時系列データの分割についてでした！
これからも、データ処理の記録をつけていこうと思います。
それでは！！！
【GA4キャッチアップ】探索を活用したユーザー数の推移の分析

## ユーザー数の推移

### ◆結果のPDF

![ユーザー数の推移_page-0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/781232/7f30d3a7-ca44-c7dd-fcc9-fbf0d237b217.jpeg)


### ◆設定内容(項目別)

〇変数
1. 日時を任意に設定
2. 指標にアクティブユーザーをインポート

〇タブの設定
1. ビジュアリゼーションを折れ線グラフに設定
2. 粒度は任意（PDFでは週で表示）
3. 値にアクティブユーザーを設定
4. 異常検知をonに指定

### ◆このレポート・分析の意義
ユーザー数のような重要な指標を推移で追い、異変があれば流入経路等のディメンションを追うのは分析の定石。

## 予備知識
### 異常検知
自由形式レポートで折れ線グラフを選択したときに使用できる。
統計的推測に基づいている。
例えば、統計的に予想される値を変数として設定した値が上回った場合に異常として検知できる。
セグメントやフィルタを適用して異常をもたらした原因を特定することができる。
[速習] ドメイン駆動設計 最新 GPT-4 32kを使用した設計手法について

![c05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3521573/6cc17903-9d1a-aeab-2629-baff058f039c.png)

## GPT-4 32k

大規模なコンテキストサイズにより複雑なタスクを破綻せずに実行することが可能となりました。これを利用し、ドメイン駆動設計(DDD)のプロセスをGPT-4 32kを使用して実現したいと思います｡これは、あくまで思いつきによる実験ですが、32kの可能性を探求する一環として、その結果は大いに意義があると考えています。

---

<script defer class="speakerdeck-embed" data-id="3e242e456d124d82ae4e74b6895cb864" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>

---

https://note.com/happyodangoo/n/n672397443356

## ステップの解説

GPT-4 32kを使用したドメイン駆動設計(DDD)[^1]のプロセスは次のように進行します。

まず、DDDの基本的な概念と価値について理解を深めます。次に、ビジネスの要望を要求として捉え、それを具体的な要件に翻訳します。この要件を基に、ドメイン分析[^2]を行い、ビジネスの領域を理解します。その結果を反映して初期のクラス図を作成します。

その後、ビジネスのコア領域を特定し、追加の要求を明確化します。これらを反映した更新版のクラス図を作成します。このクラス図に基づいて、ビジネス要求に基づいたエンティティ[^3]を提案します。

ビジネス領域の専門家と開発者が共有するユビキタス言語[^4]を作成・使用します。この言語は、ビジネスの要件を正確に表現するための用語集となります。そして、不変性を持つ値オブジェクト[^5]を提案します。エンティティ間の関係性を定義し、ビジネスプロセスにおける重要なイベントを特定します。

これらの情報を基に、トランザクションの境界を定義するアグリゲート[^6]を設計し、ビジネスロジックをカプセル化するドメインサービス[^7]を提案します。システムを論理的に分割する境界線(バウンデッドコンテキスト[^8])を定義し、ビジネスルールや制約を表現するポリシーを定義します。ここで、コンテキストマッピングを行い、システム全体のコンテキストとそれらがどのように相互作用するかを理解します。

実装に移る前に、DDDの原則に基づいた実装方針を定義します。エンティティの永続化を担当するリポジトリのインターフェースを設計し、複雑なエンティティや値オブジェクトの生成を担当するファクトリを設計します。その後、エンティティと値オブジェクトの具体的な実装を設計します。

https://note.com/happyodangoo/n/n7cbbf5b65c13

## おわりに

GPT-4 32kを用いたDDDの適用方法についての説明でした。GPT-4 32kの大規模なコンテキストサイズを活用し、設計プロセスを効率化、設計と実装の間のギャップを最小限に抑えます。これにより、開発者はドメインの複雑さを容易に理解し、それを反映した設計を効率的に行うことができます。

この記事が、可能性とその適用方法を理解する一助となれば幸いです。GPT-4 32kを用いることで、開発プロセスが大幅に効率化され、新たな開発体験が実現します。これからも、LLMの進化とその応用に注目していきましょう。

https://qiita.com/ShigemoriMasato/items/6311a8362f0fd27e6af6

[^1]: DDD: ビジネスの複雑性を理解し、その複雑性を反映したソフトウェアを設計するためのアプローチ。
[^2]: ドメイン分析: ビジネス領域を理解し、その特性を把握する活動。
[^3]: エンティティ: ドメイン内の概念を表すオブジェクト。独自の識別子を持ち、その状態と振る舞いがビジネスルールにより制約される。
[^4]: ユビキタス言語: ビジネス領域の専門家と開発者が共有し理解するための共通の言語。
[^5]: 値オブジェクト: エンティティとは異なり、自身の属性によってのみ特定されるオブジェクト。不変であることが一般的。
[^6]: アグリゲート: 一貫した変更の単位となるオブジェクトのクラスタ。トランザクションの境界を定義する。
[^7]: ドメインサービス: 特定のエンティティや値オブジェクトだけでは表現できないようなドメインの操作やビジネスロジックをカプセル化する。
[^8]: バウンデッドコンテキスト: ドメインモデルを分割する論理的な境界。それぞれのバウンデッドコンテキストは、それ自体が一貫したドメインモデルを持ちます。
PF作成：2日目

今日で２日目。計画からやるのは初めてで進捗状況があまり良くなくて焦るが地道にやっていこう。

## 進捗
- テーマ課題のサイト名変更（御朱印手帳→修験道）
- テーマを決めた理由を変更（長すぎたかも）
- WBSの下書き
- seedを使用して全国の神社・仏閣のデータを入れようとしたが個人ではダメだと返答があったので計画変更
- テーマ課題提出（返信なし）

## WBS
- 実装機能リストを元に詳細を書き出して、実装する順番に並び替えてみた
- 書き出した実装機能リストに肉付けをした
- 必要なgemを書き出した
- 自分なりにほぼ完成したと思うので明日テーマ課題次第で提出したい


## 苦労したポイント
###### 【テーマ課題】
- テーマ課題のテーマを選んだ理由。どうしても冗長になってしまう。

##### 【WBS】
- 全国の神社・仏閣のデータをもらえなかったので手作業でやるしかない。そのため管理者が神社・仏閣の情報を投稿してそれに関連していたらユーザーが御朱印を投稿できるシステムに変更。ない場合はユーザーに神社・仏閣のデータを投稿してもらわないといけなくなった。それに関連して誤った情報が表示されないように管理者の許可制に変えて、御朱印の投稿だけは投稿できる仕組みに変更。これらの組み合わせが難しい。
- 管理者が神社・仏閣を投稿するにあたって地方、都道府県、神社・仏閣の情報などとユーザーの投稿する御朱印の関連付けが実装に一番時間がかかりそうなので余裕を持って取り組もう。


## ヒント
##### 【テーブル】

users（エンドユーザー）
  id
  email
  encrypted_password

areas（地方）
 id
 name

prefuctures（都道府県）
  id
  area_id
  name

temples（神社・仏閣）
  id
  prefecture_id
  category(integer (enum))ここで神社・仏閣が選択できるようになっている
  name
  address

  もし、Userが神社・仏閣の投稿をするには、
  user_id(nilを許容する)
  is_active(boolean または enum で 承認待ち・承認済み)

Userが投稿する場合は、user_id に 値が入る　is_activeを falseにする ⇛　管理画面から is_activeを trueにできる
Adminが投稿する場合は、 user_id は nil is_activeは true

goshuins（御朱印）
  id
  temple_id
  user_id
  message

##### 【seedに記述】db/seeds.rb
area_prefectures.each do |area_prefecture|
  area_name = area_prefecture[0]
  area = Area.create!(name: area_name)
  prefecture_names = area_prefecture[1]
  prefecture_names.each do |prefecture_name|
    area.prefectures.create!(name: prefecture_name)
  end
end

コマンド
rails db:migrate:reset
rails db:seed

上記を記述すば下記の内容がデータベースに入る。すごい。
area_prefectures = [
  ["北海道地方", ["北海道"]],
  ["東北地方", ["青森県", "岩手県", "宮城県", "秋田県", "山形県", "福島県"]],
  ["関東信越地方", ["茨城県", "栃木県", "群馬県", "埼玉県", "千葉県", "東京都", "神奈川県", "新潟県", "山梨県", "長野県"]],
  ["北陸東海地方", ["富山県", "石川県", "福井県", "岐阜県", "静岡県", "愛知県", "三重県"]],
  ["近畿地方", ["滋賀県", "京都府", "大阪府", "兵庫県", "奈良県"]],
  ["中国地方", ["和歌山県", "鳥取県", "島根県", "岡山県", "広島県", "山口県"]],
  ["四国地方", ["徳島県", "香川県", "愛媛県", "高知県"]],
  ["九州地方", ["福岡県", "佐賀県", "長崎県", "熊本県", "大分県", "宮崎県", "鹿児島県"]],
  ["沖縄地方", ["沖縄県"]]
]

## 明日の予定
- ER図とテーブル提議書を作成する。
- Agile機能を使用すれば地方フォームを選択してから対応する都道府県フォームを選択することが可能らしいのでネットで調べてみよう。
- 管理者の許可システムは実装予定がなく考えていなかったので調べてみよう。
- ユーザーが御朱印の投稿は出来て神社・仏閣の投稿は許可制にすることが可能らしいのでやり方を考えてみる。
- テーマ課題が返却された即対応
- 時間があればワイヤーフレームなどにも手をつけたい。
- 明日質問しないと明後日質問出来ないので疑問に思ったことはメンターさんに質問する。
Javascriptの非同期処理でjQueryのajax使ってみた

# 辿り着くまでに

今日は仕事でWebアプリの保守してました、疲れた、、
admin画面を作成していたのだが、
検索ボタンを押した時に入力フォームをhideしたいということで、
苦戦しておりました。

Javascriptを書いても、一瞬hideされてすぐ戻るんだ、、、
悲しい、、、

ということで調べまくっていたところ、
ajaxとやらがいいらしい？
非同期処理とやらがいいらしい？

ということでjQueryのajaxを使用してみっか！


# 非同期処理とは

ボタンポチ！＝関数起動！
が同期処理。

ボタンポチ！＝第１関数起動！　　　　　・・・数年後。第２関数起動！
これが非同期処理なのだ。

というのは冗談で、
・・・詳しく書いてるサイトがありましたのでリンク貼っています。
https://qiita.com/yunity29/items/7ccc84d47e139340ecbc

代表的なのはGoogleMapとか。
リロードしなくても、ボタン押さなくても、地図がガシガシ更新されてます。
非同期処理なかったら１ミリ動かしたらリロードしなあかん。しぬ。

# ajaxについて
ajaxはjQueryのメソッドで、
「このAjaxを使うことで、Webページ全体を更新することなく「一部分だけ情報を更新する」ことが可能です。」
これです。

つまり非同期処理を行うために、使うのがajaxです。

使い方はこちら
```
$.ajax({
　url: ‘××××’　//URLまたはディレクトリを記載
　})
　.done(function(data){ // 通信が成功したときの処理 
　})
　.fail(function(data){ // 通信が失敗したときの処理
　})
　.always(function(data){ //通信の成否にかかわらず実行する処理 
});
```
参考　https://job-support.ne.jp/blog/javascript/howto-ajax

# まとめ
今回実装したのはこれ↓
```
<script>
    $(document).ready(function() {
        $('.submit').click(function(e) {
            $.ajax({
                url:  // サーバーのエンドポイント。
                type: 'GET',
                success: function(response) {
                    $('#formRow').hide();
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    console.error(textStatus, errorThrown);
                }
            });
        });
    });
</script>
```

こんな感じで書いてみました。

これで、検索ボタンポチ！→検索！　・・・２年後。formRowをhide！
となるわけです。

めでたしめでたし。

おわり。
AZ-400 に合格しました

# やりたいこと
先日、Azure の認定試験 AZ-400: Designing and Implementing Microsoft DevOps Solutions に合格しました。自分が受験する際、他に合格した方の情報などが少なかったので今後受験する方の参考になればと思い、まとめてみます。

# AZ-400 とは

https://learn.microsoft.com/ja-jp/certifications/exams/az-400/

Azure の認定試験の1つ。主に Azure DevOps での CI/CD について問われる他、Github での CI/CD についても問われます。また、Azure DevOps の各機能の使い方や開発プロセスの整備方法についても問われます。

AZ-400 と合わせて、AZ-104 or 204 を取得すると、認定資格として `Microsoft Certified: DevOps Engineer Expert` が認められます (私は104も204もまだ持っていないので資格はない… 次はどちらか取得します)。Expert レベルになるので、わりと自慢できるのではと思います。

# 勉強方法
基本的に、MS-Learn と上記リンク先の`無料の練習用評価を受ける`を繰り返し行いました。
もともと DevOps (というか CI/CD） の分野については少し経験があったので、MS-Learn についてはざっと読み、知らない言葉や Azure DevOps の機能については掘り下げていく形でした。
練習用評価は模擬試験のような形式で50問出題されます。問題は毎回固定ではなく、60〜70問くらいある中から50問出題されているようで毎回微妙に問題が変わっていきます。試験直前には安定して90%中盤の正答率になるくらいまで叩き込んでいきましたが、できるだけ暗記するようなことはせずこの選択肢はこういう理由だから正解・不正解という観点で繰り返し行っていました （繰り返しやっているとどうしても暗記してしまいますが…)。
実際の試験では練習用評価に出題されていない問題も当然出題されます。暗記などせずに練習用評価でほぼ満点くらいになれば実際の試験でもなんとか合格レベルまではいけるのではという感覚です。

他の勉強方法としては、Udemy があります。が、AZ-400 に関しては講座が英語で提供されているものしかないのとお金がかかる点で今回は使っていません。
今回、不合格だったらやってみるかーというつもりでした。笑

# 受験方法
Azure の試験はオンライン or テストセンターで受けることができ、上記リンクの `試験のスケジュール設定` から予約することができます。
個人的にはテストセンターでの受験をおすすめします。というのもオンラインの場合、試験官とつないで受ける必要があり、カメラも常時 ON、周囲に何もない環境で受ける必要があります。私の場合、自宅でそんな場所は作れないので大人しくテストセンターへ赴きました。オンラインでは受けたことはありません。
受験費用は2万円超えです。私は Build 時の Skill Challenge で無料バウチャーをもらっていたので無料でしたが、なかなかの金額です。受験する際は十二分に準備して臨みましょう。

# 試験概要
問題は全部で50問で、練習用評価で出題される形式のように1問1答のものや複数回答、操作の順番を回答するものなどがあります。50問の内、5問 (たしか) は顧客の環境や要件から回答するものもありました。このあたりはすでに Azure の試験を受けている方は分かると思います。

# 感想
スコアとしては730点で、ボーダーの700点ぎりぎりでしたがなんとか合格することができました。
実際の試験では、練習用評価で出た問題そのままというものはありませんでした。問われ方が変わっていたり、見たことも聞いたこともない問題だったりと様々な問題が出題されます。MS-Learn を繰り返し読んだり、実際に Azure DevOps を操作したりして覚えていくことが重要です。その後、練習用評価を受けるというのが正攻法かなという気がします (実際は通常の業務もあるのでなかなか難しいですが…)。
Udemy のコンテンツを使ったことはないのですが、有用という意見はわりと耳にするので次回は最初から Udemy も検討してみようと思います。

# ということで
AZ-400 の合格体験記 (ぎりぎりでしたが笑) を書いてみました。これから AZ-400 を受験する・しようとしている方の参考になれば嬉しいです！

それでは良き DevOps ライフを！


以上です。
matplotlib.pylotでグラフを描いてみた

### 棒グラフ
~~~python
import matplotlib.pyplot as plt
from matplotlib import style

# 棒グラフ
style.use("ggplot")
x = [1,3,5]
y = [4,5,1]

x2 = [2,4,6]
y2 = [6,3,2]
plt.bar(x,y, label='xy', color="green")
plt.bar(x2,y2, label='x2y2', color="blue")
plt.title("bar_chart")
plt.xlabel("X")
plt.ylabel("Y")

plt.legend()

plt.grid(True, color='blue')
plt.show()
~~~
![bar_chart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693500/ce82b818-5aff-7544-8973-8c643be27bd7.png)


### ヒストグラム
~~~python
import matplotlib.pyplot as plt

# ヒストグラム
x = [1,3,5,7,4,5,6,9]
y = [1,2,3,4,5,6,7,8]

plt.hist(x,y, histtype='bar', rwidth=0.8)
plt.title("Historgram")
plt.xlabel("X")
plt.ylabel("Y")

plt.legend()
plt.show()
~~~
![Historgram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693500/ab749b84-0918-7289-b49d-c1f105c75a09.png)


### 折れ線
~~~python
import matplotlib.pyplot as plt
from matplotlib import style

# 折れ線
style.use("ggplot")
x = [1,2,3]
y = [4,5,1]

x2 = [1,2,3]
y2 = [6,3,2]
plt.plot(x,y, 'g', label='xy', linewidth=5)
plt.plot(x2,y2, 'r', label='x2y2', linewidth=5)
plt.title("line_chart")
plt.xlabel("X")
plt.ylabel("Y")

plt.legend()

plt.grid(True, color='blue')
plt.show()
~~~
![line_chart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693500/a48c10f5-decc-d33e-0851-fc5b61f13ed9.png)


### 散布図
~~~python
import matplotlib.pyplot as plt
from matplotlib import style

# 散布図
x = [1,3,5,7,4,5,6,9]
y = [1,2,3,4,5,6,7,8]

plt.scatter(x,y, label='position', color='g', s=25, marker='o')
plt.title("scatter plot")
plt.xlabel("X")
plt.ylabel("Y")

plt.legend()
plt.show()
~~~
![scatter_plot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693500/40c5afd8-da63-3e3c-88ca-f775aaa4aee5.png)


### 積み上げ折れ線グラフ
~~~python
import matplotlib.pyplot as plt

# 積み上げ折れ線グラフ
days = [1,2,3,4,5]

study = [7,8,6,11,7]
eat = [2,3,4,3,2]
work = [7,8,7,2,2]
play = [8,5,7,8,13]

plt.plot([], [], color='m', label='S', linewidth=5)
plt.plot([], [], color='c', label='E', linewidth=5)
plt.plot([], [], color='r', label='W', linewidth=5)
plt.plot([], [], color='k', label='P', linewidth=5)

plt.stackplot(days, study, eat, work, play, colors=['m', 'c', 'r', 'k'])

plt.xlabel("Days")
plt.ylabel("Action")

plt.title("My workdays")
plt.legend()
plt.show()
~~~
![stacked_line_chart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693500/4d38a738-2f61-2377-2d86-3373a0fc1fdf.png)
Node.jsでファイルの読み書き

## fsモジュール
fsモジュールは、Node.jsでファイルの読み書きを行うための基本的な関数を提供するモジュール。
今回はこれを使用して基本的なファイル操作を試してみる。

## 同期形式と非同期形式
fsモジュールが提供しているすべてのメソッドには、非同期形式と同期形式が用意されている。
非同期処理を利用すると、処理の完了を待つことなく受付の完了のみを応答するため、エンドユーザーに対する応答性の改善や処理能力の改善を図ることができる (=メリットが多い)ため、処理内容が非同期処理でも問題ない処理であれば、非同期処理を選ぶと良いらしい。

## 事前準備
fsモジュールを呼び出しておく。
```
const fs = require("fs");
```

## ファイルの内容を読み込む
ファイルの内容を読み込みたい場合は、readFileSyncメソッドを使えば実現できる。
ファイルの読み書きは存在の有無や権限、ファイルシステムの違いなどによって例外が発生しやすいので、必ずtry~catchでエラーハンドリングを行う。
文字コードを指定したい場合、第二引数で直接指定できる。今回はutf-8を指定。
同時に動作確認も行うため、今回は成功時、エラー時にそれぞれ結果を出力する。
```
try {
    const file = fs.readFileSync("example.txt", 'utf-8');
    console.log(file);
} catch (err) {
    console.log(err);
    // ファイルが読み込めないなどのエラーが発生したときに呼ばれる
}
```

## ファイルに内容を書きこむ
ファイルに内容を書きこみたい場合は、writeFileSyncを使用する。
使い方はfs.writeFileSync(書き出すファイルパス, データ)の形。
同じ階層にtextの内容が書き込まれたoutput.txtが作成されていれば成功。
```
try {
  let text = "この内容がoutput.textファイルに出力される";
  const file = fs.writeFileSync("output.txt", text);
} catch (err) {
  console.log(err);
  // ファイルが読み込めないなどのエラーが発生したときに呼ばれる
}
```

## ファイルに内容を追記する
置き換えるのではなく追記したい場合に行う処理。
appendFileSyncメソッドを使用する。
※ファイル名を間違えて存在しないファイル名を指定してしまった場合、エラーにならず新規ファイルとして作成されてしまうので注意。
```
try {
  const appendFile = fs.appendFileSync('output.txt', '\nこれは追記です。','utf8');
} catch (err) {
  console.log(err);
}
```

## ファイルを削除する
unlinkSyncメソッドを使用することで、ファイルの削除が可能。
上の、ファイルに内容を追記するの動作時に、ファイル名を間違えてoutput.textを作ってしまったと仮定して、これを削除する。
```
try {
  const deletefile = fs.unlinkSync('output.text');
} catch (err) {
  console.log(err);
  // ファイルが存在しないなどのエラーが発生したときに呼ばれる
}
```
uploader.jp(ux.getuploader.com)からファイルをコマンドラインで取得する

# はじめに
`https://uploader.jp/`(`ux.getuploader.com`)からファイルをコマンドラインで取得すべくファイルの直リンクをコピーしても、時間が経ってからこのリンクを開いたら機能しません。しかしながら、このためだけにSeleniumを使うのも面倒です。
そこで、URLを指定したらダウンロードするスクリプトを組みました(というか組んでもらった)。
# スクリプト
Python
```Python
import sys
import requests
from bs4 import BeautifulSoup

url = sys.argv[1]
res = requests.get(url)
soup = BeautifulSoup(res.text, 'html.parser')

token = soup.find('input', attrs={'name': 'token', 'type': 'hidden'})['value']
fileName = soup.find('meta', attrs={'name': 'keywords'})['content'].split(',')[0]
userName = soup.find('a', attrs={'class': 'navbar-brand'})['href'].split('/')[-2]
index = url.split('/')[-1]

downloadUrl = f'https://downloadx.getuploader.com/g/{token}/{userName}/{index}/{fileName}'
r_zip = requests.get(downloadUrl)
with open( './' + fileName , 'wb') as file:
    file.write(r_zip.content)
```
# 使用法
オプションにダウンロードリンクを付けるのみ。
# 謝辞
原型を書いてくださった部活の先輩に感謝します。
Vue2でVuetifyのv-tabsとag-gridを使ってみた

# 環境

vue 2.6.11
vuetify 2.6.14
ag-grid-community 29.2.0
ag-grid-vue 29.2.0

# コード

plugins/vuetify.js
```js
import Vue from "vue";
import Vuetify from "vuetify";
import "vuetify/dist/vuetify.min.css";

Vue.use(Vuetify);

const opts = {};

export default new Vuetify(opts);
```

App.vue
```Vue
<template>
  <div id="app">
    <v-app id="inspire">
      <v-card>
        <v-tabs>
          <v-tab :value="one">One</v-tab>
          <v-tab :value="two">Two</v-tab>
          <v-tab :value="three">Three</v-tab>
          <v-tab-item :value="one">
            <ag-grid-vue
              style="width: 500px; height: 200px"
              class="ag-theme-alpine"
              :columnDefs="columnDefs"
              :rowData="rowData"
            >
            </ag-grid-vue>
          </v-tab-item>
          <v-tab-item :value="two"> Tab 2 Content </v-tab-item>
          <v-tab-item :value="three"> Tab 3 Content </v-tab-item>
        </v-tabs>
      </v-card>
    </v-app>
  </div>
</template>

<script>
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-alpine.css";
import { AgGridVue } from "ag-grid-vue";
export default {
  props: ["one", "two", "three"],
  name: "App",
  data() {
    return {
      columnDefs: null,
      rowData: null,
    };
  },
  components: {
    AgGridVue,
  },
  beforeMount() {
    this.columnDefs = [
      { field: "make" },
      { field: "model" },
      { field: "price" },
    ];

    this.rowData = [
      { make: "Toyota", model: "Celica", price: 35000 },
      { make: "Ford", model: "Mondeo", price: 32000 },
      { make: "Porsche", model: "Boxster", price: 72000 },
    ];
  },
};
</script>

<style scoped>
#app {
  background: linear-gradient(45deg, #076bb7, #1e98db);
}

#tab-items {
  background-color: transparent;
}
</style>
```

main.js

```js
import Vue from "vue";
import App from "./App.vue";
import vuetify from "@/plugins/vuetify"; // path to vuetify export

Vue.config.productionTip = false;

new Vue({
  vuetify,
  render: (h) => h(App)
}).$mount("#app");
```
# デモ

https://codesandbox.io/s/vuetify-sample-5ppwxq

# リンク

[vuetify v2 v-tabs](https://v2.vuetifyjs.com/en/components/tabs)
[ag-grid](https://www.ag-grid.com/)
SESエンジニアからWebエンジニアになった話

# はじめに
9月からWeb系自社開発企業で働かせていただくことになりました。

プログラミングスクールの[HappinessChain](https://happiness-chain.com/)で約５ヶ月間勉強して新しい職場で働くことができるようになりました。

# 自己紹介
現在24歳でSES企業のエンジニアとして働いています。主にHTML/CSSを使うことが多く、Web制作がメインの仕事でしたが、私が将来目指すエンジニア像になるためにはこの企業では叶えられないと思い、プログラミングスクールの入会を決意しました。

# Webエンジニアになるために学習したこと
### 前提
プログラミングスクールに入る前に事前に身につけていた知識として以下がありました。
- HTML/CSS
- JavaScript
- React(動画を複数視聴したり、簡単なアプリケーションを作成できる程度)
### 1ヶ月目

- Progate(Ruby, Rails)
- Git
- Docker
- Ruby
- Web開発の基礎

ますばWebアプリを作るための基礎のインプットから行いました。実際に形になるものがないのでここの学習は結構きつかったです。
当時、ProgateのRailsができるようになっただけで「意外とできるんじゃね？」と思い込み、とても喜んでいましたがこの後地獄をみます。
### ２ヶ月目

- Ruby on Rails

いざアプリケーションを最初から作るとなると全然手が動かない、、、
Progateで分かりきった気になっていましたがどんどん分からないことがでてきました。
分からないところは諦めず調べ続けました。
１ヶ月使ってもこの課題を終えることができませんでした。。
### ３ヶ月目

- Ruby on Rails

なんとか１つ目のアプリケーションを作成しました。
自力でアプリケーションを作成できたのでRailsの自信はかなりつきました。
２つ目のアプリケーションの作成に移りましたが、ここでも何度か壁にぶちあたりました。

### ４ヶ月目
- React
- Next.js
- TypeScript

たまたま友達の紹介でフロントエンドの副業を紹介してもらうことができ、Railsの課題は一旦中止して上記の技術を勉強しました。
ここは急いで勉強してしまって基礎の部分が抜けている可能性があるので後日、改めて復習しようと思います。

### ５ヶ月目
- Ruby on Rails
- Next.js
- TypeScript

引き続きフロントエンドの技術を勉強しつつなんとかRailsのアプリケーションを形にすることができました。

# Webエンジニアになるために
何様なんだと思われるかもしれませんが実際にWebエンジニアになった身として大切にしていたことや心掛けていたことがあるので共有します。参考にしてもらえれば幸いです。

- 諦めないこと
- 継続すること
- 行動すること

### 諦めないこと
勉強したり課題をこなすことで分からないことが必ず出てきます。しかも１つや２つではなく無数に出てきます。課題をやるうえでよく分からないエラーがたくさん出ます。正直、何度も挫折しそうになってやめたくなる時はありました。「俺、エンジニア向いてないかも」って何度も思いましたね笑。でもこれは、みんなも思っています。自分が分からないってことは、みんなも分からない道は１度はたどっていてそれを乗り越えてエンジニアになっています。

### 継続すること
1日や２日勉強するだけなら誰でもできます。長期間に渡って継続することが難しいです。その長期間で、仕事やプライベートの変化があったりプログラミングへの興味が薄れたりなどさまざまな要因があるからだと思います。私の場合、本業の仕事自体は楽なほうでしたが、炎上案件に参画して余裕がない時も、大好きだった彼女とお別れした時も、寝る時の夢でプログラミングのエラーコードを見た時も勉強する心は忘れませんでした。でも、本当にしんどい時や眠たい時は休んでいいと思います。自分も休む時は結構休んでました笑

### 行動すること
今の職場で仕事内容に不満を漏らす人はいても実際に行動する人はほとんどいませんでした。プライベートで勉強する人はいても、「運良く開発の仕事に携われないかな」みたいな待ってる人が多かったです。そんな運任せに頼るぐらいならプライベートで勉強しまくって転職活動して１００％開発に携われる自社開発企業に転職しましょう。あと高いからという理由で教材を買わない人も多くいました。私は、今払ったお金は将来何倍にもなって返ってくると信じて買っていました。

# 最後に
独学でここまで勉強するのは厳しかったと思うので、自分にとって[HappinessChain](https://happiness-chain.com/)に入会したことは良い選択だったと思います。これから仕事についていけるか不安ではありますがなんとか食らいついていこうと思います。
この記事を見ていただき、Webエンジニアを目指す方が一人でも増えれば幸いです。
マイクロアプリケーション開発　とは

はじめての投稿です。

少し自己紹介、2年間IT基盤運用保守をしてきましたが、異動となり、AP開発担当（あしかも開発手法はアジャイル）に異動になったので、早く仕事を覚えるためにアウトプットすることにしました。

毎日1投稿以上する縛りのもと俺は強くなる！！！



ということで、仕事中に出た不明用語を調査してきまーす。



## マイクロサービス

複数の独立した小さなサービスを組み合わせて、1つの大きなアプリケーションを構築する開発手法。

マイクロサービスで構築されたアプリケーションの構成はマイクロサービスアーキテクチャという。

対義語はモノリシック、すべての機能がひとつにまとまった塊としてアプリケーションを作成していた。

サービスが小さいだけではなく、自らの役割に専念して、自律的に機能するという要素を持つ。

個々のサービスはできるだけシンプルにし、個々のサービスの依存度を低くすること。また、サービスの呼び出しはネットワークを介して行うのも特徴。

##### メリット
`新しい技術を用意に採用できる。`
上記に書いた通り、個々のサービスはネットワークを介して、それぞれ公開したインターフェースを呼び合うのだけで、その他の依存関係はない。呼び合うためのインターフェース仕様が一致していれば異なる技術を使用しても問題ない。

`保守性の向上、改修の容易さ。`
各サービスは依存度が低く、小さなものなので、機能追加した際の影響範囲が狭い。

`俊敏性`
各サービスに対して、少人数の独立したチームが責任を持つことで、大規模な開発チームと比較して早く開発できる。

`アジャイル開発に超向いてる`
アジャイル開発は少人数のチームが各サービスを開発しているのでマイクロサービスに適した開発手法といえる

`デプロイが容易`
各サービスは依存関係が低いので、デプロイする際にシステム全体を停止する必要がない。

##### デメリット
`設計や統括に高いスキルが必要`
メリットで各サービスに異なる技術を採用できると記述したが、裏を返せば、システム全体の難易度は上がる。また、最初に分割したサービス単位は後から変更できないため設計には高スキルが求められる。

`結合テスト以上の難易度が高い`
各サービス内のテストは容易だが、実際は複数のサービスが連携してユーザに提供される、そのためテストでエラーが出た場合、どの機能が原因か特定するのが難しい。

`API管理が大変`
各サービスはAPIなどを通じて、通信しあうので、1つのアプリケーションに多くのAPIが使用される。サービスに変更がなくても、APIに変更があればそのAPIを使用している機能すべてに影響がある。

##### まとめ
柔軟性、拡張性の求められるアプリケーションに向いていると感じた。
アジャイル開発に向いている。
各サービス毎に異なる技術を採用できるので、IT人材育成の面でもよいと感じた。
APIに関する知識がないので調査したい
Unityゲーム開発備忘録　#2　GetAxis　マウス

# 今回の内容
```sample.cs:
Input.GetAxis("Mouse X")
```

### の動きについて


Unity におけるカメラ移動ってまあ基本こいつを使っていると思います。使ってない人に関してはちょっとわからないのでスルーしてください。


こいつの働きは、ジョイスティック、キーボード、マウスの入力に応じて-1か1の数値を出します。
マウスだとちょっと変わりますが、概ねそんな感じです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425741/2fec0709-a5ae-25c0-9ecd-2f7240c183ce.png)

関数のグラフのイメージで正負の判定を出力します。
なのでマウスでカメラを動かす
といった動きに多用されるわけですね。



しかしこいつ






**マウスの動きは関数グラフと同じですが**

**これをカメラの動きに当てはめるとXYが逆になります。**


罠ですね。


いや罠じゃあないんですが、初心者の方にはマジでわけわからんと思います。


だってXYを順当にカメラの動きに対応させると

**マウスを左右に動かすとカメラが上下に動いて**
**マウスを上下に動かすとカメラは左右に動く**んですから




これ、原因はRotationの軸なんですよね。



## どういうこと？


カメラが上下左右に動くのは、Rotation、つまり軸を中心にした円運動なんですよね。

で、Rotationにおける**X,Y**は
**X軸、Y軸**になります。

Rotation　X＝60は　X軸中心の＋６０度回転

ってことになります。

X軸は真横に伸びる線です（Z軸もそうだけどそこは気にしない）


真横に伸びる線を中心に＋60度回転するとどうなるか？


当然上を向きますよね。

同様にYのRotationをしたら横に回り始めますね。



## 要するに

**マウスのXYは座標を取得する**が
**RotationのXYは軸を指定する**ので

そこをしっかりと理解しておかないと、「あれ、マウスを横にしてんのにカメラが縦に動くじゃねーか！！！」
ということになってしまうので、注意しましょう

って話でした。

Rotationって書きすぎて平沢進のRotation（Lotus-2）を聞きたくなったので聞いてきます。

じゃあね。