OmniAICreator/Qiita-1.07M huggingface dataset:
俺がわかるように書いたAlexaスキル入門３（デバッグ）

## Alexaの基本的なスキル作成３（デバッグ）
###### 2021/6

### ■ 前回
インテントやらスロットやらで何を発言したのか、それをどうまとめて処理するのかのあたりをやりました。
適当に話すだけのスキルなら、これを拡張していくだけである程度作れそうですが、これ以上やるとなるとDeveloperConsoleで作るのはだれがどう言っていても不可能だと申し上げたい。

何故ならば、とことんデバッグ関係が無い。存在しない。
エラーチェックもほぼ無しなので、デプロイしてテスト実行して「スキルがリクエストに正しく応答できませんでした」を延々と聞き続けることになります。

実際、何度か心が折れました。
<br>

---
### ■目的と手段
せめてPrintfデバッグっぽいレベルができるまでなんとかしたい。
やることは簡単なことだけで何とかしたい。
欲は出さない。

- **第一段階**
 言語的な問題のチェックはオフラインで済ませたい。

- **第二段階**
 問題が起こった個所がわかるようにしたい。

- **第三段階**
 簡単ならデバッグしたい。

調べると多くの人がいろいろとやってますが、オフラインでサーバー環境を整えるとかハードルが高そうなものがゴロゴロしていて、自分みたいな弱者には心が折れるだけでした。
<br>

---
### ■とりあえずVSCode
DeveloperConsoleでも推しているぽい「Alexa Skills Toolkit」なんて拡張がVSCodeにはあるようです。
とりあえずこれ入れて、SingInします。

まずは「Download and Edit skill」ですね。
何もないフォルダにダウンロードします。
残骸とかがあると正常に作動してくれませんでしたので、まだまだ駆け出しということなんでしょう。

<br>
さて、サーバーにあったファイル群が手に入りました。（よね？）
DeveloperConsoleにもダウンロード、インポートなどありますが、ダウンロードは全然進まないし、インポートはZIP化して読ませないといけないみたいだし無視しました。
<br>

---
### ■Pythonの言語チェックするために
インポート関係、言語関係、ビルド関係などのデバッグをするためにスキルのlambda_function.pyがインポートしているコードが欲しいですね。

<br>
ということで、ask-sdkを入れます。
pipでサクッと入れられる。最高だ。

     pip install ask-sdk

本来は別環境を作ったうえで、そこにいれて実行できるようにしたりするみたいですが、ソースチェックをとにかく簡単にしたい場合、手っ取り早くソースをimportできる場所に置いてしまいます。
<br>
これで、VSCodeを再起動すると、importしてるファイルが見つかってる状態になってるはずです。
定義も右クリックからたどれるので、いろいろNode.jsとの違いでわからないあたりがスッキリします。

<br>
この状態で、何も考えずにVSCodeの実行ボタンを押せば実行前処理が走り、問題があればエラーが出るし、何事もなく終わったようなログが出れば言語的なチェックができたことになります。

これで「スキルがリクエストに正しく応答できませんでした」を聴く回数が80%オフぐらいになった。
<br>

---
### ■問題が起こった場所が知りたい
次は実行時の問題ですが、例外、スタックトレースが見れさえすればほぼデバッグ可能だな。

ということで、ちょっと荒業ですが、CatchAllExceptionHandlerをこんな風に変えてしまいます。

```python
# importしてね
import traceback
    
# 何か例外が起こりました (すべて受ける)
class CatchAllExceptionHandler(AbstractExceptionHandler):
    def can_handle(self, handler_input, exception):
        return True

    def  handle(self, handler_input, exception):
        msg = "exception: {}: {}".format(exception, traceback.format_exc())
        return handler_input.response_builder.speak(msg).ask(msg).response
```

これで、実行時に問題が起こればAlexaが全部しゃべります。
かなり鬱陶しいですが、シミュレータ上では文字で確認ができるので、これで問題個所は特定できると思います。

tracebackの中を見ると、ほかの表記もありそうなので表記を整理したい人は調べてみるといいと思います。

とはいえ、完全にすべてraiseしてるわけじゃないので、結局「スキルがリクエストに～」を聴く羽目になるんですが・・・。
<br>

---
### ■デバッグ？できるの？
さて、少しだけ欲を出して「ASK SDK Local debug」試すだけ試したんですが・・・ダメでした。

VSCodeのAlexaのところにDeployやらOpenSimulatorやら夢のある単語が並んではいるんですが、まともに動いてるようには見えない。

色々な設定が必要そうなので、根気がある人はやってみたらいいんじゃないでしょうか。

そして教えてほしい。
クソ簡単にまとめてほしい。
<br>

---
### ■これらによる運用
スマートではないですが、オフラインでlambda_function.pyを編集し、丸コピしてDeveloperConsoleではっつけて、デプロイしてテストするです。

ところで、loggerってどこに出てるの？？意味あるの？
<br>

---
### ■雑記

DeveloperConsoleはスキルの制作に触れてもらう初期の初期、ウィザードで作ったものを実行するまでしか想定していないんじゃないかという出来ですね。

コードエディタもUndo、Redoがバグってていつ紛失するかわからないという状態ですし、プログラム部分はオフラインで作るしか選択肢はないなと。

インテント、スロットタイプはDeveloperConsoleでも大して困らないかなという感じではあるんですがね。
<br>

---
### ■次
オーディオやる。
というか、後はそれしかやる気がない。

そもそも、AlexaでやりたかったのはPCとかで動いてるプログラムから適宜Alexaにしゃべらせるってやつ。
出力先の一つとしてというレベルで。

認証が必要で、なんとも使いづらい。
API_KEYみたいな感じで、自分のデバイスに対してスパッと投げられるといいんですが・・・。

あとは、AmazonMusicだと、自分のプレイリストも再生してくれないので、どっかに置いたファイル再生してほしいなというぐらいで、それはスキルで何とかなりそうなので、この流れのままやります。
俺がわかるように書いたAlexaスキル入門２（スロット）


## Alexaの基本的なスキル作成２（スロット）
###### 2021/6

### ■ 前回
前回はカスタムスキルをとりあえずなんとなく理解する回でした。
なんとなく、した？

まあ、そんな簡単にわかったら困らんよね。
なんとなくするまでは多分ここ読んでも、何かが深まるわけじゃないのでまだ読まなくていいです。

ということで、なんとなくわかってきた人は今回は前回疑問の残った「インテントってそんなにいっぱい作るの？まじで？」をやります。

### ■ インテントいっぱいつくらなくてよい
Alexa道場を見つつ勉強してるのを平易にまとめておこうって感じなので同じように次はスロットってやつやりましょう。

スロットってのを使うと、いろんな単語をまとめて処理できる感じになり、インテントをいっぱい作らなくてよくなります。（結論）

### ■ スロット
スロットってなんやねん？ですが、簡単に言うと単語集での認識システムですかね。

ちょっと一回使ってみましょう。
Intentの発話文の追加入力のところで「{}」で囲んで変数みたいな名前をつけます。
例として、「{place}」とでもします。
いきなり書いていいです。

すると、入力してるそばから「え？それどのスロット？新しいスロット？」みたいにダイアログが出てきますが、無視して打ち切って発話文を追加しちゃいます。

登録されるとスロット部分は色が変わって表示されてます。
で、下のほうにスクロールしていくと「インテントスロット」という項目でこの**インテント**で使われている**スロット**が並んでます。

今書いた{place}てのに対応したplaceというスロットができてると思います。

次に、そのplaceに当てはまる単語集を選びます。
amazonが事前に用意している単語集が「スロットタイプを選択」とうっすら出てるプルダウンで選べます。
AMAZON.cityあたりを選んでみましょう。

さて、これで保存してビルドして、「東京」とか叫ぶとこのIntentがスキルに飛んできます。

もやっとするでしょうけど、なんとなく想像つきますかね？
AMAZON.cityという単語集にある単語が検出されたら「{place}」のところが満たされたと判断されるということです。

発話文が「{place} に行きたいなー」とかだと「コロールに行きたいなー」「ウィーンに行きたいなー」
とかの発話文をすべて登録したのと同じになるので便利だねってことですね。

### ■ スロットタイプ
上ではamazonが用意したやつを使いましたが、当然自分で作った単語集を使いたくなる項目が出てきますわな。
方言とかスラング含めて挨拶を認識したいとか。

ということで、単語集を作ってみます。

単語集を作るところはアセット＞スロットタイプってところです。
追加するボタンがあると思うので、それをぽちります。

「値を持つカスタムスロットタイプを作成」を選びます。
自分で作るか、amazonの奴を拡張するかっていう違いですかね。

まずは単語集の名前を付けます。
「words_greeting」あたりであいさつ単語集でも作ってみますか。

名前を付けると、単語入力画面になるので、単語入力しましょう。
「おはよう」でも入れてください。

すると、下に追加されたのが出てきます。
そこを見ると「同義語」ってのが見えます。

