OmniAICreator/Qiita-1.07M huggingface dataset:
年収が1000万を超えるエンジニアのキャリアパス

この記事は、[マイナビ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/mynavi)の12日目の記事となります。
僕は非エンジニアですが、参加するからには読んでくれた方に有益な情報を提供する！という思い執筆させていただきます。
僕にテクニカルな記事を執筆することは難しいですが、営業、編集、開発、管理職、様々な経験を持っていますので、[マイナビ Advent Calendar 2020]の中ではちょっと視点の違う記事になると思います。

最初に今回のお話のお誘いをいただいた時に考えたのは、この記事を読んでくださる方の年代とパーソナリティでした。
Qiitaで投稿することからエンジニア系のお仕事をされているか目指している方。
年代はマイナビ社内で多いであろう20代の若手を意識しました。
僕自身のマイナビに入社する前の若手の頃はVC++を使って基幹システム開発をやっていました。
大変薄給で働いていたので、当時は「どうやったらお給料が増えるのか？」ということを必死に考えていました。
そんなうん十年昔を思い出しながら、絶対他のメンバーは書かないような下世話なタイトルで記載させていただきます。笑


#この記事の想定読者

* 将来稼ぎたい駆け出しのエンジニア
* 生活を安定させたい＆エンジニアになりたい大学生

など。
将来のキャリアパスや収入アップの具体的なビジョンを描けていない現職の若手エンジニアや、技術を身に着けて「手に職」的な考え方で安定した生活を図りたいと考えている大学生などをターゲットに考えています。


#この記事で得られること
具体的なキャリアパスの考え方、きっかけになればと考えています。

#この記事を書いている人
マイナビで現在はメディア運営側、編集・制作を行うセクションのマネージャーを努めております。
開発→営業→編集・制作と巡っているので、社内でも中々珍しいキャリアの持ち主です。
マイナビには中途採用で入社しておりますが、マイナビに入社する前はVC++基幹システム開発→WEBデザイン・制作→WEBディレクターという経験をしてきました。

#
結論めいてしまいますが、サラリーマンでコードやエンジニア領域の知識や経験を伸ばすだけで年収が1000万に到達するのは至難の業です。
純粋なエンジニアとして年収が1000万を超える唯一の方法はフリーランスor起業することです。
プログラミング言語別の平均年収を調べて見ると、時流の流れで変動はするもののいずれも1000万を超えることはありません。

2016年のマイナビニュースの調査では、1位がPythonで651万、2位はperlで633万、3位がRubyで606万と続きます。
誰もが知る世界規模の超大手メーカーのエンジニアでも年収1000万には届かないくらいだそうです。
これはつまりエンジニアとして一人前になったとしても年収1000万を超えるエンジニアは一握りということが言えると思います。

ではどうするか。
次に年収1000万を目指すエンジニアのキャリアパスに必要なスキルや経験を提示します。


#年収1000万を目指すエンジニアのキャリアパス
結論から言ってしまうと、年収1000万を超えるキャリアパスは大きく分けて二通りあります。
一つはエンジニアとして年収1000万を超えるルート。
もう一つはエンジニア以外の領域も経験して年収1000万を超えるルート。

エンジニアとして年収1000万を超えるにはフリーランスまたは起業して独立するのが代表的なルートです。
コードを書くのが好き、実際に手を動かしたい方にオススメのルートです。
僕が知る限りフリーランスで年収2500～3000万までは行けるようなので、フリーランスであれば年収3000万くらいが限界かも知れません。
厳密に言うと2000～3000万稼げるフリーランサーは案件を外注したり、複数の案件をこなしますので純粋なエンジニアではなくなっているかも知れません。
新規の案件を取る営業力、有利な条件で話をまとめたり与件を整理するコミュニケーション力も必要です。
規模が大きくなり起業した場合は、企業の形態や経営次第で青天井なのでここでは割愛します。

次に企業の開発セクションのマネージャーとして管理職に就くことも年収1000万超えの可能性があるルートです。
管理職として勤務するとコードを書く機会が減り、案件を生み出したり進行管理を行ったり、配下のメンバーをマネージメントする必要が出てきますのでマスターするべき領域も広がります。
エンジニア領域以外を経験して年収1000万を超えるルートを検討できるのであれば、営業領域の経験を積むことをオススメします。
あるいは商品企画やアイディアを出すようなセクションもオススメです。

僕の周りには営業で年収1000万を超える人もエンジニアで年収1000万を超える人も複数名知り合いがいます。
どちらもスペシャルな人材であることに変わりはありませんが、人数としては営業領域で年収1000万を超える人の方が多いです。
「人よりモノを売る力が強い」は分かりやすく、収益が発生するポイントに近い方が収益に貢献していると考えられやすいのかも知れません。
ということは営業的思考＋エンジニア的思考ができる、商品企画ができる＋自分で施策できるなどは希少性が高くなり貢献度も高まりますね。
まとめます。

**営業又は企画領域の経験＋エンジニアの経験**
＜メリット＞
つぶしが利く（起業もサラリーマンもお好みで）
社内の様々なセクションの人と同じ目線で話せる
自分ひとりで大抵のことができる

＜デメリット＞
スキルが中途半端になりがち
自分のスキルに関わらず色々な仕事を頼まれがち（人によってはメリット）

**企業のシステム開発セクションで管理職に就く**
色々な領域を学びたい！マネージメントもやってみたい！な人にオススメ
＜メリット＞
会社看板が使える
人的、物理的リソースが活用できる
報酬の安定性

＜デメリット＞
社長にならない限り上司がいる
勤務環境など自由になる領域が限られている
報酬の頭打ち
自分でコードを書く機会は減る

**フリーランスで活躍**
コード書きたい！現場に居たい！な人にオススメ
＜メリット＞
全てが自由
報酬も青天井
コードを自分が書いても書かなくてもOK

＜デメリット＞
開発以外の要件を自分で満たすかチームを組んで満たす必要がある
コーチ・メンターの不在により成長機会に乏しい
報酬が安定しない時もある

#最後に
報酬が全てではありませんが、報酬は少ないより多いほうがモチベーションも上がると思います。
色々書きましたが、この記事が将来のキャリアパスを考えるきっかけになれば幸いです。
読み解きがちょっとしんどいDB(テーブル)の特徴

# はじめに
今までの経験で「読み解きがしんどい…」と思ったDB(テーブル)について記載します。

ER図をむりやりリバースで出して何となく推測したり、利用されている業務ロジックを紐解いて「あ、ここで使われているんだね」と泥臭く見ていけば理解できることはわかっています。
しかし、そんな泥臭さを得なくても理解しやすいテーブル設計にする方が、ゆくゆくメンテする人も開発に携わる人も、みんなハッピーになると信じています。

あとは、自分が同じことをしないためにメモっておく意味合いもあります。。

# 1. 論理名がない
例）gyunyu_detail_master_abc　という名前のテーブルについて、説明なしのDDLとなっている。ぱっと見、何のテーブルなのか推測不可能。

物理名でテーブル説明を受けても、あまり頭に入ってこないです。

そのシステムへ長く携わる人からしたら、わかり切ったことだから物理名で話すのでしょう。
しかし、永遠に論理名のテーブルやカラム名で説明されるとしんどいです。

それが業務のコアな部分のテーブルだとなおしんどいです…

## 今後の教訓
DB設計するときは、面倒でも論理名をつける。
大切な業務を設計する場合は、必ず用語（と物理名）を定義する。

# 2. 用語揺れ
例）あるテーブルでは「milk」なのに、別のテーブルでは「gyunyu」と呼ばれている。

例のパターンだとまだ分かりやすいですが、専門知識を必要とする業務の場合、ぱっと見て「あ、これ同じなんだ」と分からないです。
また、例のように分かりやすい違いならいいのですが、微妙にスペルが違ったりしているといよいよしんどくなります。
例）gyunyuとgunuとmilk、みたいな。

過去に色々あったのでしょう。仕様を知らない人がスポットで入ってぱぱっと作ったのかもしれません。しかし、新参者の身としては、オロオロするしかないです…。

## 今後の教訓
用語（と論理名）を定義する。

# 3. マスタデータとトランザクションデータで、同じ意味合いのフィールド名が違う
例）マスタデータはgyunyu_idなのに、トランザクションデータはmilk_idとなっている

フィールドに限らず、テーブル名も微妙に命名パターンが異なると困ります。
作ったときに作業メンバーの仲が悪かったのかなぁと少し疑ってしまいます。。

## 今後の教訓

同一用語は同一論理名を使えるよう、用語を定義する。

# 4. マスタとトランザクションを紐づける項目が、IDではなく名称

例）牛乳マスタの値を注文テーブルに保持する時、IDではなく商品名「北海道xx牛乳」を持たせている。

何のためにIDが存在しているのだろうか…という気分になります。
これで2.や3.の症状を併発していると、ソースを深く深く根気強く読み解いて「あ、ここが繋がっているんだね」と気づく必要があります。

例のパターンでいうと、マスタの商品名が変更可能となってしまうと、紐付けを追いかけることができません。
トランザクションデータに断面的にマスタの情報を持ってくれていればいいのですが…持っておらずマスタデータを参照する必要がある場合、無理になります。

## 今後の教訓
一意かつ変化のないものを、リレーション関係として利用する

# 5. 謎の省略語

例）a_id、x_idなど

idであること以外、なにも分からないです。
これが業務のコアロジックに使われていて説明がないと…ほんとに何の話ってなりますね…😭

日本語の頭文字を取って「gn_id」みたいにしてくれていたらギリギリ推測がつくのですが（ダサいけど）。