#### 同義語（シノニムっていうんだってさ）
全部別々に登録してもいいんですが、おはようと同じ意味の挨拶はこっちに登録しておくとどの意味の挨拶が入力されたから、どういう返事をするみたいなスキル処理をするときに簡単になります。

同義語に「はよー」やら「おっはー」やら追加していきます。

「こんばんは」とかも、夜っぽい挨拶を同義語に入れて、「こんにちは」の昼っぽい挨拶も同様に追加していけば挨拶の単語帳（words_greeting）の出来上がりです。

#### ID
各単語の同義語のどれが認識されたとかまで見て処理を書くことって基本ないと思うんですよ。

そこでIDを設定しておくと、認識された言葉と一緒にIDが飛んでくるので、IDで処理分けをすることができるようになります。

設定しましょう。
ちなみに文字列ですが、飛んできた後に数値にして使うのが楽かと思うので、数値文字列を入れておくのがおすすめ。

### ■ スロットなにがしが多い（小休止）
ちょっと混乱してきましたかね。

・スロットタイプ = 変数の型
・スロット ＝ 変数名
・インテントスロット = インテントで使ってるスロットというだけ

自分はこんな風にイメージしてます。
文章中に単語集のどれかが入る変数を置けるみたいな。

「東京の名物は？」が「{place} の名物は？」とすることで、都市単語帳のどれかがplaceという変数に入ってくるみたいなね。


### ■ 値の扱い方
Intentと認識されて飛んできたときに、スロットの単語が認識されていたらslotsという配列にデータが入ってきます。

ウェブで探すと大抵Node.jsのやつですが、Pythonだと命名規則が違ったりするし、Pythonは「.」つなぎでdictのアクセスできないせいで記述もちょこちょこ違うんですよね。

あんまりウェブに出てきませんが、ask_sdk_core.utils.request_util.pyってのに少しアクセサーが入ってるので、これ覗くとわかりやすいかもです。
（https://github.com/alexa/alexa-skills-kit-sdk-for-python/blob/master/ask-sdk-core/ask_sdk_core/utils/request_util.py）

ということで、とっとと関数化しましょう。
めんどくさいので、最初の要素の最初のIDを得るやつです。
（複数同時に認識されることがあるので、配列になってる）

```python
from ask_sdk_core.utils import request_util

def  get_slot_id(self, handler_input, name, def_value):
    try:
        s = request_util.get_slot(handler_input, name)
        if s is not None and s.resolutions is not None:
            r = s.resolutions.resolutions_per_authority[0]
            if r.status.code == StatusCode.ER_SUCCESS_MATCH:
                return r.values[0].value.id
    except:
        return def_value
    return def_value
```

これで、IDの値をスロット名（name）から取得できます。
認識されてなかったらdef_valueが返ります。
特に指定なしの場合に決まった処理などさせれば、あまり発言しなくていいので楽です。

### ■つぎは
だんだんDeveloperConsoleでの作業がつらくなってきたと思います。
特にデバッグ環境がないことに。
次はそこを最低限確保します。

最低限です。
でも、雲泥の差です。
【Python】ホワイトボードツールMiroのAPI叩いてめっちゃ付箋貼る

最近、ホワイトボードツール「Miro」を知り、仕事でブレストに使用しています。

https://miro.com/index/

↓ボードのテンプレートの例。
![スクリーンショット 2021-06-17 1.15.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158553/ac03d7c6-33de-ee0a-a1bb-b1e31c76f92e.png)

付箋を貼り付ける他にもマインドマップを作ったりプレゼンテーションができたりなど、非常に機能が豊富です。複数人で作業しててもストレスなくぬるぬる動きます。Miroを使うとオンラインでも楽しくブレストができます。

CSVから付箋を作成できたら便利なので、PythonでAPIを叩いてみました。Mac OS11.3.1(Big Sur)、Python3.9で実行しています。

###参考：

https://developers.miro.com/reference
https://developers.miro.com/reference#sticker

https://qiita.com/Horie1024/items/e2d541dd5f58655337c5

APIキーは無料で取得できます。取得方法は上のQiitaがまとまっています。


##準備

APIキーは別で保存しましょう。

```Miro_API_KEY.txt
ここにAPIキーを書く
```

CSVファイルは「データ.csv」というファイル名で、カラム3つのUTF-8でエンコードされているファイルを想定しています。（この記事では触れませんがCSVをMacで操作しようとすると文字コードの壁がありますよね。。）今回使うCSVは最初の行に百人一首の歌が入っています。

MiroのボードのIDが必要になります。ボードをブラウザで開いたときにURLで (略)app/board/　の次に入っている文字列です。

##コード本文


```miro_create_widget.py
import csv
import json
import requests
import time

with open('Miro_API_KEY.txt') as f:
    access_token = f.read()

headers = {'Authorization': 'Bearer {}'.format(access_token)}
BOARD_ID = "<ここにボードのIDが入ります。>"
url_create_widget = "https://api.miro.com/v1/boards/{}/widgets".format(BOARD_ID)

my_csv = "データ.csv"

my_data = []

with open(my_csv,encoding="UTF-8") as f:
    csv_reader = csv.reader(f)
    for row in csv_reader:
        my_data.append([row[0],row[1],row[2]])


for i, data_line in enumerate(my_data):

    data = {}

    data["type"] = "sticker"
    data["x"] = 100
    data["y"] = 0 + 114*i
    # data["height"] = 228
    # data["width"] = 199

    data_style = {}
    data_style["backgroundColor"] = "#f5d128"
    # data_style["fontFamily"] = "Noto Sans"
    data_style["fontSize"] = 40
    data_style["textAlign"] = "left"
    data_style["textAlignVertical"] = "top"
    data["style"] = data_style
    text_in_sticker = data_line[0]
    data["text"] = "<p>{}</p>".format(text_in_sticker)


    with open('load_data_tmp.json', 'w') as f:
        json.dump(data, f)

    json_open = open('load_data_tmp.json')
    json_data = json.load(json_open)

    response = requests.post(url_create_widget,json=json_data,headers=headers)

    print(response.text)

    time.sleep(1)
```

![スクリーンショット 2021-06-17 1.52.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158553/a1919af4-e624-5846-3818-48db0859a5f1.png)

![スクリーンショット 2021-06-17 1.53.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158553/ec3bd09c-bb87-98f6-27ea-351dbf6f9672.png)

普通のREST APIなのですが、ペイロードを書くにあたり、引っかかった事がいくつかありました。
・付箋の大きさは自由に指定できません。"height"は199,228,350のどれかを指定できます。それから1でもずれると400エラー（ペイロードの中身の形式が間違ってるよ、という内容）になります。
・"scale"と"fontFamily"は指定しようとすると400エラーになっちゃいました。理由はわかりません。上のコードではコメントアウトしています。
・上のコードではJSONをファイルとして一旦出力して再度それを読み込んでいます。この無駄なプロセスがないと、やはり400エラーを吐かれました。JSONの扱いに関する問題だと思いますが...わかる方いらっしゃいましたらコメントお願いします。

##感想
ちょっと引っ掛かるポイントはありましたが、概ね使いやすい印象です。CSVデータの2列目にデータの属性を入れて、その値によって付箋を色分けする。3列目の数値によって付箋の大きさを変える、など、Miroならではの使い方をすると有り難みが出てきそうですね。

この記事がブレストの一助になれば幸いです。よきMiroライフを！
Pythonツールを初めて作成

Pythonで初めてツールを作成して、GitHubに公開した。
csvファイルからJSON、YAMLファイルに変換するだけのツールを作成。
JSONを書いたり、YAMLファイルを書くと、初学者なので慣れていない。
例えば、DockerCompose.ymlを作成すると、慣れていないので見えないバグがあり探して直すのが大変。
ｃｓｖファイルでパラメータを作成して一発で作りたいなと・・。

今後
DockerCompose.ymlが作れるかどうか検証。
コードを再度よく見て、このQitaを見ながらコードを綺麗にまとめよう。
【CSV】書式を「標準→数値」に変更して上書き保存→「標準」に戻り「〇.〇〇〇〇〇E+12」と文字化けしてしまう問題

#前提
【目的】
Excelで作られたフォーマットに商品データの一覧を作成し
そのExcelファイルをcsvファイルに変換して
そのcsvファイルを某システムに読み込ませたい。
（もとのExcelファイルの書式設定は全て「標準」）

【問題】
JANコード(13桁の整数)を入力してある列に問題発生！

・Excelファイル（書式設定＝標準）の状態だと→「〇.〇〇〇〇〇E+12」と表示される
<img width="500" alt="200.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/5a0c15b4-e69e-ac08-93a8-b07eed267df1.png">
<img width="300" alt="100.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/6df8a16b-84fa-38e0-6b9b-6d3cc942560e.png">
↓
・ExcelファイルのJANの数値が入っているセルのみ、書式設定を「標準→数値」にすると→13桁の整数が正常に表示される。
<img width="150" alt="300.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/9fb2611d-2911-95a0-83fe-154951f4669c.png">

↓
・そのExcelファイルをcsvファイルに変換すると→書式設定が「標準」になり「〇.〇〇〇〇〇E+12」と表示される
<img width="300" alt="500.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/1dd7e5d4-16b5-6ac8-2756-975bc98f6bdf.png">

なぜ「標準」に戻ってしまうのだろうか？
csvのJAN列を数値の状態にするにはどうしたら良いのか？

#結論
結論を先に書いておきます。
書式設定「標準」（"〇.〇〇〇〇〇E+12"と表示）のままシステムにアップすればOK！


#仮定1
csvにした後、JANの列名が入っている1行目の書式設定も「数値」にしてみたら良いのではないか？
（現在は　標準　になっている）

#仮定1検証
（csvファイル）
1.JAN列の書式設定を「数値」にする
<img width="300" alt="600.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/d248bbb9-51e0-4e90-d3ab-f913a980ef15.png">
↓
2.上書き保存&「×」でcsvファイルを閉じる
↓
3.再度同csvファイルを開く
<img width="150" alt="800.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/4dc437bc-0116-c7f7-f1d9-ece8ea340305.png">
また「標準」に戻ってしまった・・・。
違う方法を考える。

#仮定2
「書式設定の変更」以外の方法があるのではないか？

#仮定2検証
私と似たような状況の方がした質問に、こんな回答が付いていました。