## 今後の教訓

面倒に思ったとしても、フィールド名に適当な名前をつけない。

# おしまい

しんどくなったことがあったら追記するかもしれないです。

最初に概念設計とかして用語の認識合わせるのは、本当に大事なんだなーとしみじみ感じます。
Postfix の header_checks で From と Subject を同時に書き換えたい(その２）

# その２の事情

[Postfix の header_checks で From と Subject を同時に書き換えたい](https://qiita.com/nakacya/items/d773402ca71d04e4f738)	を実施すると「すべてのメールの From が変更されてえしまう」という問題が出てくる。
希望としては
## Subject で振り分けて From を書き換えたい
というのが理想でした。

# さて、どうやるか？
### 「postfix をマルチインスタンスで動かして Subject で振り分けて別インスタンスで書き換えれば良い」
という事がわかりました。

まずは「postfix をマルチインスタンスで動かす」はこちらのページをご参照ください。

[postfixのマルチインスタンス設定を用いた複数サーバー運用](https://qiita.com/henkeizyu/items/771b84ef7ed8ec160f0c)

## その後
### プライマリ(port 25)の設定変更
```conf:/etc/postfix/main.cf
header_checks = regexp:/etc/postfix/header_checks
```

```shell:サービス再起動
# systemctl restart postfix
```

```conf:/etc/postfix/header_checks
/^Subject: hogehoge-ML(.*)/ FILTER smtp:127.0.0.1:10025
```

### セカンダリ(port 10025)の設定変更
```conf:/etc/postfix-2nd/main.cf
smtp_header_checks = regexp:/etc/postfix/header_checks
```

```shell:サービス再起動
# systemctl restart postfix
```

```conf:/etc/postfix/header_checks
if /^(From: (.*))|^(Subject: hogehoge-ML(.*))/i
/^Subject: hogehoge-ML (.*)/ REPLACE Subject: [HOGE-ML] $1
/^From: (.*)/ REPLACE From: hoge-ml@examle.com
endif
```

こうやることで「 Subject: に hogehoge-ML と書かれていれば Subgect: [HOGE-ML] を追記し From: も hoge-ml@examle.com に書き換える」
というのが上手く動きます。

# まとめ
マルチインスタンスで処理することで色々と柔軟に書き換えることが可能になります。
ポイントとしてはプライマリの header_checks を smtp_header_checks では無く header_checks で動かすことで `FILTER` が動くようになります。(smtp_header_checks では動作しません。

# 参考サイト
[postfixのマルチインスタンス設定を用いた複数サーバー運用](https://qiita.com/henkeizyu/items/771b84ef7ed8ec160f0c)
[水銀室 Postfixをマルチインスタンスで起動する -CentOS最短構築支援-](http://hp.vector.co.jp/authors/VA022911/tec/centos/postfix_multi_instance.htm)
[Route mail in postfix to different relays based on subject](https://serverfault.com/questions/365458/route-mail-in-postfix-to-different-relays-based-on-subject/365701#365701)
【JavaScript 2020】 CodeceptJS でファイルのダウンロード

CodeceptJS を使ってファイルのダウンロードを試した際のメモです。
JavaScriptネタなので、後付けで [JavaScript のアドベントカレンダー](https://qiita.com/advent-calendar/2020/javascript2)の 25日目に登録もしてみました。

## CodeceptJS の利用
以前、自動化をあれこれ試していたときに使ったものの 1つに「[CodeceptJS](https://codecept.io/)」がありました。

その際、Puppeteer・Playwright・WebDriver との組み合わせをそれぞれ試したりして、Puppeteer との組み合わせをメインに使っていました。
そんな中、以下の記事を見かけて、Playwright との組み合わせなどをあらためて見直してみようと思い、それを試すついでに以前は試していなかったファイルのダウンロードも試してみたりもしました。

●2020年12月現在、puppeteerとplaywright どっち選んだらいいの？ - Qiita
　https://qiita.com/YusukeIwaki/items/a9dbd48b1ed4313f3815

このファイルダウンロード関連の話について、自分用のメモに残しておこうと考えて書いたのがこの記事になります。

## CodeceptJS でファイルのダウンロード

### codecept.conf.js への追記
以下のページの情報などを見ると、ファイルのダウンロードを行う場合は、codecept.conf.js に `"FileSystem": {}` という内容を記載する必要があるようです。

●"I.amInPath is not a function" on using FileSystem helper · Issue #931 · codeceptjs/CodeceptJS
　https://github.com/codeceptjs/CodeceptJS/issues/931

![ダウンロードのための設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/8a30b9dc-5874-3990-2afe-7e91f2a58892.jpeg)

具体的には、codecept.conf.js で以下のように追記をしました。

```JavaScript
  helpers: {
    Playwright: {
      【（省略）】
    },
    "FileSystem": {}
```

### プログラムの部分
ファイルのダウンロードについて、とあるファイルへのリンクがページ内にあり、それをクリックする動作でダウンロードが実行できる状況を想定しています。そのページでリンクを単純にクリックをするだけなら、以下のようになるかと思います。

```JavaScript
  I.click('【（クリック対象となるテキスト）】');
```

ファイルのダウンロード関連の情報で、公式ドキュメントを見てみると、以下の部分が見つかりました。

●Playwright | CodeceptJS
　https://codecept.io/helpers/Playwright/#handledownloads

![ダウンロードのためのコード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/dc3893f8-10bf-7848-a31a-5db3302255fc.jpeg)

ダウンロード対象が pptx で、01.pptx というファイル名で保存する場合、例えば以下のようにすれば良いようでした。

```JavaScript
  I.handleDownloads('files/01.pptx');
  I.click('【（クリック対象となるテキスト）】');
  I.amInPath('output');
  I.waitForFile('files/01.pptx', 5);
```

これにより、output フォルダのサブフォルダ「files」の中に、01.pptx が保存されるのを確認できました。
Access denied for user 'hoge'@'localhost' (using password: YES)

なかなか解決できなくて困ったエラーです。
パスワードは正しいはずなのに、MySQLを起動できない。
一通り調べた結果、どうしてもダメならMySQLをインストールし直せばいいとあったので、インストールし直しました。
しかし、インストールし直しても同じエラー。
どうしたものかといろいろ見たところ、インストールし直したときのログに答えがありました。

``` shell:ターミナル
% brew install mysql@5.7
（ログ一部抜粋）
To have launchd start mysql@5.7 now and restart at login:
  brew services start mysql@5.7
Or, if you don't want/need a background service you can just run:
  /usr/local/opt/mysql@5.7/bin/mysql.server start
```

上のログにある通り、`brew services start mysql@5.7 ` をターミナルに打ち込むと無事に起動できました！
【FileMaker】懐かしいあのフレーズをもう一度！ズンズンズン、、、♪

クリスマスということで、このネタで2020年Qiita FileMaker Go AdventCalendarを終わりたいと思います。

# まずは見て。
いつ出るかわからないフレーズを何度もトライし、やっと出ました！
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">32秒だけお付き合いください。<br>きよしこの夜だから✨<a href="https://twitter.com/hashtag/FileMaker?src=hash&amp;ref_src=twsrc%5Etfw">#FileMaker</a> <a href="https://twitter.com/hashtag/FileMakerGo?src=hash&amp;ref_src=twsrc%5Etfw">#FileMakerGo</a> <a href="https://t.co/UMotWyPbm5">pic.twitter.com/UMotWyPbm5</a></p>&mdash; Guppy Web Service (@GuppyWebService) <a href="https://twitter.com/GuppyWebService/status/1342454776022253573?ref_src=twsrc%5Etfw">December 25, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

さぁ。懐かしいですね。
Qiitaを調べてみたら、4年前に流行ったそうです。
[ズンドコキヨシまとめ](https://qiita.com/shunsugai@github/items/971a15461de29563bf90)

# キヨシを出そう！
今回は何もフィールドを作っていません。
作ったのは、
$$kiyoshi
というグローバルフィールドのみ。
![スクリーンショット 2020-12-25 21.39.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/676f02f7-e973-2af8-567a-b476adbf31b7.png)

「きよし！」の黄色い声援は、「ズンズンズンズンドコ」が出るまでお預けです。
![スクリーンショット 2020-12-25 21.40.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/4cbb136a-fbcf-aeab-3f0b-64f10163795b.png)

$$kiyoshiに溜め込まれたフレーズは、狙った物が出ない場合はクリアするようにクリアボタンを設置。
![スクリーンショット 2020-12-25 21.42.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/a87e7d37-b3a7-0b6e-fbca-7bbfad2591e0.png)

[湯婆婆ネタ](https://qiita.com/tyuma/items/a8a887e019b1d5e58ae7)として同じように、乱数で「ズン」「ズンドコ」を生成します。
２個しか言葉がないので、最初は乱数を２でやっていたのですが、それだとなかなかフレーズが出来上がらないので、４択にしました。
![スクリーンショット 2020-12-25 21.45.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/456f0e91-0cfa-dbf7-750a-be426b9d09ab.png)


実装は、たったこれだけです。
さぁ、みなさんも年末の紅白でも観ながらズンドコしてみましょう！

p.s.
FileMaker Goだけでなく、FileMaker Proでも動くのでFileMaker Go縛りではないな、、、と気付きつつもトリを務めました。
総務 system 設計概論

総務 system を構築するとしたらどうするでしょうか。
また、総務 system のクラウドサービスを設計するとしたらどうするでしょうか。

#範囲(scope)
大事なのは、範囲(scope)です。
組織にとって、総務とは、それ以外を意味します。

例えば、総務課と経理課がある組織では、
総務は経理以外ということになります。

例えば、総務課、経理課、人事課とある組織では、
総務は、経理、人事以外ということになります。

つまり、汎用的にありとあらゆることが熟せる上で、
その組織の事情に応じた範囲設定ができる必要があります。

例えば、経理、人事がすでにシステムがあれば、
それらのシステムと継ぎ目なく繋がることが大事です。

総務課、経理課、人事課、秘書課がある組織では、
総務は、経理、人事、秘書を除きます。

総務課、経理課、人事課、秘書課、企画課がある組織では、
総務は、経理、人事、秘書、企画を除きます。

総務課、経理課、人事課、秘書課、企画課、広報課がある組織では、
総務は、経理、人事、秘書、企画、広報を除きます。

総務課、経理課、人事課、秘書課、企画課、広報課、労務課がある組織では、総務は、経理、人事、秘書、企画、広報、労務を除きます。

総務課、経理課、人事課、秘書課、企画課、広報課、労務課、法務課がある組織では、総務は、経理、人事、秘書、企画、広報、労務、法務を除きます。

総務課、経理課、人事課、秘書課、企画課、広報課、労務課、法務課、技術課がある組織では、総務は、経理、人事、秘書、企画、労務、法務、技術を除きます。

総務課、経理課、人事課、秘書課、企画課、労務課、法務課、技術課、情報課がある組織では、総務は、経理、人事、秘書、広報、労務、法務、企画、技術、情報を除きます。

この話は際限なく続くかもしれません。

## 規模
10人の組織と、100人の組織と、1,000人の組織と、10,000人の組織と、100,000人の組織と、1000,000人の組織では、総務の仕事の項目が異なるかもしれません。

#項目(items)

割と特殊な業務から検討してみましょう。

### 総会屋対策
秘書課があるところでは秘書課が対応するかもしれません。
法務課があるところでは法務課が対応するかもしれません。
株を公開している株式会社での話ですから、小さい組織の総務には、原則関係ありません。
しかし、総会屋は業界新聞などを出していて、総会屋が対象にしている組織と取引のある小さな会社にも、業界新聞を売ったり、広告を出してという要請があったりします。総会をしない組織の総務でも、総会屋対策は一つの業務項目の場合があります。

### 暴力団対策
法務課があるところでは法務課が対応するかもしれません。
労務に関する事案が暴力団対策の重点である場合は、労務課が対応するかもしれません。
総会屋が明確に暴力団の配下にあれば、暴力団対策の中に総会屋対策があるかもしれません。

### 宴会対策
国会議員をはじめとする各種議員、内閣総理大臣をはじめ自治体の首長、業界団体の役員などとの宴会の設定は、かならずしも営業が担当しないことがあります。
営業は、直接の取引のある組織の宴会は対応するが、それ以外は総務で対応しないと、営業が疲弊してしまうからです。

場合によっては宴会の開催自体を報道媒体から秘匿したい時に、どこで何時に開催すれば、報道から秘匿できるかを把握している必要があります。
広報課が直接担当すると報道に漏れてしまうといけないので、総務が対応します。報道機関から広報に連絡があって電話に出られないと、調べられるからです。

###個人対応

組織内部、および外部の個人に対する対応で、法律上必須な事項以外を担当するのが総務です。

例えば、役員の家族であるとか、大株主の親族であるとか、直接規定していない事項の処理は総務が行います。
違法行為でないかどうかは、法務に調査してもらうとしても、手を汚すのは総務です。

所謂便宜を図るという類のことです。
取引先であれば、営業課、秘書課が対応しますが、それ以外の利害関係者の場合には総務が対応します。

# 設計思想

ありとあらゆる文書を作成発行できることが必要です。
場合によっては、システム全体を存在しなかったように秘匿できることも条件になるかもしれません。
場合によっては、公開できる部分と、非公開部分とを切り分ける機能が必要かもしれません。

時間（日程を含む）管理、空間（場所、物、人間）管理は必須です。

それらを柔軟に設定できることと、得た知見を体系的に整理できることが大事。

定型処理と非定型処理を連携できるとよい。

＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞
SQLAlchemyとSQLServerの組み合わせでupdlock, rowlock等をかける方法

# TL;DR

```python
session.query(Table).with_hint(Table, "WITH (ROWLOCK)").filter(Table.count > 0)
# SELECT * FROM Table WITH (ROWLOCK) WHERE count > 0
```


# やりたいこと

SQLAlchemyではロックをかける場合普通なら`with_for_update`メソッドを用いますが、以下の例を見ての通り、SQLServerに`FOR UPDATE`はないのでこの記述は無視されます。

```python
from sqlalchemy.sql import select, table, literal_column
from sqlalchemy.dialects import mssql

tbl = table("MyTable")
stmt = select([tbl]).where(literal_column("hoge") > 0).with_for_update()

print(stmt.compile(dialect=mssql.dialect()))
# SELECT
# FROM [MyTable]
# WHERE hoge > :hoge_1
```

# 解決策

SQLServerではロックはFROM句の末尾にロックヒントという形で`WITH (ROWLOCK, UDPLOCK)`などと記述します。SQLAlchemyでは`with_hint`というメソッドを用いて以下のようにヒント文字列を埋め込むことができます。

```python
from sqlalchemy.sql import select, table, literal_column
from sqlalchemy.dialects import mssql

tbl = table("MyTable")
stmt = select([tbl]).with_hint(tbl, "WITH (ROWLOCK)").where(literal_column("count") > 0)

print(stmt.compile(dialect=mssql.dialect()))
# SELECT
# FROM [MyTable] WITH (ROWLOCK)
# WHERE count > :count_1
```

めでたしめでたし

# 参考

https://docs.sqlalchemy.org/en/14/core/selectable.html#sqlalchemy.sql.expression.Select.with_hint

https://docs.sqlalchemy.org/en/14/core/selectable.html#sqlalchemy.sql.expression.Select.with_for_update

https://stackoverflow.com/questions/56030825/sqlalchemy-query-api-not-working-correctly-with-hints

https://www.m3tech.blog/entry/sqlalchemy-tutorial
FlutterでWebView実装・JavaScript有効化

まずは[pub.dev](https://pub.dev/)から"webview"を検索してみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499546/4d8595b8-7eed-f7b7-1d84-bb207141872f.png)
上から順番にポピュラーなWebViewプラグインが表示されたので、[webview_flutter](https://pub.dev/packages/webview_flutter/)を試してみる。Updatedも新しい日付なので選択として良さそう。

Android StudioでNew Flutter Projectを新規作成。
Flutter Applicationを選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499546/ba2fe103-e9e6-820b-b120-ff92c0a6d690.png)
WebView pluginを導入する手順が[Installing](https://pub.dev/packages/webview_flutter/install)に記載されているので順に進める。

pubspec.yamlのdependencies:配下にwebview_flutter: ^1.0.7の記載を追加。

```yaml:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.1
  webview_flutter: ^1.0.7
```

main.dartファイル冒頭に下記import文を追加。

```dart:main.dart
import 'package:webview_flutter/webview_flutter.dart';
```

クラス _MyHomePageStateの中で下記initStateを追加。
"Undefined name 'Platform'."との警告が表示されるので、`import 'dart:io';`もmain.dart冒頭に追加。

```dart:main.dart
@override
void initState() {
  super.initState();
  // Enable hybrid composition.
  if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}
```

`return Scaffold(...);`部分を下記コードで置き換え。

```dart:main.dart
@override
Widget build(BuildContext context) {
  return WebView(
    initialUrl: 'https://flutter.dev',
  );
```

これだけで簡単にWebViewを起動することができた。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499546/10343d91-f41c-9e5e-2388-a3dbe799c0a0.png" width="320">

# 初期設定URLの変更・JavaScriptの有効化

`https://flutter.dev`の部分を任意のURLに書き換えてみる。
`https://yahoo.co.jp`を表示させてみたところ"JavaScriptが無効です"と表示されたので下記手順でJavaScriptを有効化する。

`javascriptMode: JavascriptMode.unrestricted`の記載をURL初期指定の直後に追加。

```dart:main.dart
@override
Widget build(BuildContext context) {
  return WebView(
      initialUrl: 'https://yahoo.co.jp',
      javascriptMode: JavascriptMode.unrestricted
  );
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499546/758dc4e5-b65d-b51b-1a28-dff44b54b9da.png)

上記警告が表示されなくなった。

iOSシミュレータでも設定した初期URLのページを問題なく表示確認することができた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499546/9c5e748e-e071-4604-9d41-bcd43b7c071e.png)
memo

![humanpicto.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974586/909453cb-3645-d100-5ad0-8bc0bb449f0b.gif)
# はじめに
先日、動画ファイルを共有ドライブに上げ続けていたらあっという間に15GBの制限に突入してしまった。とりあえず古いいらないものから消して行ったが、どうにも反映されない...

# 仕様
Googleドライブは削除後、24時間から1週間程の反映のラグがあるようです。ゴミ箱のアイテムの完全削除や復元など、複数ファイルで行うと時間がかかる旨が公式のヘルプにも書いてありますね。

# 解決策 
Googleドライブのアイテムの削除が反映されるまでには24時間前後のラグがあるので、削除後は反映されるまでまつのが良いでしょう。ただ、追加購入の反映は即座なので、どうしても急ぐ場合には購入するのも良いでしょう。
「複雑」だった事例について振り返る


過去経験してきた現場のなかで、それぞれに違った「複雑」な事例がありました。
最近自分がやらかした事例も含めて振り返ってみたいなと思います。
(色々アレなのでぼかして書いています)


# 事情が複雑
医療系の現場で諸々要件を整理していく段階で、「この場合はこういうパターンなんだけどこの値があったらこうなって、その時に値がどうたら...」ってわかるかー！！！となりました。笑
紐解いていくと、そもそもそれを定めている法律やそれによって決まった業界内での規程などがあってそうならざるを得ないという状況。

これはどんな業界にも言えることかも知れませんが、業界特有の事情で要件が複雑になる場合、実装する人は大変だけどその分乗り越えれば他社が簡単に参入できない障壁にもなるわけで。

ドメインエキスパートが社内にいてガンガン活躍できるのであれば、あえてその道をいくのもアリなのかもしれません。

# 施策が複雑
ビジネスの目標としてある数字を達成したいとなった時、そのために行う施策の設計（これは企画サイドが行った）が複雑であったために、以下のような事象が起こりました。

- 施策の内容が複雑なため、ユーザーに意図が正しく伝わらない
- ↑の状況から頻繁に問い合わせが来るため、サポートチームが適切な説明をする手間を取られる（しかも、施策の難しさ故に説明がまた難しい)
- 施策が複雑なため実装自体にバグが混入しやすい（実際した。そうするとまたユーザーから問い合わせが...という負のループに)

振り返ってみると、最初に立てたビジネス目標を達成するために本当にこの施策であるべきだったのかは多少の疑問が残ります。
特に、ユーザーに意図が伝わっていないというのが大きな問題で、両者のキャッチボールが正しくできる施策をリリースするというのはめちゃくちゃ大事なんだなというのが個人的に学びでした(今まであんましこういった事例にあったことがなかった)。

「こうありたい」という目標に対して、できるだけその意図を正しく簡潔に伝えるにはどうしたら良いのか？に拘らないとそのあとの工程、運用で苦しむことになる。

# 実装が複雑(設計ミス)
これはプログラミングの話で、ある要件があった時にそれをシンプルな形で実装できていないというケース。
例えば、本来レコードは1対1で結びつけたいモデル(has_one <-> belongs_to)があるんだけど、様々な事情によりそれを直接は実装できない、となった時。
間にもう一つテーブルを置けばある程度簡単にクエリのやりとりができそうですが、それをやらずにクエリを複雑に組み立てることでテーブルを置かずに実装した。という事例がありました。(そうです私です...orz)
簡単に正規化できないモデルが現れた時、それを無理やりどうにかするんではなくよりスマートに解決できる方法はないか？と考える姿勢、大事です。またそれを個の力ではなく組織の力として発揮できる状況にあるか？というのも大事だなと思いました。

# 実装が複雑(責務が分離できていない)
こちらも割とプログラミングの話。
とある現場にて「サイト全体のSEO(検索エンジン最適化)を強くしたい」という要望が過去にあったそうで、その際にSEOのコンサルティング会社から「自サイト内の検索に使えるタグを増やすのと、そこへのリンクやコンテンツを増やしていくべき」という助言を受けたそうで。
結果生まれたものが、「既存のサイト内の地域別検索に、SEO用の検索とコンテンツロジックを組み込む」というもの。
お前は何を言ってるんだと突っ込まれそうですが、僕も何言ってるのかよくわかりません笑
初めて実装を見た時に本当に何がしたいのかよくわからんかった。。。あれほど闇深いElasticSearchはなかなかないと思う。
ここから学んだことは、「SOLID原則って本当に大事なんだなあ」ということ。
やりたいことを一つのクラスにそのまま実装してあげればそんなに難しくならないはずのものが、一つのクラスに色んな振る舞いを実装してしまうからおかしなことになってくる。
この事例について言えば、検索ロジックが複雑だからSEOでも使いまわしたかったという事情があったのかなと思いますが、それをやったが故にとても難解なコードになり、結果SEOのトレンド変わる際にメンテを入れてくのが余計にしんどくなったという悪循環がありました。
原理原則と呼ばれるものの大事さを身にしみて感じた事例でした。

# 顧客の要求が複雑
これはどの現場にも共通して言えることかなと思いますが、BtoBで大きな売り上げを持つ顧客がいるとどうしても「個社対応」が出てきます。あるいは、「個社対応」することがサービスの売りであったりする場合もあるかなと。こういった部分の実装はどうしても複雑になりがちだなと思います。

これに関しては、「ある程度共通化できる部分は残しつつ、DBも使って柔軟に個社対応の部分を変更できるようにしておく」みたいなアプローチをとる現場が多いのですが、これまで見てきた経験からはこれが本当にいいのかは微妙だなという気持ちになっています。
メリットとしては、ある程度共通化する部分を残すことと大規模な実装->デプロイをなるべく防ぐことで工数を減らすということが考えられますが、大体このての実装が入る時ってイレギュラーだったり詳しい人が突貫対応するということが起こりがちで、時間の経過と共に個者対応した実装のキモの部分を知る人が組織にいない（いても捕まらない）みたいな事例が多々ありました。(知識経験が属人化してしまうというのはコレに限った話ではないですが)

なので、最近の僕はこう言った実装が入る場合はできるだけGit管理できる方に寄せていく、冗長になってもいいから個別にUseCaseを切り出す、というアプローチの方がいいのかなと思っています。

----

とまあこんな感じです。どこかの本に書いてあることではなく、敢えて自分の経験を言葉にしてつらつらと書いてみました。

全体通して思うのは「人間」の事情が立ち入るところに複雑さがあり、その要望を解決した結果の実装が複雑になるのかもしれないな、と。なので、そもそも人間の気持ちをできるだけシンプルに解決するにはどうしたらいいのか？(ライトついてますか的な)、というのを最初に頑張るのがいいのかなと思いました（できるとは言ってない)。

来年は人と向き合って問題を解決していけるように頑張りたいなと思います。
rails環境におけるdocker-compose upでexited with code 1エラー解決方法 

初めての記事投稿。

Docker-compose upでrailsアプリをブラウザにて「localhost:3000」のurlで接続したことを確認し1日放置した結果、接続しようとしても更新してもブラウザに表示されなかった。

一旦dockerのコンテナを削除し、再作成し、起動してみた。

```ターミナル
Docker-compose down
Docker-compose build
Docker-compose up -d
```

最後の行で

```ターミナル
rails_web_1 exited with code 1
```

と固まってしまったので、コンテナ状態を見てみると

```ターミナル
docker-compose ps
```

```ターミナル
   Name                  Command               State    Ports
-------------------------------------------------------------
rails_db_1    docker-entrypoint.sh mysqld      Exit 0        
rails_web_1   bundle exec rails s -p 300 ...   Up        
```

とStateがUpにならず困っていたところ、DBごと削除した可能性があるのではと思い改めてDB作成し、Upしてみた。

```ターミナル
docker-compose run web bundle exec rake db:create

docker-compose up
```

するとブラウザにrailsを表示することができました！！
↓Serverが起動している状態

```
web_1  | Use Ctrl-C to stop
```

![Hellorails.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458337/be3b68fe-28d9-702b-621d-cd4af0586551.jpeg)
【初心者】プログラミング歴一ヶ月弱の私が覚えておきたいターミナルのコマンド


スーパー初心者が、１２月頭にアプリエンジニアを目指すことが決まり、
そこからswiftをいじってきました。

プログラミングの勉強を始めるに当たってはじめてコマンド操作をしたので（そこから）

####超基礎だけど、大事なことを書いておきます！

- ターミナルの＄ 以降に入力すべきコードを書いてます。

- 基本的に入力すべきコードを打ったらenterを押します。









## ディレクトリ

#### ディレクトリとは？
`簡単に言うと、フォルダの階層のようなもの
`
 



 - ディレクトリの移動
 
xxxという名のフォルダがあるディレクトリで以下のコマンドをすると、xxxへ移動できる。

```ruby:qiita
cd xxx
```


- 
一つ前のディレクトリに移動

```ruby:qiita
cd ../
```

- 
今のディレクトリ内にあるものをターミナルに表示する

```ruby:qiita
ls
```

最低限、上の３つがあればなんとかできると思います。





## gitのcommit

gitコミットしたい
=書き込みたい（保存したい）ディレクトリに移動した上で

```ruby:git
git add --all
```
の後に

```ruby:git
git commit
```
その後

```ruby:git
i
```

を押すと、`INSERT`と出てくるので、コミット名を書きます。
注）　”i”は打っても表示されず、`INSERT`と出てくるだけ

コミット名を書き終わったら、キーボードの”esc”を押します。

```ruby:git
:wq
```

これでgitcommit完了！

---

また、勉強していくうちに追記していきます！
JetsonにJetPackに含まれるライブラリを個別にインストールする

##JetPackとは
JetPackはJetson向けにTensorRT、cuDNN、CUDAなどのAI関連のSDK、ライブラリをパッケージしたものです。
インストール方法はNVIDAが提供しているSDK Managerを使う方法と、イメージファイルをSDカードに書き込む方法の2種類があります。
この記事ではSDK Managerを使って必要なデータをダウンロードします。

##CUDA、cuDNNを個別にインストールする方法
SDK ManagerとTerminalを使ってCUDAとcuDNNの個別インストールする方法について説明します。
手順としては、インストールしたいライブラリの含まれるJetPacKをダウンロードし、個別にJetsonにインストールします。

###対応するSDK、ライブラリバージョンの見つけ方
下記urlからJetPackに含まれる各SDK、ライブラリを確認します。
https://developer.nvidia.com/embedded/jetpack-archive
今回は例としてCUDA10.0、cuDNN7.5をインストールしたいと思います。
対応するJetPackは4.2になります。

###SDK Manegerを使った必要なデータの取得方法
1. SDK Managerを起動し、STEP 01 の 『TARGET OPERATION SYSTEM』からデータをダウンロードするJetPackを選択します。
![Screenshot from 2020-12-25 18-49-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675981/6d22dd53-dbfc-80e8-e922-d1ace346f4ee.png)


2. STEP 02の チェックボックス『Download now.Install later.』にチェックをつけ、Download folderにデータをダウンロードするフォルダを指定します。
![Screenshot from 2020-12-25 20-34-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675981/580dfd50-c72a-2e5b-3fc3-40147ccac08a.png)


###インストール手順
ライブラリ、SDKごとのインストール手順を説明します。
前手順で取得したデータを外付けHDDなどに移し、ライブラリをインストールしたいJetsonを起動します。
Jetsonのterminalを起動し、カレントフォルダをインストールしたいデータを格納しているフォルダにし、下記のコマンドを実行します。


CUDAのインストール

```bash
$ sudo dpkg -i cuda-repo-l4t-10-0-local-10.0.326_1.0-1_arm64.deb
$ sudo apt update
$ sudo apt-key add /var/cuda-repo-10-0-local-10.0.326/7fa2af80.pub
$ sudo apt update
$ sudo apt install cuda-toolkit-10.0

$ echo "# Add 32-bit CUDA library & binary paths:" >> ~/.bashrc
$ echo "export PATH=/usr/local/cuda-10.0/bin:$PATH" >> ~/.bashrc
$ echo "export LD_LIBRARY_PATH=/usr/local/cuda10.0/lib64:$LD_LIBRARY_PATH" >> ~/.bashrc
$ source ~/.bashrc
```

visionworksのインストール

```bash
$ sudo add-apt-repository universe;
$ sudo dpkg -i libvisionworks-repo_1.6.0.500n_arm64.deb
$ sudo apt update
$ sudo apt install libvisionworks libvisionworks-dev libvisionworks-samples
```

cuDNNのインストール

```bash
$ sudo dpkg -i libcudnn7_7.5.0.56-1+cuda10.0_arm64.deb
$ sudo dpkg -i libcudnn7-dev_7.5.0.56-1+cuda10.0_arm64.deb $ sudo dpkg -i libcudnn7-doc_7.5.0.56-1+cuda10.0_arm64.deb
```

##最後に
CUDAなどがインストールされていない環境や、JetPackにてインストールされるバージョンから変更したい場合に利用することがあると思います。
CUDAなどのライブラリのバージョンからそのライブラリが含まれるJetPackのバージョンを簡単に判別できる方法があれば便利かなと思いました。

###参考URL
https://developer.ridgerun.com/wiki/index.php?title=Installing_CUDA-toolkit_and_VisionWorks_Jetson_TX2/Xavier/Nano
RaspberryPi zeroで高速にPDFを表示する(mac出力のPDFにも対応)

この記事は[IoTLTアドベントカレンダー19日目](https://qiita.com/advent-calendar/2020/iotlt)です！(本当に大遅刻です．ごめんなさい...)

さて，ご時世もあってオフラインでプレゼンする機会は減りましたが，思い返せばオフラインでプレゼンっていうのは問題が多かったですよね．
プロジェクターとパソコンの相性，コネクタ問題，スライドサイズ....めんどくさい！
![スクリーンショット 2020-12-25 20.18.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259617/666f1a27-ea7b-d868-b622-a6ecd3bc221e.png)

そんなめんどくささを解決するために，プロジェクターの入力にラズパイを繋ぎっぱなしにしておく方法を思いつきました．
繋ぎっぱなしのラズパイにスライドをアップロード・遠隔操作することでプロジェクターとパソコンの相性問題を解決します！
![スクリーンショット 2020-12-25 20.18.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259617/efef5d57-4b41-f354-84b8-1bb00456cf6f.png)

# RaspberryPi(CUI)でPDFを映したい
まずは第一段階，RaspberryPiからプレゼン資料(pdf)をHDMI出力したいです．
コストを考えてRaspberryPiのモデルはZeroを選びました．
「pdfを出力するだけにそんなスペックは要らないだろう！」と思ったわけです．
ですが，やはりRaspberryPi zeroはスペック的に貧弱．少しでも処理に余裕が持たせられるようにOSはRaspbian Lite(CUI)を選択しました．
と，なると．X WindowなどGUIシステムがない環境でPDFを表示する必要が出てきます．
実現は簡単で，表示したいデータをframebufferというメモリ領域に直接書き込めばHDMIにそのまま出力されます．
んで，世の中にはPDFをframebufferを使って表示するアプリがいくつかあります．便利ですね！
では何を使ったらいいんでしょうか...? いろいろ試してみました．

# うまくいかなかったやつ
・fbi
・fbpdf
・fbgs
などなど...他にも試した気がするがどれもうまくいかなかった．
画質が悪かったり，raspberryPi zeroでは動作が重いものが多い．
**あと，とにかくmacが出力したpdfに対応しているものが無い！**
私はmacのkeynoteでプレゼン資料を作るので，これは致命的．(フォントの関係やpdfの仕様の違いなど問題の闇は深そう)

# うまくいったやつ(jfbview)
サクサク動作でmac PDFも問題なく映せる，そんな夢のようなPDF Viewrが**jfbview**です．
https://github.com/jichu4n/jfbview

## インストールする
環境は以下の通り．
・Raspberry Pi Zero W Rev 1.1
・Raspbian GNU/Linux 10 (buster)

まずは公式リポジトリのリリースからdebファイルをダウンロードする．
https://github.com/jichu4n/jfbview/releases
いろんな環境向けにパッケージが用意されている．
今回私の環境はRaspberryPiでOSのバージョンはbusterなので， `jfbview_0.6.0.buster_rpi.deb`をダウンロードする．自分の環境に合わせて適宜選んで欲しい．

```
$ wget https://github.com/jichu4n/jfbview/releases/download/0.6.0/jfbview_0.6.0.buster_rpi.deb
```

ダウンロードしたパッケージをインストールする

```
$ sudo apt install ./jfbview_0.6.0.buster_rpi.deb 
```
これでインストール完了！簡単！

## 使ってみる
使い方は簡単，基本は映したいファイルを渡すだけ．
オプションも充実で
・ `--zoom_to_fit`  ・・・ 表示サイズを画面にフィットさせる
・ `--cache_size=N` ・・・ ページを先読み(キャッシュ)する数，多ければ多いほど高速なめくりに対応できるがRAMをいっぱい使う
など，他にも色々ある．

```
$ jfbview --zoom_to_fit iotlt.pdf
```

かなり綺麗にpdfが表示される．動きもサクサク！
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259617/6f8c07a3-b024-7e2d-b7b3-4e5c815a8141.gif)


矢印キーの上下でページ送り． `q`キーで終了する．
その他基本操作はvimに似たような感じ，詳しくは以下manを参照．
https://htmlpreview.github.io/?https://github.com/jichu4n/jfbview/blob/master/doc/jfbview.1.html

# まとめ
無事，サクサクにpdfが表示されました！(しかもmac出力の)
実際にプロジェクターにつないでテストもしてみましたが，問題なく動いています．
あとはネットワークを使ってファイルをアップロードしたり，スライドを遠隔操作したりする部分を作りたいですね！（そうしないとIoTじゃないので）
では，皆さん良い年末を〜
Node-REDの自作ノードを更新するときの自分用メモ


公式手順などがありますが、自分用のメモです。
毎回ノード作る時に調べてしまうのでそろそろまとめます。

自分に対して指示出してます。

## Node-REDのインストール

大体毎回入って無いです。

ノードを作ろうとか更新しようのサイクルが頻繁じゃないので、気がつくといつもいない......

この辺が特に自分用メモっぽい。

```bash
$ npm i -g --unsafe-perm node-red
```

起動

```bash
$ node-red
```


## `~/.node-red`に移動

`~/.node-red`にノードがインストールされているらしい

```bash
$ cd ~/.node-red
```

```bash
$ .node-red ls
lib          node_modules package.json settings.js
```

## git cloneするなどする

たぶん手元にプログラムが置かれてないのと思うので、[GitHubのリポジトリ](https://github.com/n0bisuke/node-red-contrib-line-messaging-api)からCloneしてきましょう。


そして修正します。


## ローカルのNode-REDノードのプロジェクトをインストール

`~/.node-red`の中で`npm i <localプロジェクトのパス>`という指定でローカルパッケージのインストールをします。

```bash
$ npm i ~/パス/node-red-contrib-line-messaging-api
```

再起動して確認

```bash
$ node-red
```

一緒にしちゃった方が楽かも

```bash
$ npm i ~/パス/node-red-contrib-line-messaging-api && node-red
```

## npm publish

例えば、`node-red-contrib-line-messaging-api`を作業しているフォルダで

package.jsonの`"version"`を上げてから

```bash
$ npm publish
```

これでnpm上は更新されます。

## パッケージの更新

https://flows.nodered.org/add/node の一番下にモジュール名を入れて`add node`で更新します。

> ![スクリーンショット 2020-12-17 4.55.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/dca282d1-5ead-4c32-2fa0-cd61a29dc672.png "スクリーンショット 2020-12-17 4.55.13.png")

これでやっと更新される

> 昔は勝手に更新されてた模様ですが、最近はこのやり方になったみたいです。

## その他

GitHub側の更新も忘れずに。
【Git】余計なコミットを記録しない。コミット後に小修正を適用した場合の対処法（git commit --amend --no-edit）

コミットした直後に、不要なスペースやカンマやconsoleなどデバッグ用コードの消し忘れに気付き消してコミットすると、履歴が汚くなる。

##事例
例えば、`pタグ`を追加しコミットした後で、不要なスペースがあるのに気付き再度コミットする場合。

```html:コミット１
<p>added </p>
```

↓スペース削除

```html:コミット２
<p>added</p>
```

<br>
**▼普通にコミットした場合**

```:コミット履歴
* cd50968 - (HEAD -> master) remove space
* f9ac530 - add p
```

add pの後に、余計なコミットremove spaceが入る。


##対処法
追加処理(git add後)のコミット時にオプションで`--amend`を使う。

・`git commit --amend --no-edit`

```:
git add .
git commit --amend --no-edit
```

ファイルの内容は上書きされるが、コミット履歴を残さない（前回のコミットメッセージのまま）

```:コミット履歴
* ed04c55 - (HEAD -> master) remove space
* f9ac530 - add p
```

※注：コミット番号は変わる。



###コミットメッセージを変更する場合
ファイルの追加等なしで、単にファイル名を変更したい場合は`--amend -m`オプションを使う

`git commit --amend -m "変更後のメッセージ"`

```:元のコミット
* ed04c55 - (HEAD -> master) remove space
```

↓　git commit --amend -m "変更後のメッセージ"

```:メッセージの変更
* a378eb4 - (HEAD -> master) 変更後のメッセージ
```

こちらも、コミット番号が変わる。


<br>
##注意点
githubを使い複数人で開発している場合の注意点はmasterにmerge後のコミットは修正してはいけない。

自分のローカルのみなら、強制プッシュ`push -f`で修正できるが、もし、masterにマージしてしまったら、自分だけでなく使っている人全員に`push -f`などの対処をしてもらわなければならない。


###プッシュ後の自分のブランチへの強制プッシュ法

```:
git push origin ブランチ名 -f
```

masterへの強制プッシュは絶対禁止！！！！(master -fの組み合わせはあってはならない）
クリスマスなので、Node-REDのGmailノードを公開してみました #nodered #noderedjp


タイトル通りですが、[こちら](https://flows.nodered.org/node/node-red-contrib-gmail-fetch)になります。 Gmailのノードを公開してみました。

クリスマスプレゼント的な感じですかね！（謎）

> ![スクリーンショット 2020-12-25 20.26.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/e440fc19-8d66-81e1-f883-ccfc315b90f3.png "スクリーンショット 2020-12-25 20.26.57.png")

> ![](https://camo.githubusercontent.com/823d146ce64d1af95a42feec567ecd85b3d99c6541555dc68bdc157165b83941/68747470733a2f2f692e6779617a6f2e636f6d2f30666264333239303434353266313838383564323934386231653139323937662e706e67)

## どんなノードか

Gmailからメールを検索して1件取得するノードを入れています。

後から追加した機能ですが、Gmailでメール送信もできます。

送信も作ってしまったので、gmail-fetchという名前にしてしまったけどnode-red-contrib-gmailに変更するかもしれません。

## Node-REDにGmail的なノードが無かった

無かったから作ったというやつです。

元々、メールの情報を取得して、LINEに転送するということをやりたかったのですが、IFTTTやIntegromatを介するのもちょっとなぁと思い、Node-REDだけでやりたいと思って作ってみました。

## 使う前に

公式チュートリアルを元に`credentials`と`token`の情報を取得する必要があります。ここだけ要注意ですね。

> https://developers.google.com/gmail/api/quickstart/nodejs


トークンは以下のパーミッションが必要です。自分用のメモとしても残しておきます。

* メール送信時のパーミッション

```
https://mail.google.com/
https://www.googleapis.com/auth/gmail.modify
https://www.googleapis.com/auth/gmail.compose
https://www.googleapis.com/auth/gmail.send
https://www.googleapis.com/auth/gmail.addons.current.action.compose
```

* メールを検索して本文取得する時のパーミッション

```
https://mail.google.com/
https://www.googleapis.com/auth/gmail.modify
https://www.googleapis.com/auth/gmail.readonly
https://www.googleapis.com/auth/gmail.addons.current.message.metadata
https://www.googleapis.com/auth/gmail.addons.current.message.readonly
https://www.googleapis.com/auth/gmail.addons.current.message.action
```

> ![](https://camo.githubusercontent.com/622b513eb8b49e175c9bcb82f2a348555fb097c364150cf3ee3b9c9084a8ffab/68747470733a2f2f692e6779617a6f2e636f6d2f39303530376163626435313963336562383130346362633066643461306164312e706e67)

## 利用例

Gmailのメッセージを取得してLINEに流したり、Twitterに流したり出来ます。

間に（たぶん）Changeノードとかをかませてフィルタリングしたメッセージを別のSNSなどに流すこともできると思います。

![スクリーンショット 2020-12-25 20.35.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/19aaec6c-fa8f-bc64-faa8-74090b2f0eab.png "スクリーンショット 2020-12-25 20.35.59.png")

## クリスマスですね〜

Node-REDでGmail使いたかった人へのクリスマスプレゼント的な物だと思ってもらえると幸いです。

こじつけですね笑

良いお年を！
WPF(+Prism)でのウインドウ表示

Shell(MainWindow)内のRegionにコンテンツを表示する以外のウインドウ表示の方法
(Prism はv6.3) 

## Windowインスタンスを作って表示する

WindowsForms以来のやり方

```csharp
var window = new FooWindow();
window.Show();
```

## prism:PopupWindowAction

Prism でpopup。スタイルとかボタンとかPrism のデフォルトになる。

コンテンツ部分に PopupView.xaml を使う場合以下

```xml:xaml
        <i:Interaction.Triggers>
            <prism:InteractionRequestTrigger SourceObject="{Binding ShowPopupCommand, Mode=OneWay}">
                <prism:PopupWindowAction>
                </prism:PopupWindowAction>
            </prism:InteractionRequestTrigger>
        </i:Interaction.Triggers>
```

```csharp:viewmodel
public InteractionRequest<Notification> ShowPopupCommand { get; set; } = new InteractionRequest<Notification>();

...

 this.ShowPopupCommand.Raise(new PopupNotification{
                   Title = "test",
                    Content = new PopupView()  
                });
```
Rubyのif,case

\![Mac OS X-10.15.7](<https://img.shields.io/badge/MacOSX-10.15.7-brightgreen>) \![ruby-2.7.1p83](<https://img.shields.io/badge/ruby-2.7.1p83-brightgreen>) 


# if-elsif-else-end

if文の書き方

```el
if 条件式 then
  処理
elsif 条件式 then
  処理 
else
  処理 
end
```


## 閏年判定(単数)

まず4の倍数なのかを判定する

```el
p year = ARGV[0].to_i

if year%4==0 then
  p true
else
  p false
end
```

yearを入力として、それは4の倍数ならtrue、そうじゃなければfalse 　実行すると

```el
$ ruby check_leap.rb 2004
2004
true
```

では、1999でやってみる

```el
$ ruby check_leap.rb 1999
1999
false
```

となる
閏年の条件は４年に一度だけじゃなく
1)100で割り切れる年はうるう年でなく
2)400で割り切れる年はうるう年  
その二点の条件を含めて判定しましょう

```el
p year = ARGV[0].to_i
if year%400 == 0
  p true
elsif year%100 == 0
  p false
elsif year%4 == 0
  p true
else
  p false
end
```

これを実行すると

```el
$ ruby check_leap.rb 1900
1900
false
$ ruby check_leap.rb 2000
2000
true
```

となった


## 複数

複数の値を一気にテストしたいときには配列にしてloop回すだけ

```el
[2004,1999,1900,2000].each do |year|
  p year
  if year%400 == 0
    p true
  elsif year%100 == 0
    p false
  elsif year % 4 == 0
    p true
  else
    p false
  end
end
```

実行結果

```el
$ ruby check_leap_year.rb
2004
true
1999
false
1900
false
2000
true
```

長くなってきたのでmethodにしておく

```el
def leap?(year)
  if year % 400 ==0
    p true
  elsif year % 100 ==0
    p false
  elsif year % 4 == 0
    p true
  else
    p false
  end
end

[2004,1999,1900,2000].each do |year|
  p year
  leap?(year)
end
```


# case


## case文の書き方

```el
case A
when 1 then  
  処理
when 2 then  
  処理
else       
  処理
end
```

caseを使って先ほどのコードを書きなおして

```el
def leap?(year)
  case
  when year % 400 ==0 ; true
  when year % 100 ==0 ; false
  when year % 4 ==0 ;   true
  else ;                false
  end
end

[2000, 1900, 2004, 1999].each do |year|
  p year
  p leap?(year)
end
```

プログラムは短くなった



------
 - **source** ~/grad_members_20f/members/wjswnsrud12/memo7.org
GmailのAPIでメール取得が出来ているけどsizeが0になってしまう場合の対処


GmailのAPIを触ってみてますが、メールによって取得できるパターン取得できないパターンがありました。

## まずはどんなコードか

"[Google公式ライブラリを利用してNode.jsからGmailの送受信をしてみよう](https://dotstud.io/blog/gmail-api-from-nodejs/)"などを参考にコードを書いてメール取得をしてみています。

`users.messages.list()`でメールを検索し、`users.messages.get()`でメール本文を取得します。

```js
//省略

  const gmail = google.gmail({version: 'v1', auth});
  
  
  //1件検索
  const resList = await gmail.users.messages.list({userId: 'me', q: 'from:hoge@hoge.com'});
  const lastMessage = resList.data.messages[0];
  
  
  //検索したメールIDで中身を取得
  const res = await gmail.users.messages.get({
    userId: 'me',
    id: lastMessage.id,
    format: 'FULL'
  });

  const buf = new Buffer.from(res.data.payload.body.data, 'base64');
  const str = buf.toString();
  console.log(str,str.length);

//省略
```

通常だと、`res.data.payload.body.data`にメール本文が入ってきて、メール本文がコンソールに表示されます。

## メールが空の場合がありました。

Gmailなどのメーラー的にはちゃんと表示されてるのですが、このコードの`console.log`で表示がされないケースがありました。

こんな感じのエラーです。

```bash
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined
```

`new Buffer.from(res.data.payload.body.data, 'base64');`と指定している第１引数に文字列を入れろと怒られてます。

`console.log(resMes.data.payload);`で調べてみると`{ size: 0 }`となっていました。

```bash
body: { size: 0 },
  parts: [
    {
      partId: '0',
      mimeType: 'text/plain',
      filename: '',
      headers: [Array],
      body: [Object]
    },
    {
      partId: '1',
      mimeType: 'text/html',
      filename: '',
      headers: [Array],
      body: [Object]
    }
  ]
```

さらにbodyではなく、partsの方にBodyが入ってそうです。
`console.log(resMes.data.payload.parts[0]);`などでみてみるとやはり入ってます。

```bash
{
  partId: '0',
  mimeType: 'text/plain',
  filename: '',
  headers: [
    { name: 'Content-Type', value: 'text/plain; charset=utf-8' },
    { name: 'Content-Transfer-Encoding', value: 'base64' }
  ],
  body: {
    size: 11661,
    data: '44GT44KT44Gr44Gh44Gv44CB44G144KL44GV44Go44OB44On44Kk44K544...

```

## payload.bodyではなくpayload.partsに本文がいるケースがある

ということで、bodyではなくparts側に本文のbase64文字列が格納されている場合があります。

何個か試してみましたが、HTMLメールなどはそうなってるのかもしれません。

GoogleのAPI側でその辺吸収してくれても良いのになぁ...

ということで、bodyが空の場合はpartsからbase64文字列をchunkとして取得して、partsの数だけ結合するようにしました。

```js

    let mailData = '';
    
    //bodyが場合
    if(resMes.data.payload.body.size !== 0){
        mailData = resMes.data.payload.body.data;
    }
    
    //bodyが空の場合はpartsから取得
    else{
        const parts = resMes.data.payload.parts;
        for (let i = 0, len=parts.length; i < len; i++) {
            if(parts[i].body.size === 0) continue;
            const chunk = parts[i].body.data;
            mailData += chunk;
        }
    }
    const buf = new Buffer.from(mailData, 'base64');
    const str = buf.toString();
```

これで今のところbodyが空の場合のメール本文も取得することができています。

## まとめ

メールの仕様なんですかね？

APIの返却値が`payload.parts`の奥にある場合と、`payload.data`に存在する場合があるという話でした。

Gmail API触ってる記事はまだまだ少ない気がするので参考になれば幸いです。
【Flutter】Error: Not found: 'dart:ui' import 'dart:ui' as ui show Paint, Path, Canvas;の解消法

## 概要
Flutterプロジェクトを実行するときに
`Error: Not found: 'dart:ui' import 'dart:ui' as ui show Paint, Path, Canvas;`が出た時の解消法です。

## 解決方法
`Run` -> `Edit Configurations`でFlutterプロジェクトとして実行するように設定する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230436/920d4fb6-a617-2e0d-389b-ec2e65fe4acb.png)

※これ以外が原因の場合もあると思います
svls: SystemVerilog Language Server

# はじめに

この記事は [SystemVerilog Advent Calendar 2020](https://qiita.com/advent-calendar/2020/systemverilog) の25日目です。
7日目の記事と若干被ってますが、svlsというSystemVerilog向けのLanguage Serverについて紹介します。

Language ServerとはMicrosoftが仕様策定したLanguage Server Protocol(LSP)というプロトコルをしゃべるサーバです。
このサーバは接続してくるエディタに対して、タグジャンプや補完、リント、フォーマットなど様々な機能を提供します。
従来こういった機能はエディタ毎に実装されていましたが、共通のプロトコルができたことで、1つLanguage Serverを書けば対応するあらゆるエディタがこの機能を利用できるようになりました。

最近のモダンなプログラミング言語ではこのLanguage Serverが標準で用意されることも多いですが、残念ながらSystemVerilogにはそのような動きはありません。（あまり真面目に調べたことはないですが、商用ツールでも聞いたことないです）
ないなら作ろうということで、[7日目に紹介したSystemVerilogパーサライブラリ](https://qiita.com/dalance/items/2c318ef6559eed8f2dc9)を使ってLanguage Serverを実装したのがこのsvlsです。実装言語はRustです。

https://github.com/dalance/svls

# svls

どんなことができるかというのは以下のスクリーンショットを見てください。
赤背景でリントエラーが表示され、それを修正するとその結果がリアルタイムに反映されます。
（表示のされ方はエディタやLSPプラグインによって異なります）

![test.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84296/9fe1726a-e643-807f-dbe3-cfe9e4b268c3.gif)

また、シンタックスエラーもリアルタイムに表示されます。

こちらはVSCodeの例で、末尾の`;`が抜けているケースです。
（以下はgifにするのが面倒だったので静止画です…）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84296/3d24a805-8e95-3995-a628-47bacafd7bfa.png)

マウスホバーで詳細（というほどのものでもないですが）が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84296/11a4c2f6-70e4-4ace-3db2-21f52befa3a9.png)

当初リントエラー表示を目的にしていましたが、このシンタックスエラー表示も思いのほか便利です。svlsが使っているパーサは言語規格に対して非常に厳格に作ってあります。一方、商用含めてSystemVerilogの処理系（シミュレータや合成ツールなど）は文法が適当なことが多く、ツールによって規格違反の記述が通ったり通らなかったりします。
そのため、svlsを使って確実に規格の範囲内で書くようにすると、ツールの差異で問題になりにくくなると思います。（また規格通りなのに通らない商用ツールがあれば、ベンダーに文句を言うこともできます）

# 使い方

基本的な流れは

* svlsのバイナリをダウンロードしてパスの通ったところに置く
* エディタのLanguage Serverとして登録する

という感じです。詳細は以下を見てください。

https://github.com/dalance/svls#installation

今のところ以下のエディタで動作するようです。

* VSCode
* Vim
* Neovim
* Emacs

他にもLanguage Serverに対応したエディタなら動くはずです。
SystemVerilogをよく書く方にはぜひ使っていただければと思います。
New Relic Syntheticsでいろいろなユーザーエージェントを指定する

New Relicでソリューションを提供している佐々木です。
New Relic Advent Calendar 2020の最終日の記事をお届けします。

## New Relic Syntheticsとは
外形監視をするための機能です。詳しくは[こちら](https://blog.newrelic.co.jp/new-relic-basics/newrelic-synthetics-overview/ "New Relic Syntheticsについて")の公式ブログで解説しているのですが、一言でいうと、めちゃめちゃ簡単に、定期的にサイトのエラーやパフォーマンス状態について監視してくれる機能です。
どれくらい簡単かというと、例えばある特定のページを監視したい場合は、そのURLを入力するだけです。
![synthetics1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538642/16820919-1d6e-e601-19c4-fef5640e30ed.png)

そうすると、定期的に対象のページに対するアクセス結果がNew Relic上に表示されます。
![synthetics2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538642/2663679d-9086-8120-1019-03a728bfdf25.png)

## New Relicが用意しているモニターのユーザーエージェント

Linux上のChromeです。
![synthetics3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538642/738ab7ea-c945-7810-badd-f26a7071fa03.png)

## 別のユーザーエージェントを指定してみる

ユーザーエージェントによって表示させるコンテンツを切り替えているような作りのサイトの場合、ユーザーエージェントごとのパフォーマンスやエラーを確認したいかと思います。
その場合、```Scripted Browser```というモニタータイプを使うことで、ユーザーエージェントを切り替えることができます。

以下のようなScriptを書いてみましょう。

```
var assert = require('assert');

//iphoneをシミュレート
$browser.addHeader('User-Agent', 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1');

//https://newrelic.com/jp にアクセス
$browser.get('https://newrelic.com/jp');
```

すると、Request Headerのuser-agentの情報も書き換わっていることがわかります。
![synthetics4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538642/9153ce29-1a11-c51c-0317-1f22d428f217.png)

他のユーザーエージェントを指定したい場合も、```$browser.addHeader```内の文字列を変更するだけです。

簡単にできますのでぜひ試してみてください。
Reactで開発してみた　〜色々気づいたことプチまとめ〜

## はじめに
2ヶ月ほどReactを使って開発を行ったのですが
その中でも勉強になったことや、こんなミス一生したくないというものをアウトプットしていきたいと思います。

### props 受け渡し
親コンポーネントから子コンポーネントへ
値を受け渡す際にpropsで渡しているのですが

その際に関数内でpropsで受け取り、
props.~~~で使用していたのですが

```react:hoge.jsx
 // 例
export default hoge = () => {
  return (
    <hogeChildren data="hogehoge" dataLayout="hogelayout"/>
  )
}

const hogeChildren = (props) => (
  <>
    <div>{props.data}</div>  // =>hogehoge
    <div>{props.dataLayout}</div> // =>hogelayout
  </>
)
```

受け取る際に ({recommed})とすると
propsでやらなくても済む

```react:hoge.jsx
 // 例
export default hoge = () => {
  return (
    <hogeChildren data="hogehoge" dataLayout="hogelayout"/>
  )
}

const hogeChildren = ({ data, dataLayout }) => (
  <>
    <div>{data}</div>  // =>hogehoge
    <div>{dataLayout}</div> // =>hogelayout
  </>
)
```

props書かなくていいのは個人的に楽

### Custom Hooks
#### Custom Hooksとは

> 名前が ”use” で始まり、ほかのフックを呼び出せる JavaScript の関数のことです。（参照: [React document 独自フックの作成](https://ja.reactjs.org/docs/hooks-custom.html)）

今回は初回以外かつuseEffectで第二引数値が変更した時のみ処理を行う際に使用したのでそれを記します。

```react:hogeUserEffect.jsx
const fisrtFlgRef = useRef(false);

  useEffect(() => {
    if (fisrtFlgRef.current) {
      document.title = `${count} 回クリックしたよー`;
    } else {
      fisrtFlgRef.current = true;
    }
  }, dependencyList);

```

フラグを用意し、初回は

こちらだと毎回useRefを使って生成しないといけないといけないので

```react:hogeUserEffectCustom.jsx
const useEffectCustom = (func, dependencyList) => {
  const fisrtFlgRef = useRef(false);

  useEffect(() => {
    if (fisrtFlgRef.current) {
      func();
    } else {
      fisrtFlgRef.current = true;
    }
  }, dependencyList);
}

export default useEffectCustom;
```

```react:hogeUserCustom.jsx
import useEffectCustom from hogeUserEffectCustom.jsx

  useEffectCustom(() => {
    document.title = `${count} 回クリックしたよー`;
  }, [count])

```

このようにrefから

もっと詳しくuseEffectでの初回レンダリングを走らせずの処理を知りたい方はこちらの記事を
[useEffect 初回レンダリングで走るな!!!](https://qiita.com/irico/items/4b2ff1c25b49ea6a4abf) 
お世話になりました:bow_tone2:

customhooksについてもっと知りたい方はドキュメントへ
[独自フックの作成](https://ja.reactjs.org/docs/hooks-custom.html)


### UseEffect無限ループ
これは恥ずかしいミスですが共感できる方がいらっしゃるととても嬉しいです。

useEffectでの第二引数の指定を第一引数で変更する内容にすると無限ループにはまりました。


```react:hoge.jsx

  useEffect(() => {
    count++
    console.log(`${count}回clickされたよー`)
  }, [count])

```
この例はおおげさですがこのような記述にしてしまい
すごい量のconsolelogがでてきました。


## まとめ
実際に実装してみないと気づかないこととかって結構ありますよね。。


## 参照記事
[Reactドキュメント 独自フック作成](https://ja.reactjs.org/docs/hooks-custom.html)
[useEffect 初回レンダリングで走るな!!!](https://qiita.com/irico/items/4b2ff1c25b49ea6a4abf)
プロダクト開発を支える名言

# はじめに
この記事は [弁護士ドットコム Advent Calendar 2020](https://qiita.com/advent-calendar/2020/bengo4com) 25日目の記事です。
昨日の記事は [@poemn](https://qiita.com/poemn) さんの 「[RESTとSEOの観点でURLについて考えてみた](https://qiita.com/poemn/items/c1526a58c32ce52edfd8)」 でした。

プログラミングについて、多くの名言があります。曰く、「計算機科学のあらゆる問題は、新たな抽象化レイヤにより解決できる」「計算機科学における難問は2つしかない。キャッシュ無効化と名前付けだ」などなど。

ここでは少し趣向を変えて、プロダクト開発における名言 (と個人的に思っているもの) を紹介したいと思います。

# Done is better than perfect
Facebookの[上場申請資料](https://www.sec.gov/Archives/edgar/data/1326801/000119312512034517/d287954ds1.htm)で、オフィスの壁に書かれてことで有名になったものです。弁護士ドットコムでも「エンジニア・デザイナー行動指針」の1つとして、「いいものを最短距離で」と、似たような趣旨の指針を掲げてます。

これは「技術的負債など気にせず汚いコードを出していこう」という話ではありません。
誰だって、ユーザーに価値を提供する、品質の高いコードが実現できればいいことに異論はないでしょう。でも現実は往々にしてそうはならず、特にユーザへの提供価値は不確実性がつきものです。例えば、提供価値を体感できる最小限の雑なコードと、提供価値を100%カバーしてアーキテクチャとしても作り込まれたコードの、どちらを取るかというトレードオフが発生しえます。

行動指針というものは、トレードオフの解消に役に立つものでなければなりません。そしてここでは前者を取る、というのが冒頭の指針です。100%作り込むには時間がかかり、そしてリリースした後に想定と違って価値を提供できない可能性もあります。失敗するのであれば早く失敗して、フィードバックをもとに軌道修正していく、不確実な状況ではそうしたトライアンドエラーで徐々にプロダクトを成長させていく方針が適しています。
(もちろんいつまでも雑なコードのままではなく、価値が明確になった後ではリファクタリング等の時間を確保しましょう)

# 君は今、岐路に立ち、道を選ぼうとしている。でも選択することはできない。ただ受け入れるしかない。選択は、とっくの昔に為されていたのだ。

コーマック・マッカーシーが脚本を書いたことで (一部で) 有名な「悪の法則」という映画のセリフです。ある人物に救いを求めた主人公に対する、映画同様に救いのないセリフです。
> You are now at the crossing. And you want to choose, but there is no choosing there. There's only accepting. The choosing was done a long time ago.

プロダクト開発をするための組織づくりには時間がかかります。急遽「爆速で開発するぞ」となって、例えば大枚叩いてフリーランスのエンジニアを大勢集めても、開発は加速しません。むしろオンボーディングやチームビルディングのため、しばらくは減速するでしょう。

いつも僕らは「今」が選択の時だと思いがちです。でも、今は過去の選択の上に成り立っています。プロダクト開発は将棋のようなもので、先を見越して手を打っていかねばなりません。王手をされてから慌ててももう遅い。そして組織づくりにおいて銀の弾丸はなく、普段から大量の鉛の弾丸で戦っていく必要があります。
(インピーダンスミスマッチの話)

# やればよかったと思うことには一切時間を使わず、すべての時間をこれからきみがするかもしれないことに集中しろ。結局は、誰も気にしないんだから。
ベン・ホロウィッツが書いたベストセラー「HARD THINGS」の一節です。

プロダクト開発は、日々意思決定の連続です。あるいは、妥協の連続と言ってもよいかもしれません。
「売上目標を達成するには目玉となるXXの機能が必要だけど、技術的負債を解消しないと開発速度がいつまでたってもあがらない」といった状況で、プロダクトの仕様・UX/UI・技術的なアーキテクチャについて、綱渡りしながら走っていかなければなりません。

そして意思決定には失敗がつきものです (間違った意思決定をしてないのであれば、それは挑戦してないのと一緒です)。そうした時に、あの時こうしていれば、ああしていればという後悔がよぎるかもしれません。失敗を言い繕って自分を慰めたくなるかもしれません。でも、辛くてもただ前進していくしかないのです。
不確実な状況での意思決定である以上、一定の失敗は起こりえます。失敗を折り込み、小さく早く失敗して試行回数を増やし、トータルで勝てるような仕組みが必要でしょう。

# おわりに
ということで3つの名言を紹介しました。
これらに共通するのは根底に「時間」が関わることです。不確実な状況と限られた時間の中で、いかにプロダクトの価値を最大化できるかが、プロダクト開発におけるエンジニアリングの醍醐味なのではと思います。

今年も1年間おつかれさまでした。みなさんよいお年を。
macOS へ VNC でリモート接続するメモ(RDP で接続は難しそう..)

## 背景

* macOS(e.g. mac mini) **へ**, Linux や Windows からリモート接続したい.
  * XCode を動かして iOS アプリ開発したいとか(特にカメラを使い実機が必須のもので, M1 macOS で動かすことができないものとか)
  * 手元が Linux or Windows note PC で, Mac でしか動かないアプリのために mac mini へ接続したいとか.

## VNC

共有設定からリモートアクセスを有効にするだけです.
特に extra な設定はありません.

ただ, VNC なので画面転送がとても遅いです.

mac 側で画面サイズを小さくするくらいしか手がありません.
(M1 mac mini だと 10 GbE 対応がなくなったので, ネットワーク速度を上げるというのができません. Thunderbolt3 でなにかうまくやる手はあるかもですが...)

## RDP

ネットを探すとほぼ mac から Windows へ RDP 接続しか見つからずつらい :cry:

https://support.apple.com/en-za/guide/remote-desktop/welcome/mac

RDP サーバっぽいのがありますが, 1 万円するのとレビューのレートがよくありません.

FreeRDP で server 動かせるかもですが, M1(arm)だと FreeRDP が依存する ffmpeg が依存する libvpx が arm 対応しておらず macports で入りませんでした.

## xrdp

xRDP on MacOS Mojave
https://ryancreecy.com/2019/10/29/xrdp-on-mac.html

ソースからビルドすれば頑張ればいけるかも..?
Pardot のスコアリングとグレーディング (Pardot Lightning アプリケーション) ⇒ スコアリングの使用 (Pardot Lightning アプリケーション)

１．Pardot のスコアはどのようなものですか?
２．スコアリングカテゴリとプロスペクトのスコアにはどのような関連がありますか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/0a0565cf-8925-8350-c9e9-071041b8fb30.png)