「[csv形式のexcelファイルについて](https://answers.microsoft.com/ja-jp/msoffice/forum/msoffice_excel-mso_win10-mso_2019/csv%E5%BD%A2%E5%BC%8F%E3%81%AEexcel%E3%83%95/7ea48eca-1425-479b-8710-65ce531fe9b7)」

上記記事から得た情報：
・書式情報を持たないのが csvファイル
・csvファイルの該当列について、「データ」→「区切り位置」→列のデータ形式を「文字列」にすればOK

やってみます。

1.JANの列をまるっと選択
↓
2.「データ」タブをクリック→「区切り位置」をクリック
↓
3.区切り位置指定ウィザードが立ち上がる→「次へ」
<img width="400" alt="11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/9c4095a6-7d02-d713-7139-a666022038e5.png">
↓
「次へ」
<img width="300" alt="22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/d97702af-ffa3-3bee-ed61-aaa3d0f2d4de.png">
↓
列のデータ形式のチェックを「G/標準」から「文字列」に変更→「完了」
<img width="300" alt="33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/ce2a9e43-49f3-4f2c-5459-df160e614d16.png">
 
↓
<img width="150" alt="55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/9ed3854a-0a7f-3f51-3011-9fd637066711.png">
（リボン中の書式の欄は「標準」と表示されている）
↓
「上書き保存」→csvファイルを閉じる→再度開く
↓
やはり「標準（〇.〇〇〇〇〇E+12）」に戻ってしまった。
<img width="150" alt="88.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/3f0aad01-59ea-c096-8f6d-c06c0b0b8002.png">

#仮定3 & 結論
文字化けしたままでシステムにアップしても良いのではないか？

→「標準」の文字化け（？）した状態（〇.〇〇〇〇〇E+12　と表示されている状態）のcsvファイルを
そのままシステムにアップロードしたところ、システムのJANの欄には問題なくJANが表示された。

csvの状態で各セルの中が文字化けしていても、セルをクリックすると数式バーには正しい13桁の数字が表示されてる。ということは、見かけが「〇.〇〇〇〇〇E+12」となっているだけで、システムにとって必要な13桁の数字の情報はきちんと入っているということだよね。

次回からは文字化けは気にせずに、そのままアップロードしよう！
最新版のcmakeをインストール

## 環境


```
cat /etc/os-release

> NAME="Ubuntu"
VERSION="18.04.5 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.5 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

uname -a
> Linux hoshina-ThinkPad-X1-Carbon-7th 5.4.0-74-generic #83~18.04.1-Ubuntu SMP Tue May 11 16:01:00 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

```

## 方法

アンインストール

```
sudo apt purge cmake
```

以下のサイトから自分の環境にあったBinaryをダウンロード
私の環境の場合では```cmake-3.20.4-linux-x86_64.tar.gz```をダウンロード

https://cmake.org/download/

![Screenshot from 2021-06-17 00-43-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/94a43d73-c486-13ed-ee85-e9d875ef235b.png)

解凍

```
tar -xzvf cmake-3.20.4-linux-x86_64.tar.gz
```

インストール

```
cd cmake-3.20.4-linux-x86_64
sudo cp bin/* /usr/bin/
sudo cp -r share/* /usr/share/
```

確認

```
cmake --version
> cmake version 3.20.4

CMake suite maintained and supported by Kitware (kitware.com/cmake).
```


## 参考

https://qiita.com/koara-local/items/9d01c6bb9dd93563b7c6
Pimplはアンチパターンだと思います

# はじめに
数年前は使うこともあったのですが, 現代にはふさわしくないと思い使わなくなりました.

# 利点と欠点, それについての考え

## 利点

- includeを減らして, コンパイル時間の短縮
  - 2021年では, 計算機, コンパイラ, そしてリンカの性能が向上しました. これは使う理由にはなりません. 聞こえていますか？20年前から来たあなた
    - 時間は金で買うべきです, ビルドマシンぐらい金をかけましょう
  - 今のプロジェクトのビルドが遅い理由は, 次です. ビルドが遅すぎて, ビルドは一日一回, agileではなく, sluggishです, stupidでもいいです
      - Pimplを数多く使っているのに, includeが多い. コピペのせいもあるのですが
          - リファクタリングをしないので, コピペが修正されることは２度とない
      - inlineが多い
          - inlineを理解していない
          - コンパイラオプションで, できるだけinline展開するようにしている
          - inline展開で処理が速くなるとは限らない, これは今も昔も
      - コンパイラオプションで最大限の最適化を設定している
          - O2より上は速くなるかは環境依存, 遅くなることはよくある
              - 使用者が少ないので, 不具合も多くなる
          - コンパイラを理解していない
- 実装の隠蔽
   - 例えば, JavaやC#で困ったことはありますか？
      - 自分の意に沿わないからといって, ヘッダを書き換えるようなエンジニア？をチームに置いておきますか？ そちらの方が問題だと思います
  - インターフェイスを使って, FILEのようなことをすれば完全に隠蔽できるので, 使う理由にはなりません

## 欠点

- メモリコストと実行速度に悪影響がある
  - 処理落ちがどうのなど, 言っていることとやっていることが異なる
- 冗長
  - 処理を転送するだけの記述がコード量を増やす
  - コードを追うことに２倍のコストがかかる
  - たまにインターフェイスのメソッド名と, 実体のメソッド名が異なる
- ヘビークラスを作りやすい
  - これは当社比なのですが, 10年以上のエンジニア経験では, Pimplイディオムはくそでかクラスになりやすい傾向にあります
      - コンパイル時間の短縮という錦の旗, メモリコストと実行速度を考えると, Pimplイディオムがコンポジションに向いていないことが原因と思っています
  - コンポジションやアグリゲーションで, ソフトウェアを建築する, という考え方を持っている人には受け入れ難いです

# まとめ

他人に強制するつもりはありませんが, 価値のないイディオムだと思います.
yum update実行で、killedになってしまう

# yum update実行で「Killed」と出力される
途中で「Killed」と出力され、終了してしまう。

# 原因
メモリ不足。
t3.nanoインスタンスをケチって使っていたので、メモリ不足でシステムが終了していた。
スワップ領域を、1GB追加して解決。

## 参考
https://webbibouroku.com/Blog/Article/composer-killed
ActiveAdminなんて使う必要なんて実はなかった話....

別記事で掲載しているとおりですが、ActiveAdminを使用してテーブルのデータをインポートで登録しようと思っていました。

そして導入したわけですが、後から知ったことが普通にHerokuデプロイした後のテーブルも、SequelProから操作ができるということ...

https://hhmmm.hateblo.jp/entry/2016/02/15/204638

最初からこっちで良かったわ...

ちなみにインフラがAWSでも同じようなことはできるみたい。
https://bonoponz.hatenablog.com/entry/2021/02/04/%E3%80%90AWS_RDS%E3%80%91Sequel_Pro%E3%81%A7AWS_RDS%E3%81%AEMySQL%E3%82%92%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B
TerraformでBucket名にリージョン名とアカウントIDを動的に付与する

# リージョン、アカウントID取得

```terraform:main.tf
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
```

# Bucket名にリージョンとアカウントIDを使用

https://www.terraform.io/docs/configuration-0-11/interpolation.html

```terraform:s3.tf
resource "aws_s3_bucket" "artifact" {
    bucket = "artifact-pragmatic-terraform-${data.aws_region.current.name}-${data.aws_caller_identity.current.account_id}"

    lifecycle_rule {
        enabled = true

        expiration {
            days = "180"
        }
    }
}
```

```shell:terraform-apply実行時の抜粋
Terraform will perform the following actions:

  # aws_s3_bucket.artifact will be created
  + resource "aws_s3_bucket" "artifact" {
      + acceleration_status         = (known after apply)
      + acl                         = "private"
      + arn                         = (known after apply)
      + bucket                      = "artifact-pragmatic-terraform-ap-northeast-1-123456789012"
```
Pipelineを作る②フォルダ作成編: Cookiecutter

フォルダを適切に作るのは難しいのでテンプレートを使います。

https://cookiecutter.readthedocs.io/en/1.7.2/#

https://qiita.com/Hironsan/items/4479bdb13458249347a1

機械学習用のテンプレートは以下のようにして使います

```cookiecutter https://github.com/drivendata/cookiecutter-data-science```
CodeDeployとは？

## 勉強前イメージ

プログラムのデプロイを自動でするサービス？そのまま

## 調査

### CodeDeployとは

EC2やオンプレ、Lamda・ECSでビルドしたアプリケーションのプログラムなどファイル等のデプロイを自動で行うサービスです。
完全マネージド型のサービスになります。
デプロイの開始、管理、監視まで一元管理が可能です。

### 特徴

- 自動デプロイ・自動デプロイ

developer環境・staging環境・production環境、それぞれまたがるアプリケーションのデプロイを
自動化することが可能です。
また、EC2やオンプレなど複数環境がある場合でも同時にデプロイが可能です。

- ダウンタイムの最小化

ローリングデプロイ(複数のサーバーに対して順番にデプロイ)を行ったり、
置き換え方法でデプロイすることでダウンタイムを最小限に抑えることが出来ます。

- デプロイ履歴の参照が可能

過去のデプロイ履歴を保存しているので、バージョンの確認が出来ます。
また過去のリビジョンにロールバックすることも可能です。

### デプロイ方法

CodeDeployでは、以下の2種類のデプロイ方法があります。

- In-Place

アプリケーションを一旦止めて、最新版を上書きし
テストが完了した後再起動を行います。
EC2とオンプレで使用でき、古いバージョンで稼働するということを防ぐことが出来ます。

![1# Codedeployとは？ - diagrams.net - Google Chrome 202.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/a15db7d5-61fd-1822-66d8-0ed06ee7496c.png)


- Blue/Green

アプリケーションを新しい環境で新バージョンのテストを行い、
テストが完了した後本番環境に移行する方法です。
こちらの方法ではELBが必要になります。

![2# Codedeployとは？ - diagrams.net - Google Chrome 202.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/5a514594-ecbe-d7de-46c1-adf533457849.png)


## 勉強後イメージ

自動でデプロイまでしてくれる・・・
しかもオンプレも！

## 参考

- [[AWS Black Belt Online Seminar] AWS CodeDeploy](https://d1.awsstatic.com/webinars/jp/pdf/services/20210126_BlackBelt_CodeDeploy.pdf)
- [CodeDeployでデプロイを簡単にしよう](https://www.acrovision.jp/service/aws/?p=1174)
- [AWSのCodeDeployでデプロイしよう！特徴5つとメリットを紹介](https://www.fenet.jp/aws/column/aws-beginner/449/)
Pipelineを作る①準備編: JupyterLab + GitHub

1. GitHubアカウントでrepositoryを作成する

この記事を参考にします

https://qiita.com/cleeeear/items/2fa90aded84e90f9bff5

Jupyter Labのinstall

https://jupyterlab.readthedocs.io/en/stable/getting_started/installation.html

```conda install -c conda-forge jupyterlab```

詰まったポイント
・先にrepositoryを作成した場合はgit pullを行う
・Gitとの連携はJupyterLabのextensionを使う
```conda install nodejs```
を行ってから
```conda install -c conda-forge jupyterlab-git```
でinstall

・Jupyter Labの起動方法

https://jupyterlab.readthedocs.io/en/stable/getting_started/starting.html

これでJupyer Lab上でGitHubとの連携ができるようになりました。
WSL上のUbuntuにTeraTermでログインしてみる

#はじめに
今回の記事の主旨をまとめておきます。
・wsl2上にUbuntu環境を構築している。
・Windowsの標準ターミナルではログの取り方がめんどくさい。
・使い慣れたTeraTermからログインして、自動でログ取得できるようにしたい。

という経緯から、いろいろ設定を入れてみました。

#環境
以前18.04を導入した記事を書いていますが、今回は同様の手順で20.04をインストールした環境で行います。
[WSL上にUbuntu18.04を構築してみた](https://qiita.com/nnydtmg157/items/901099843fe89eb1ff42)
※systemdの変更はしていません。init.dで作業しています。

#設定手順
以下の要領で設定していきます。

* UbuntuでのSSHの設定
* TeraTermのダウンロード
* ログ自動取得設定

では、作業開始です。

##SSHの設定
まずは、Ubuntu側のSSH設定を行います。
現時点では標準ターミナルからログインし操作します。
openssh-serverをインストールします。

```
$ sudo -E apt update
$ sudo -E apt upgrade ← 必要に応じて..
$ sudo -E apt install openssh-server
```

SSH鍵の作成を行います。

```
$ sudo ssh-keygen -A
```

/etc/ssh/sshd_configの設定を変更し、パスワード認証の許可を行います。
vi等で/etc/ssh/sshd_configを開き、以下の設定を変更します。

```:/etc/ssh/sshd_config
Port 10022 # sshd を 22番以外のポートで立ち上げたい場合(今回は変更していません)
PasswordAuthentication yes # パスワード認証を許可したい場合
```

SSHを再起動します。

```
$ sudo /etc/init.d/ssh status
以下が表示されればOK
active (running)

$ sudo /etc/init.d/ssh restart
以下が表示されればOK
[ ok ] Restarting ssh (via systemctl): ssh.service.
```

※SSH起動がうまくいかない場合はwsl2を再起動してみてください。再起動時は特に意識せず、標準ターミナルから接続すればOKです。

```
wsl.exe -t Ubuntu-20.04
```



##TeraTermのダウンロード
次に、TeraTermのダウンロードを行います。
こちらからダウンロードしてください。(https://ja.osdn.net/projects/ttssh2/releases/)
インストール設定はご自身に合わせてカスタムしてください。(基本的にはデフォルトで問題ないです。)

##SSH接続してみる
Teratermを起動します。起動後に以下のように設定します。(ホスト名はlocalhostで良いです。)

```
ホスト：接続先ホストのアドレス（ドメイン名もしくはIPアドレス）
サービス：SSH
TCPポート：22
バージョン：SSH2
```

初めての接続の際は認証許可画面が出るので、「続行」をクリック。
その後、Ubuntuで設定したユーザーとパスワードを入力しプロンプトが表示されれば接続完了です。


##ログの自動保存設定
TeraTermでログの自動保存設定を行います。

* 上部メニューから、「設定(S)」を選択します。
* 「その他の設定(D)」を選択します。
* 「ログ」タブを選択します。
* 「自動的にログ採取を開始する(U)」にチェックを入れる
* ログの保存先、ログファイル名を入力する。ログファイルは「%Y%m%d_%H%M%S_&h.log」とすると「年月日_時分秒_ホスト名.log」となります。
* オプションは適宜設定してください。個人的には「追記(A)」、「プレーンテキスト(P)」、「タイムスタンプ(T)」を設定しています。
* 設定が終われば「OK」をクリックします。　

※この時点では次回以降再設定が必要になるので注意してください。

* 再度上部メニューから、「設定(S)」を選択します。
* 「設定の保存(S)」をクリックします。
* TeraTermの保存フォルダに保存します。(例）C:\Program Files (x86)\teraterm
* TeraTermを開きなおして、ログが保存されていることを確認する。

以上で設定完了です。この他、表示設定なども同様の手順でカスタムできますので、ご自身に合った設定を見つけてください。


#最後に
これでやりたいことはできました。
標準のターミナルでログが簡単に取れれば良いのですが、ちょっと手間をかけてSSHの設定を触る機会にもなり、使い慣れたTeraTermに移行するタイミングが生まれたので個人的には良かったです。
ぜひ参考にしていただければうれしいです。

ちなみに、wsl2は起動するたびにIPが変わってしまうので、IPでの接続をするためにはちょっとした工夫が必要です。
こちらが参考になるかと思いますが、普段使いであればlocalhostで十分かと思います。(https://kemasoft.net/?vm/wsl2%A4%CB%B8%C7%C4%EAIP%A4%C7ssh-server)

#追記
次回以降sshを都度起動する必要があったので、ローカルからbatファイルでssh起動できればと思っていたところ、
自動でsshdを起動する方法を掲載されている方がいらっしゃったので、参考にさせていただきました。@nashi2603さんありがとうございます！
[Windows10のWSL上にあるServiceを簡単に自動起動させる](https://qiita.com/nashi2603/items/d0645305b137017b91b0)
Redisのdumpについて

# そもそもRedisの仕様

Redisはオンメモリであるため、終了すると全てのデータは削除される

では、データの永続化はどのようにしているのか？

デフォルトでは、メモリの内容を定期的にファイルに保存する設定になっている
つまり、自動的にバックアップがとられている形（※1）
バックアップファイルの場所と名前はデフォルトでは、``/var/lib/redis/dump.rdb``らしい（※2）

起動時にバックアップファイルが存在すれば、自動的にそれを読み込む

※1：手動のバックアップコマンドも存在する（``save, bgsabe, lastsave ``など）
※2：正確には``redis.conf``ファイルの``dir, dbfilename ``を参照して確認すべき

# dumpをとりたい場合

以上のことから、バックアップファイルがdumpファイルになり得る
しかし、そのままだと自動的に中身が更新され続けるので、dumpしたい時点でバックアップファイルを移動 or 改名 or コピーする必要がある

当たり前ではあるが、、、
移動や改名した場合は、バックアップファイル``/var/lib/redis/dump.rdb``が存在しないことになるため、Redisを起動すると何もデータが入っていない状態となる
コピーした場合は、元のバックアップファイル``/var/lib/redis/dump.rdb``は存在するため、Redisを起動するとデータが入っている状態となる

# dumpしたデータを戻す

いわゆるリストア
``/var/lib/redis/``ディレクトリ配下に``dump.rdb``という名前でdumpファイルを置いてあげればOK

その後、Redis再起動してデータが入っていればOK

# 参考
- [redisデータバックアップとリストア - Qiita](https://qiita.com/kkam0907/items/9a384fa260fdc5b4b047)
- [【2020年最新版】【Redisメモ・２】基礎設定、バックアップ、リストア](https://www.servernote.net/article.cgi?id=redis-note-2)
pythonでゾンビプロセスを作る方法

★はじめに
httpdサービスのプロセス監視をするためのスクリプトを作っている最中に
「個数だけだとゾンビプロセスが大量発生に気づけないからそれは除外したいなぁ」と
考えて、つくってみたけど「ゾンビプロセスがないと確かめようがないなぁ…」って
嘆いていたら、ありがたいことにコードを公開している方がいらしたのでありがたくお借りすることに。

★参考先
シンプルでホントに助かりました。
https://gist.github.com/nobonobo/4670476

★実行結果がコチラ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/d0d26592-5d40-7e71-c683-14f70e826468.png)

で、このときのpsの様子がコチラ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/70be67fe-7d53-8feb-5ae3-1055588b7bce.png)

★Ctrl-Cで止められる
超簡単！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/05e88fda-7829-b89f-1193-bd35f25d468f.png)
Cloudflare アカウントのユーザー管理

# 概要

図にしてみると、こんなイメージです。
ユーザーはメールアドレスに紐付き、複数のアカウントに所属できます。
また、ご利用中のアカウント[プラン](https://www.cloudflare.com/plans/) によって利用できる機能が異なります。

> [Introducing Multi-User Organizations: Share An Account Without Sharing A Login](https://blog.cloudflare.com/introducing-multi-user-organizations-share-an-account-without-sharing-a-login/#:~:text=Multi%2DUser%20is%20an%20Enterprise,enabled%2C%20contact%20your%20account%20manager)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/96f51ae7-482e-338e-8751-bac8e604617c.png)

# Free / Pro / Biz アカウント

RBAC によるユーザー権限管理機能はなく、1人の Super Administrator が複数の Administrator をメンバーとして招待できます。

> [Setting up Multi-User accounts on Cloudflare – Cloudflare Help Center](https://support.cloudflare.com/hc/en-us/articles/205065067-Setting-up-Multi-User-accounts-on-Cloudflare)

![image-20210616172800316](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210616172800316.png)

# Enterprise アカウント

Organization という枠組みのもとで、RBAC によるユーザー権限管理ができます。
また、複数人に Super Administrator を割り当てることもできます。

![image-20210616174013228](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210616174013228.png)

![image-20210616174136428](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20210616174136428.png)

## ロール詳細

こちらの API を使って、各ロールごとの詳細な権限設定が確認できます。

> [Cloudflare API v4 Documentation](https://api.cloudflare.com/#accounts-list-accounts)
結局のところ「記録」より「記憶」

最初にお断りしておくと...表題の件の後半は某野球選手の言葉ですね。

スクラム開発手法とか、正しいやり方とかで顧客の要望や満足に応えるサービスを作る。
ビジネスの価値を証明する手段として開発スピードや成果物の量などから形として「記録」を提示する。
仲間の貢献を「記録」をもとにフィードバックする。

それってもちろん大切なことだと思います。


自分がよく思うのは
記録を作るだけの人生に価値がどれほどあるのだろうかということです。

こういうでしょう
「ビジネスをやっている以上、記録でモノをいうべきだ。何よりやった証明・証拠がいる」

確かに。

でも
チームで動いているのは人間です。
顧客も人間です。
お客様も人間です。

自分が思うのは
対価を払ってやってもらったことに対して
記憶が残ったことを振り返り感謝するようにしています。

それは
やってくれた人がいて
何かを残した証だと思っています。

そして
反対の立場でも
何かを残してみせる

そろそろ
記録だけを残そうとするマインド
やめてもいいのかなって思います。

1日
1年

今年何したっけ?
って、ある種の「記録病」を要因にしていると思ったりもします。

そろそろそういうの
やめてもいいのかなって。

生き方として。
残プロ　第-15回　~cronでpythonを定時実行する~

# 第-11回のコード

以下のように書くと**毎日午前7時に定期実行**でした．


~~~ cron:
0 7 * * * python3 /home/pi/Documents/hello.py
# 書き方は[分　時　日　月　年　コマンド]
~~~


これを**7, 16時に実行**するように変えていきたいと思います．


# /nで毎nごとに実行

単純に1行増やしてもいいのですが，せっかくなので少し別の方法を試します．

1.まず，crontabに1時間ごとに実行として登録．


~~~ cron:
0 /1 * * * python3 /home/pi/Documents/hello.py
# 書き方は[分　時　日　月　年　コマンド]
~~~


# main関数

2.main関数を定義して時間で条件処理

先日，コメントから「main関数使うといいよ～」と教えてもらったので，せっかくですし使ってみます．


~~~ python:
import datetime

def main():
    print(datetime.datetime.now().hour)


if __name__ == '__main__':
    if datetime.datetime.now().hour in [7, 16]:
        main()
~~~


in演算子を使いました．リストに含まれた場合はmain関数実行となります．
IBMQで3-SAT問題

# 3-SAT問題

Groverの量子アルゴリズムを用いて、SAT問題が解けます。
qiskit SDK のテキストブックには、3-SATの例があります。
https://qiskit.org/textbook/ja/ch-applications/satisfiability-grover.html

こちらを**実機の量子コンピュータで**やってみます。

# コード

テキストブックをそのままコピペすればよいですが、実機でやるにはIBMQのアカウントをロードする必要があります。
おすすめは、IBMQのWebページ上にある　IBMQ Quantum Lab というクラウド開発環境を使うことです。
こちらで作業しますと、単に

```python
from qiskit import IBMQ
provider = IBMQ.load_account()
backend_dev = provider.get_backend('ibmq_16_melbourne')
```

と書けば、（アカウント情報は自動的に保存してくれているので）いきなり実機へアクセスできるインスタンスbackend_devが手に入ります。
あとは、実際に投げるだけです。

```python
quantum_instance = QuantumInstance(backend_dev, shots=1024)
result = grover.run(quantum_instance)
print(result['result'])
plot_histogram(result['measurement'])
```

今回は量子ビットがたくさん必要な回路なので、一番大きい”メルボルン”に投げます。
そこそこ人気があるので、待ちます。私は20分待ちました。

セッションがきれてしまった場合、IBMQのWebページ上のQueueに積まれたタスクから、タスクのIDを拾ってきます。
IDがわかったら、それを指定することでタスクをサルベージできます。

```python
job = backend_dev.retrieve_job('60c9edf...hogehoge')
```

詳細に中身を見たい人は `vars(job)` とすればよいです。
次に、jobから測定結果を引っ張り出してヒストグラムにします。

```python
result = job.result()
plot_histogram(result.get_counts())
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/4685467a-cf23-66b1-da7c-91d7ab87680f.png)


どこが解やらわかりません。

`vars(job)`によると、この回路のゲート数は
`'gates_executed': 913`
だそうです。そりゃ、無理ですな。


# まとめ

3-SATは今の量子コンピュータには難しすぎる。
AutoML（VARISTA）を使ってみた

* 製造業出身のデータサイエンティストがお送りする記事
* 今回はAutoML（VARISTA）を使ってみましたので、メモとして残しておきます。

## VARISTAとは
[VARISTA](https://www.varista.ai/)は、機械学習を効率的に行うためのプラットフォームです。つまり、AutoMLですね。DataRobotやdotDataとかと一緒です。
後者の二つのAutoMLは有料ですが、VARISTAは無料でも一部機能が使えます。

## 基本的な流れ
GUIで全てできるので細かい説明は不要かと思いますが（サポートもでますので）、簡単に下記に整理しておきます。

1. データセットを準備（サンプルデータも用意されております）
2. 構築するモデルを作成
    - 構築できるモデルは決まっております（無料プランのみ確認）
        - XGBoost
        - lightGBM
        - catboost
        - scikit-learn（一部）
    - 有料プランではもっと他のモデルが使える可能性があります。
3. モデル学習
4. 学習モデルの評価
5. その他
    - ハイパーパラメータが利用可能です

## 実際の使い方
#### データのアップロード

今回はサンプルのタイタニックのデータをアップロードしております。
無料版では、100MBぐらいまでのデータセットなら使用できるようです。
プロジェクトは一つしか作成できないので、本当にお試しという感じですね。

![スクリーンショット 2021-06-16 23.15.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/b505f610-0d70-2e8c-f881-ca4607d135a3.jpeg)

アップロードしたデータは、下記のような感じで各カラム毎にデータの型、欠損値、使用可否を簡単に確認・選択できます。

![スクリーンショット 2021-06-16 23.16.42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/bc5875da-64e9-9a7e-c1ca-17032f963932.jpeg)


#### モデルの構築

次に構築するモデルを作成します。無料プランではサンプルでいくつかのモデルが作成されております。
一番上の「lightGBM_classificaion」が今回作成したモデルであり、その他はテンプレとして用意してくれているモデルです。

![スクリーンショット 2021-06-16 23.18.45.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/4c5ff21b-4cd3-47de-0013-a4c12b80e09d.jpeg)

モデルを構築する際は、構築するモデルの目的（回帰、分類）を選択し、前処理や検証データの分割方法とかを選択できます。

![スクリーンショット 2021-06-16 23.19.53.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/24bf009e-86ab-d4ad-ee72-70bc2282ce27.jpeg)

その他、アルゴリズムはハイパラチューニング方法も選択できます。
ハイパラチューニングはグリッドサーチ、ランダムサーチ、ベイズ最適化（Hyperopt、optuna）が選択できます。
その他、ハイパラの探索範囲なども選択できるようになっております。

![スクリーンショット 2021-06-16 23.21.12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/d718068d-5d8e-9c9a-524d-2b397037cd66.jpeg)


#### モデルの学習

あとは、モデルを選択して学習します。

![スクリーンショット 2021-06-16 23.23.39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/a1d6977d-dafd-3a9a-7c90-d27b70cdce4f.jpeg)


#### 構築したモデルの評価

構築したモデルの中身を見て評価を行います。
分析できる項目としては、ある程度揃っている印象があります。

![スクリーンショット 2021-06-16 23.24.24.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/72e3ad76-a3ac-32f5-c388-5e19c64391dc.jpeg)

![スクリーンショット 2021-06-16 23.24.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/4193259e-3124-951f-7ca6-0579c9319567.jpeg)

![スクリーンショット 2021-06-16 23.24.56.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/8d1de080-8c00-cac8-081e-e6bf1477cb17.jpeg)


#### その他

構築したモデルのハイパラもyamlファイルで取得可能です。
ただし、pythonで完全に同じモデルを再現できるのかどうかは確認しておりません。

![スクリーンショット 2021-06-16 23.26.19.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743453/72cf70b8-f321-e1ad-8588-59309b83b467.jpeg)


##さいごに
最後まで読んで頂き、ありがとうございました。
今回はAutoML（VARISTA）を使ってみましたので、メモとして整理してみました。

有料版を試していないので分からないですが、モデルの種類に関してはDataRobotが一番多くて良いのかなとは思います。
また、dotDataは特徴量エンジニアリング自動化の部分が強みです。
VARISTAは上記2つのAutoMLツールに対してどのような優位性を持って戦っていくつもりなのか、無料版では見えてこなかったため、そこら辺が分かると選択肢の候補として上がるのかなと思います。
一方で、無料でもお試して簡単に使えるのは良かったです。
互いにnp.nanを含む2つの集合をunionした際にnp.nanが2つ残存する現象

# 概要
- この記事は解決策ではなく現象のメモです
    - 理由や解決策をご存知の方は教えてください
- 互いにnp.nanを含む2つの集合(setA, setB)をunionした
    - setC = setA.union(setB)
    - 期待：結果の和集合にはnp.nanは(当然)1つ含まれる
    - 結果：結果の和集合にはnp.nanが(なぜか)2つ含まれていた
- 何故にwhy? # 未解決
    - 原因を探ってみた
        - 和集合に含まれる2つのnp.nanはidが異なる
            - np.nanA, np.nanBとする
            - 通常のnp.nanのidとも異なる
        - np.isnanとmath.isnanでは共にTrue
        - np.nanA is np.nan, np.nanB is np.nanはFalse
            - 通常はnp.nan is np.nan はTrueのハズ
    - np.nanA, np.nanBの生成過程で別インスタンスになっている？
        - なお、元集合は異なるpandas dfの列から生成している
            - setA = set(dfA['colname'].unique().tolist())
            - setB = set(dfB['colname'].unique().tolist())
- 暫定対処
    - 元集合の生成時にnp.isnanを噛ませた
        - ar_A = dfA['colname'].unique()
        - setA = set(ar_A[~np.isnan(ar_A)])
    - np.nanは処理が全て終わってから要素として追加（どうせ含まれてるので）
- 環境
    - python 3.8.8
    - pandas 1.2.4
    - numpy 1.20.1
MacOSでPythonでクリップボードへリッチテキストをコピーする方法

## はじめに

何かと便利なクリップボード、コピペでソースコード取ってくるのはもちろん、Clipyなどのツールを使えばスニペットまで設定できてしまいます。リッチテキストも便利ですよね。太字やリスト形式をそのままコピーできて、Slackなどのメッセージをコピペするときに重宝します。
今回はそのクリップボードをPythonからいじる方法についてまとめてみました。

## セットアップ

MacのOS機能にアクセスするためにPyObjCをインストールします。

```bash
pip install pyobjc
```

## 関数の定義

```python
import AppKit
import Foundation


def copy(plain, html):
    data = {
        'public.utf8-plain-text': plain,
        'public.html': html
    }
    pb = AppKit.NSPasteboard.generalPasteboard()
    # クリップボードの内容をクリアする
    pb.clearContents()
    pb.declareTypes_owner_(data.keys(), None)

    for fmt, value in data.items():
        # 内容をエンコードする
        new_data = Foundation.NSString.stringWithString_(
            value
        ).nsstring(
        ).dataUsingEncoding_(
            Foundation.NSUTF8StringEncoding
        )
        # クリップボードへ値をセットする
        pb.setData_forType_(new_data, fmt)
```

## 実行例

### 太字の設定

```python
copy('hoge', '<b>hoge</b>')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329945/e35a4a1f-7e81-b144-214c-c76809ea4104.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329945/b992aaa2-5f7b-cee0-77be-c311ce1762da.png)

プレーンテキスト(Visual Studio Code)でもリッチテキスト(Slack)でも貼り付けられていることがわかります。ただ、少し違いが分かりづらいですね:sweat: なので、次はもう少し分かりやすい例を出してみます。

### リストの設定

```python
copy('a. hoge\nb. fuga\nc. moge', '<ol><li>hoge</li><li>fuga</li><li>moge</li></ol>')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329945/7bd812bc-a591-34c0-c5d4-dd2015d72a25.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329945/15f25915-64a0-b136-5a3a-38c7da62a9a9.png)

この通り！プレーンテキストではa,b,cで指定し、リッチテキストでは`<ol>`とだけ指定していたので、数字で連番が振られています。

もちろんこのリストは入れ子にしても正しく展開されます。

```python
copy('dummy', '<ol><li>hoge<ol><li>ほげ</li><li>ふが</li></ol></li><li>fuga</li><li>moge</li></ol>')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329945/8e253ee0-70f7-4e0e-4eb8-d55bc9d481bc.png)
ちゃんと「ほげ」と「ふが」のアイテムが2階層目に入っていることがわかります。

この他にも*斜体*の`<i>`タグや、~~取り消し線~~の`<strike>`タグ、[リンク](https://example.com/)の`<a>`タグなどにも対応しているので良かったら試してみてください。

## 余談(この記事を書くに至った経緯)

僕は毎日Slackで日報を書くのですが、最初は自分宛のDMに日報のフォーマットを作っておいてコピペして使いまわしていました。しかし日付の部分を今日に変更することがだんだん面倒になってきました。定型文に日付を挿入しつつ箇条書きの部分まで自動的に作ってくれるととても効率的に入力できます。
便利なPythonのことだし、クリップボード操作用のモジュールもすぐに見つかるだろうと思ったのですが、なかなか見つかりません。やっとのことで[richxerox](https://pypi.org/project/richxerox/)というモジュールを見つけたものの、なんと開発がストップしていて、[bitbucketへのリンク](https://bitbucket.org/jeunice/richxerox)も切れてしまっているではありませんか。
そこで、richxeroxのソースコードを読み解いて、まとめたものがこちらの記事になります。
richxeroxのソースコードを自分で読んでみたいよという方は[こちら](https://pypi.org/project/richxerox/#files)からダウンロードしてみてください。
Spring 開発

## Spring 開発


# 概要
Java開発でも人気のある「Spring Framework」ざっくりだが、  
その開発での処理を記載していく。    
※  
・自分たちで開発したものをベースに記載をしていく  
・SpringBootも導入しているので、bean、Daoの記載は省略
  
# 目次
1. Spring開発の概要(あくまで個人開発ベース)
2. プロジェクトにおけるアノテーションの役割
  

# 1.Spring開発の概要(あくまで個人開発ベース)
MVCモデルで実装
- Controller  
　→ここでModel,Viewに指示
- Model  
　→データのやり取り  
　　→DBなどから
- View  
　→ユーザーインターフェース、いわゆるHTML部分
  

処理の流れのイメージとしては、  
Controllerで  
表示したいパス(HTMLファイル)を指定し、画面の表示をViewに命令  
画面表示に必要なデータを取得(更新や、削除含め)するようにServiceへ命令
  
上記を繰り返すことで、Webアプリとして完成する

# 2.プロジェクトにおけるアノテーションの役割
＠Contoroller
- コントローラーとなる部分  
- GetMapping()で指定されたパスに遷移する際に、処理が走る
- returnで表示するHTMLファイル名を指定する  
 →例だとindex.htmlを表示する
(例)

```java
@Controller
public class TestController extends Common {

    @GetMapping("/index")
    public String indexDisplay() {
    	
    	/* *****************************
    	  HTMLに渡すデータなどを生成、
    	  Serviceに渡したりなどの処理を記載
    	***************************** */
    	return "index"
    ｝
｝
```


＠Service
- Modelとなる部分  
- データのやり取りを行う  
 →DB操作や、純粋にリスト操作などデータ操作を行う  
(例)  
　CHATHISTORY型のArrayList作成
　Mapper(xml)ファイルのselectHistoryメソッドを実行し  
　DBからメッセージを取得

```java
@Service
public class MessageService {
    /* メッセージの履歴取得 */
    public List<CHATHISTORY> getMessageLog(int roomId) {
        /* メッセージ履歴格納用 */
        List<CHATHISTORY> messageLogList = new ArrayList<>();
        /* Mapper(xml)にてSQL実行し、メッセージ履歴を取得 */
        messageLogList = messageMapper.selectHistory(roomId);
		/* メッセージが格納されたリストを返す */
        return messageLogList;
    }
｝
```


＠Mapper
- Daoとなる部分
- DBアクセスする
- XMLファイル(MyBatis)を実行

```java
@Mapper
public interface messageMapper {
    /* 
    * メッセージ履歴の取得用のSQLを実行
    * SQLはXMLファイルに記載
    */
    public List<CHATHISTORY> selectHistory(int roomId);
｝
```

# まとめ
　Springの開発のイメージとしては、上記のような構成と処理の内容である。  
これによって、画面遷移ごとに処理が走り、期待するデータを取得、画面へ受け渡しを行い、Webアプリとして機能する。
【GIF動画でわかる】HTMLの要素を真ん中に持ってゆきたいが、どんなCSSを当てていいかわからないとき試してほしい方法。

![center.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166484/b1f12f2b-e22b-ee2a-7303-3dbad8948c45.gif)

## 動画の解説

1. Chromeを起動し、`Chrome Developer tools`を開きましょう。
1. `elements`パネルから真ん中に持ってゆきたい要素を選択しましょう。
1. 次に`element.style`に`center`と入力してみましょう。するとスタイル候補がズラッと表示されるはずです。
1. 候補が表示されたら、上下キーで順番に候補を変えていきます。
1. 画面表示が真ん中に変わるものが見つかりましたか？ それがあなたが探していたCSSのスタイルです。
Git rebaseを実施したらなんかエラーが出た 個人メモ

# 目的

- `$ git rebase`実行後にコンフリクトエラーが出たときの解決方法をメモ的にまとめる

# 情報

- `$ git rebase`を実行したら下記のエラーがでた。

    ```terminal
    $ git rebase master
    Auto-merging コンフリクトファイル名
    CONFLICT (content): Merge conflict in コンフリクトファイル名
    error: could not apply コミットID... コミットメッセージ
    Resolve all conflicts manually, mark them as resolved with
    "git add/rm <conflicted_files>", then run "git rebase --continue".
    You can instead skip this commit: run "git rebase --skip".
    To abort and get back to the state before "git rebase", run "git rebase --abort".
    ```
 
- 雑に翻訳してみた。

    ```
    $ git rebase master
    自動マージコンフリクトファイル名
    CONFLICT（コンテンツ）：コンフリクトファイル名で競合をマージ
    エラー：ダウンロードIDを適用できませんでした...
    すべての競合を手動で解決し、解決済みとしてマークします
    「gitadd / rm <conflicted_files>」を実行してから、「gitrebase--continue」を実行します。
    代わりに、このコミットをスキップできます。「gitrebase--skip」を実行します。
    中止して「gitrebase」の前の状態に戻すには、「gitrebase--abort」を実行します。
    ```

- 「rebaseを実施したらコンフリクトしたよ。なんとかしてね。」って感じのことを言われているっぽい。

# 解決方法

1. 下記コマンドを実行する。

    ```terminal
    $ git status
    ```

1. ステージングされていないファイルを開き、コンフリクトを解消する。
1. 下記コマンドを実行してコンフリクト解消したファイルをステージングする。

    ```terminal
    $ git add コンフリクト解消したファイル
    ```

1. 下記コマンドを実行してコミットする。エディタが開くが特にコミットメッセージは記載せずに保存する。

    ```terminal
    $ git commit
    ```

1. 下記コマンドを実行してrebaseを再度実行する。

    ```terminal
    $ git rebase --continue
    ```
【PHP】オーバーライドのサンプルソース

# コード
```PHP
class Goku {
  function skill($name, $damage){
    echo "孫悟空の必殺技！【{$name}】!なんと{$damage}ダメージも敵に与える事ができるんだ！",PHP_EOL; 
  }
}

class Gohan extends Goku {
  function skill($name, $damage){
    echo "孫悟飯の必殺技！【{$name}】!なんと{$damage}ダメージも敵に与える事ができるんだ！"; 
  }
}
$dragonball = new Goku();
$dragonball->skill('元気玉', '500');
$dragonballZ = new Gohan();
$dragonballZ->skill('魔閃光', '435');

```

# 結果
```
孫悟空の必殺技！【元気玉】!なんと500ダメージも敵に与える事ができるんだ！
孫悟飯の必殺技！【魔閃光】!なんと435ダメージも敵に与える事ができるんだ！
```
【GAS】Slackの特定のキーワードを拾ってNotionに保存する方法

社内でこんな要望があったのでやってみました
![Slack___shoppl-contents___fastbeat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165108/e6b16ff1-bd49-05b6-5ac0-138beea35328.png)

## 手順
1. [Notionの公式サイト](https://www.notion.so/my-integrations)からIntegration＋トークンを作成する
2. GASで後述の関数を作成＋ウェブアプリとして公開（デプロイ時に設定するアクセス権限は「全て」を選択すること）
3. SlackのOutGoing Webhookを設定し、手順2で公開したアプリのURLを設定![Outgoing_Webhook___Slack_App_ディレクトリ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165108/2767c4bf-2a65-d18c-819d-2061aefeb413.png)

## GASの実装
```javascript
function doPost(e) {
  // Slackのトリガーに設定した単語を正規表現で消す
  var text = e.parameter.text.replace(/`Idea`/g, '');
  var arr = text.split(/\r\n|\n/);
  
  var data = {
    "parent": { "database_id": {*** NotionのページURLにあるパラメータを入力 ***} },
    "properties": {
      "Title": {
        "title": [
          {
            "text": {
              "content": arr[0]
            }
          }
        ]
      },
      "Description": {
        "rich_text": [
          {
            "text": {
              "content": arr[1]
            }
          }
        ]
      }
    }
  }

  var headers = {
    "Authorization": "Bearer {*** Notionで作成したIntegrationのトークン　***}",
    "Content-Type": "application/json",
    "Notion-Version": "2021-05-13"
  };

  var options = {
    "headers": headers,
    "method": "post",
    "payload": JSON.stringify(data)
  };
  
  UrlFetchApp.fetch("https://api.notion.com/v1/pages", options);
}
```
※ String.splitで改行をキー配列に変換してますが、割と適当です。あしからず

## 結果
![Slack___shoppl-contents___fastbeat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165108/0a4330c8-9135-8921-546f-456b56ecb8f9.png)

![Idea_lists.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165108/0306005b-c66c-c861-91b0-a7846b00a914.png)

## 参考
- [Notion API Guide](https://developers.notion.com/docs/getting-started)
- [Notion API Documentation](https://developers.notion.com/reference/intro)
STM32F303K8でWS2812Bを光らせる。 (Mbed)


x Mbed NUCLEO-F303K8 Mbed2 リビジョン172

目的
GPIOのテスト

NUCLEO-F303K8

説明
WS2812Bの接続ピンは、A6(PA7)です。

プログラムは、STM32F103C8(Mbed)と同じです。

計算式
64Mhz(64,000khz)/800khz(1.25us)=80カウント
80カウントから処理分を引いた値　仮に70とした。

```c++


#include "mbed.h"

//Serial pc(USBTX, USBRX); // tx, rx
//Serial pc(SERIAL_TX, SERIAL_RX); //767 303
//RawSerial pc(PA_2, PA_3); //010
//Serial pc(PA_9, PA_10); // tx, rx 103

DigitalOut myled(PA_7);
                  //     65432109876543210
int on1  = GPIOA->ODR | 0b0000000010000000;
int off1 = GPIOA->ODR & 0b1111111101111111;

int l[90]; //max30 led

void bit_on1();
void bit_off1();

//             12345678   12345678   12345678   12345678
int b8[8] = {0b10000000,0b01000000,0b00100000,0b00010000,
             0b00001000,0b00000100,0b00000010,0b00000001, };

int ws_led(int num1)
{
    int on_off;

    //__disable_irq(); // disable interrupt
    //__enable_irq(); // enable interrupt

    //GPIO bkup
    //int g_bk  = GPIOA->ODR;


    for(int ii=0;ii<num1;ii++){
        //pc.printf("  -%d\t%d\r\n",ii,l[ii]); //303
        
        //8ビット分送る
        for(int jj=0;jj<8;jj++){
            //pc.printf("  -%d\r\n",jj); //103
            
            on_off = l[ii] & b8[jj];
        
            if( on_off == 0 ){
                //ビットが0
                //pc.printf("0"); //103
                bit_off1();
            } else {
                //ビットが1 
                //pc.printf("1"); //103
                bit_on1();
            }//endif
        
        }//for 8bit
        
        
    }//for max30byt

    //__disable_irq(); // disable interrupt
    //__enable_irq(); // enable interrupt

    //GPIO bkup
    //GPIOA->ODR = g_bk;

    return(0);
}

//メイン
int main() {
    
    //pc.printf("\r\n103\r\n"); //103
    GPIOA->ODR = off1;
    wait_ms(1);

    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

    l[0] = 31;
    l[1] = 32;
    l[2] = 33;

    ws_led(3);

    while(1){}

} //main

// 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 
void bit_off1(){
   //0.3us 800khz
        
        DWT->CYCCNT = 0;

        GPIOA->ODR = on1;
        
        while (DWT->CYCCNT < 17L){ 
         //a++;
        } ;
        
        GPIOA->ODR = off1;

        while (DWT->CYCCNT < 70L){ 
         //a++;
        } ;
                
}//bit_off1


// 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
void bit_on1(){
   //1us 800khz
        
        DWT->CYCCNT = 0;

        GPIOA->ODR = on1;
        
        while (DWT->CYCCNT < 47L){ 
         //a++;
        } ;
        
        GPIOA->ODR = off1;

        while (DWT->CYCCNT < 70L){ 
         //a++;
        } ;
                
}//bit_on1




```
【Go】echoを使ってAPIサーバを構築する際に起きたエラーの備忘録

#About
windows環境でVS Codeを使用。Goのechoを用いてApiサーバの構築のチュートリアルを行おうとした。

```Go:ApiTest.go
package main

import (
	"net/http"

	"github.com/labstack/echo/v4"
)

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "こんにちは!")
	})
	e.Logger.Fatal(e.Start(":1323"))
}

```

##どんなエラーが起きたか
```
package github.com/labstack/echo/v4: cannot find package "github.com/labstack/echo/v4" in any of:
        /usr/local/go/src/github.com/labstack/echo/v4 (from $GOROOT)
        /home/username/go/src/github.com/labstack/echo/v4 (from $GOPATH)
```
みたいなことを言われたので色々調べてみるとどうやら先に`go.mad`とやらを手に入れないといけない模様。

```
go mod init echo-sample
```

上記を実行してファイルを入手すると実行ファイルと同じファイル内に作成される。

これでもう一度実行すると

```
C:\Users\Documents\GoApp>go get github.com/labstack/echo/v4
go get: added github.com/labstack/echo/v4 v4.3.0
```

となり、`go.mad`ファイルを見ると

```Go:go.mad
module echo-sample

go 1.16

require github.com/labstack/echo/v4 v4.3.0 // indirect

```

GitHubの部分が追加されているのでこれでOKっぽい。
実行するとしっかり動いてくれた。
[公式GitHub](https://github.com/labstack/echo)を読んでもよくわからなかったので同じような状況に陥った方がいれば．．．。

また何分初学者のため指摘やご教授していただければなと思います。
【Swift】UITableViewのCellは再利用されるよって話

#はじめに
今回は皆さんも使ったことあるであろうUITableViewの話をします。
UITableViewのセルはメモリの関係で再利用されます。それゆえに思った通りの挙動になってくれないことがよくあります。

はじめの10個のセルの背景を赤色に変える処理を書いてみましたが、セルが再利用されているため、セルを追加してスクロールすると白色のセルのはずが赤色になってしまいます。

![ezgif.com-gif-maker (6).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/9d03ce83-6bef-c76a-83e3-3fb5f445a786.gif)

これの対処法を紹介します。

#実装
まずはセルの背景を赤くするところまで書きます。

```swift:ViewController
final class ViewController: UIViewController {
    
    @IBOutlet private weak var tableView: UITableView!
    private var testModels = [String]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setData()
        setupTableView()
        
    }
    
    private func setData() {
        (1...20).forEach { i in
            testModels.append("Test \(i)")
        }
    }
    
    private func setupTableView() {
        tableView.dataSource = self
        tableView.register(CustomTableViewCell.nib,
                           forCellReuseIdentifier: CustomTableViewCell.identifier)
        tableView.tableFooterView = UIView()
    }
    
    @IBAction private func addButtonDidTapped(_ sender: Any) {
        testModels.append("Added Text")
        tableView.reloadData()
    }
    
}

extension ViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return testModels.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.identifier,
                                                 for: indexPath) as! CustomTableViewCell
        let text = testModels[indexPath.row]
        cell.configure(text: text)
        if indexPath.row < 10 {
            cell.backgroundColor = .red
        }
        return cell
    }
    
}
```


```swift:CustomTableViewCell
final class CustomTableViewCell: UITableViewCell {
    
    static var identifier: String { String(describing: self) }
    static var nib: UINib { UINib(nibName: String(describing: self), bundle: nil) }
    
    @IBOutlet private weak var label: UILabel!
    
    func configure(text: String) {
        label.text = text
    }

}
```

ここまでのコードだと先程のような挙動になってしまいます。

次に、カスタムセルに以下のように記述しましょう。

```swift:CustomTableViewCell
    override func prepareForReuse() {
        super.prepareForReuse()

        backgroundColor = .white

    }
```

[prepareForReuse](https://developer.apple.com/documentation/uikit/uitableviewcell/1623223-prepareforreuse)は再利用可能なセルを準備するときに呼ばれます。このタイミングで先程挙動がおかしかった背景色を白にします。セルを追加しても初めの１０個のセルのみ背景色が赤になることを確認してみてください。


#おわりに
おわりです。
DDD ドメインサービスとは？

この記事は、筆者がドメイン駆動設計に関する本をいくつか読んだ結果つかえそうだとおもった知識をまとめるための記事です。

#ドメインサービスって？
業務知識の詰まった、ドメインに含めるべき処理であるが、それを直接エンティティや値オブジェクトのメソッドにすることがためらわれる場合につくると便利なサービス。

#ためらわれるときって？
ひとつには、複数の集約にまたがった処理をする必要がある場合。ドメインを直接操作してタスクをこなすクライアントでありながら、自身もドメインの知識であるならそれはドメインサービスとする。

ほかにも、単一の集約に対する操作ではあっても、そのメソッドとして記述してしまうと、ユビキタス言語をなめらかに表現したコードにならないとおもわれる場合はドメインサービスとする。

# 要はドメインのメソッドを切り出したもの？
ドメインサービスはその処理自身が業務知識となるが、無制限にドメインサービスとしてしまうとドメインが貧相になるので、まずはドメインとして記述する方法を模索し、うまくいかなそうなときに慈善の策としてドメインサービスを検討するとよさそう。
また、ドメインサービスは状態をもつこともさけるべきで、状態をもつのであればそれは見えていないエンティティや値オブジェクトの存在をまず疑うとよいとおもわれる。

# ドメインのクライアントならアプリケーションサービスでは？
ドメインサービスはあくまでビジネスロジックがつまっていてドメインにすべきものなのでアプリケーションサービスとは異なる。
アプリケーションサービスは、ドメインの業務を成立できるようにサポートすることを目的としているので、ここにドメインの知識をかかないようにする。