OmniAICreator/Qiita-1.07M huggingface dataset:
AttributedTextを簡単に書けるExtension


`UILabel`とか`UITextView`の`attributedText`はそのまま書くと結構めんどくさいので楽に書けるextensionを作りました。

もっとこうしたら良いんじゃないのとかダメじゃんて部分あったらコメントで教えてもらえるとありがたいです。

最初に、どう書けるかを書いときます

#使い方
```swift
let atrStr1 = "aaa".attribute()
    .font(.boldSystemFont(ofSize: 12))
    .textColor(.blue)
    .spacing(5)

let atrStr2 = "bbb".attribute()
    .font(.systemFont(ofSize: 15))
    .textColor(.red)
    .spacing(1)
        
let atrStr3 = "ccc".attribute()
    .font(.systemFont(ofSize: 12))
    .textColor(.green)
    .spacing(10)
        
label.attributedText = atrStr1 + atrStr2 + atrStr3
```
<img width="126" alt="Screen Shot 2019-03-31 at 20.32.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/216743/fba43784-f925-79c4-5382-966a8a508816.png">

#実装法

```swift
extension String {
    
    func attribute() -> NSMutableAttributedString {
        return NSMutableAttributedString(string: self)
    }
}

extension NSMutableAttributedString {
    
    static func + (left: NSMutableAttributedString, right: NSMutableAttributedString) -> NSMutableAttributedString {
        left.append(right)
        return left
    }
    
    func font(_ font: UIFont) -> Self {
        addAttribute(.font, value: font, range: NSMakeRange(0, string.count))
        return self
    }
    
    func textColor(_ color: UIColor) -> Self {
        addAttribute(.foregroundColor, value: color, range: NSMakeRange(0, string.count))
        return self
    }

    func backgroundColor(_ color: UIColor) -> Self {
        addAttribute(.backgroundColor, value: color, range: NSMakeRange(0, string.count))
        return self
    }
    
    func baseLineOffset(_ offset: CGFloat) -> Self {
        addAttribute(.baselineOffset, value: offset, range: NSMakeRange(0, string.count))
        return self
    }

    func underline(color: UIColor, style: NSUnderlineStyle) -> Self {
        let attributes: [NSAttributedString.Key : Any] = [
            NSAttributedString.Key.underlineStyle : style.rawValue,
            NSAttributedString.Key.underlineColor : color
        ]
        addAttributes(attributes, range: NSMakeRange(0, string.count))
        return self
    }
    
    func spacing(_ spacing: CGFloat) -> Self {
        addAttribute(.kern, value: spacing, range: NSMakeRange(0, string.count))
        return self
    }
}
```
個人的に演算子のオーバーロードのところとかが気になっています

参考
https://qiita.com/roba4coding/items/7a5decc7e4f6137fcc88
プログラミング学習記録43〜クオリティが低くても公開した方がいい〜

##今日やったこと
- 昨日作った「メモの魔力」のwebアプリの動作確認と動画撮影

ちゃんと新規会員登録できるのか、ログイン、ログアウト、、、などが機能してくれるかどうかを確認し、アプリを実際に使っている様子を画面収録で動画撮影しました。

今日はほとんど何もやっていません。

ですが、Twitterにアプリの動画をあげたところ思った以上に反応が来たので作ってよかったな、と思いました。

Twitterという広い世界では誰かしらが評価してくれます。

いい評価をもらえるのか、よくない評価をもらえるのか、そもそも評価をもらえないのかはわかりませんが、何かしらプラスになることがあります。

「クオリティが低くて公開するのは恥ずかしい」というレベルのものでも、どんどん公開していくべきなんだなと改めて思いました。

明日からは今回作ったアプリのコードを整理（主にCSS）します。

そして、作ったアプリをGitHubに上げるためにGit、GitHubについても学習していこうと思います。

ということで、明日からも引き続きプログラミング学習頑張ります。

おわり
getRequestDispatcher()メソッド

java初学者です。
今回はgetRequestDispatcher()メソッドについてアウトップトさせていただきます。
#Q1: getRequestDispatcher()メソッドとは？
・ServletからJSPを表示するためのインターフェイス
#Q1: getRequestDispatcher()メソッドの使い方
`.getRequestDispatcher("./sample.jsp").forward(request, response);`
この書き方がよくあるのではないかと思います。
突然出てきた, **forward(request, response)** というのはRequestDispatcherインターフェイスを使うことで使用可能になるメソッドです。
forwardを使うことで指定のJSPへ飛ばすことができます。
#使い所
doPost()メソッドやdoGet（）メソッドから抜けた後のページ変移に使うことが多いと思います。
メソッドの処理から抜けた後、ブラウザに表示するものがなくなったらエラーになってしまいますからね。




※内容に間違いがあった場合、恐れ入りますがコメントからご教授いただけると幸いです。
プログラム初心者のためのC#入門 #0 Hello, world!

# #0 Hello, world!
プログラムにあまり慣れ親しんでいない初心者に向けてC#プログラムの書き方を教えるつもりでQiitaにまとめることで，自分の中の数少ない知識を整理するという目的で書いていきます．今回はVisual Studioのインストールから実際に簡単なプログラムを書くまでをまとめようと思います．また，今回はWindowsで行うことを前提としています．

#なぜC#なのか
C#はWindowsの開発元であるMicrosoftが開発した言語で，IDE(統合開発環境)もMicrosoftが出しています．また，公式のドキュメントも多く，Unityでも使われているため，サンプルコードも簡単に見つかるため，比較的簡単に習得できるプログラミング言語です．

##VisualStudioのインストール
まずはVisual Studioをインストールし，プログラムを書く環境を整えます．
Visual Studioは[こちらのサイト](https://visualstudio.microsoft.com/ja/downloads/)からCommunityのインストーラをダウンロードしてください．
Visual Studio Installerを起動して，ワークロードをインストールします．ワークロードはUniversal Windows Platform developmentと.NET desktop developmentをインストールすれば十分だと思います．

##プロジェクトの作成
インストールが完了したら，次は実際に簡単なプログラムを書きましょう．
Visual Studioを起動し，**[新しいプロジェクトの作成(N)]** -> **[コンソールアプリ(.NET Framework)]** を選択します．プロジェクトの**名前**をHelloWorldにすると，自動で**ソリューション名**もHelloWorldになるのでそのまま [OK] を押してプロジェクトを作りましょう．今回作ったプロジェクトは C:\Users\\(UserName)\source\repos の中に作成されていると思います．保存場所を変えたい場合は，**場所**のところでお好みの場所を指定してください．
##Hello, world!
```HelloWorld.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}
```

さて，プロジェクトを作成すると上のようなプログラムが自動で作成されます．まずは，**using**や**namespace**，**class**などは考えずに，**static void Main(string[] args)**に注目しましょう．

static void Main(string[] args)と波括弧で囲われた部分を総じて**Main関数**と呼びます．プログラムはこのMain関数の中に書いたことが実行されます．試しに次のように書いて実行してみましょう．

```HelloWorld.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, world!");
        }
    }
}
```
```:出力結果
Hello, world!
```
**[デバッグ]** -> **[デバッグなしで開始]**または**Ctrl + F5キー**で実行できます．
**Console.WriteLine("Hello, world!");** は，"(ダブルクオーテーション)で囲われた文章がコンソールに出力されるものです．
もうお気づきの方もいらっしゃるかもしれませんが，C#では文の終わりに`;`(セミコロン)をつける決まりがあります．これを忘れるとエラーになるので気をつけましょう．


今回はここまで．次回は[リテラルと変数・定数](https://qiita.com/17t7037t/items/c0b5dafb9da68b42ca07)について説明します．
##練習問題
自分の名前を画面に出力するプログラムを書いてください．

<details><summary>解答例</summary><div>
丸括弧の中の値を変えるだけなので簡単ですね．

```HelloWorld.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Kyohei Morita");
        }
    }
}
```
</div></details>
Django入門02（開発編）

Djangoを設定後、開発でハマったところについて書く。

前回
[Django入門01（設定編）](https://qiita.com/yKRSW/items/8176cdad3f4b1df6dcf0)


# モデル作成

## 既存テーブルを用いる

モデルを作成すると、モデルは命名則に従ったテーブルに対してデータ操作をしようとする。
しかし既にテーブル作成済みの場合はDjangoの命名則に従わずに既存のテーブル名を使いたくなる。
その際、メタオプションを用いる。

[Model Meta options](https://docs.djangoproject.com/ja/2.1/ref/models/options/#table-names)

具体的には以下のように記述する。
（Meta optionsはモデル定義の中に書く）

```
class モデル名(models.Model):
    モデルのフィールド設定
    
    class Meta:
        db_table = '(このモデルと紐づけたいテーブル名)'
```

## フィールド設定

### フィールドの型
[Django: モデルフィールドリファレンスの一覧](https://qiita.com/nachashin/items/f768f0d437e0042dd4b3)

### 複数フィールドの組み合わせでPrimary Keyを設定できない

Djangoは複合キーをサポートしていない。
しかしモデル上でPrimary Keyを指定せずにadmin機能を使おうとすると、データ選択した際にエラー画面に遷移してしまう。
（admin機能を使わなければ大丈夫かどうかは未確認）
[Multi-Column Primary Key support](https://code.djangoproject.com/wiki/MultipleColumnPrimaryKeys)

回避するにはDB側のテーブルにてPrimary Key用にIDカラム（auto increment）を設け、本来のPrimary Keyのカラムにはunique indexを張る。

## 別スキーマのデータを参照する

アプリの使うスキーマはAだが、別スキーマBに保存されているマスタも参照させたい場合、「Django model schema multiple」などで検索してもよくわからず。

### 方法１：Viewにしてしまう

そこで発想を転換し、スキーマBのマスタに対してselectするviewをスキーマAに作成することでadminからマスタを参照できる事を確認できた。
（もっと良い方法があれば共有願います）

### 方法２：settingsで接続DBを制御する

settings.pyとDATABASE_ROUTESで接続先を切り分ける方法もある模様。
方法２はDjango側の設定だけで済むし、方法１はDB側にview追加するだけで済むので目的に応じて使い分けが必要かと思われる。

参考：[Djangoで複数のデータベースを使う](https://tokibito.hatenablog.com/entry/20160202/1454344534)


# WEBサーバー

## ローカルPCで起動したDjangoサーバーを公開

settings.pyでALLOWED_HOSTSの設定を変更

```
ALLOWED_HOSTS = ['*']
```

さらにWEBサーバーを起動する際にデフォルトでは127.0.0.1で起動してしまい、他のユーザーが起動しているマシンのIPをWEBブラウザで参照しても見られない。
他のユーザーにも公開するには0.0.0.0で起動する必要がある。

```
python manage.py runserver 0.0.0.0:8000
```

# データ操作

## id項目以外を用いた結合

Djangoでモデルを結合する場合は、暗黙的にprimary key であるid項目で結合している模様。
[一対一 (one-to-one) 関係](https://docs.djangoproject.com/ja/2.1/topics/db/examples/one_to_one/)
[多対多 (many-to-many) 関係](https://docs.djangoproject.com/ja/2.1/topics/db/examples/many_to_many/)

auto incrementしているid項目だと、リレーションが崩れやすいので値に意味を持つ一意項目で結合したい。

### 生SQLの実行

強引な手段ではあるが、生SQLを記述する方法がある。
以下のようにrawを使うことで生SQLの実行が可能。

```
from .models import (モデル名)

def (view名)(request):
    (変数) = (モデル名).objects.raw( (SQL文字列) )    
```
#### 注意点1：primary keyが必要

select結果にprimary keyが無いと

```
Raw query must include the primary key
```
のエラーが発生する。

特にハマりやすいのが

```
select
m.id
...
from hogetable m
```
ではエラーを回避できないこと。

```
select
m.id as id
...
from hogetable m
```
と **エイリアスを追加** することでやっとエラーが回避できた。

#### 注意点2：like検索等で"%hoge%"を直接SQL内に書くとエラーになる

```
(変数) = (モデル名).objects.raw( "select colA, colB, colC from tableX where colD like '%hoge%' " )  
```
と書くとargumentエラーが発生してしまう。

```
(変数) = (モデル名).objects.raw( "select colA, colB, colC from tableX where colD like %s", tuple(["%hoge%"]) )  
```
と外出しすることでSQLを実行できる。

[Error while using like statement in django raw sql](https://stackoverflow.com/questions/6366734/error-while-using-like-statement-in-django-raw-sql)
has_manyとbelongs_toにinverse_ofオプションが必要なケースを検証してみた

has_manyとbelongs_toでinverse_ofオプションが必要なケースを検証してみました。
結論から書くと`has_many`で`inverse_of`が必要なケースは検証できましたが`belongs_to`での必要なケースが不明でした。

[検証に使用したリポジトリ](https://github.com/kenchiki/rails-example-inverse_of)

## has_manyでinverse_ofが必要なケース（ソース抜粋）
```ruby
# app/models/blog.rb
has_many :articles, -> { order(id: :desc) }, dependent: :destroy, inverse_of: :blog
accepts_nested_attributes_for :articles, reject_if: :all_blank

#app/models/article.rb
validate ->(article) {
  if article.blog.title == article.title
    errors.add(:title, 'blogタイトルとarticleタイトルが同じではいけない')
  end
}
```

## has_manyでinverse_ofが不要なケース（ソース抜粋）
```ruby
# app/models/blog.rb
has_many :articles, dependent: :destroy
accepts_nested_attributes_for :articles, reject_if: :all_blank

# app/models/article.rb
# 必要なケースと同じソース
```

## 上記の結果から分かること

- `-> { order(id: :desc) }`の有無で`inverse_of`の必要性が決まりました。
- `-> { order(id: :desc) }`がある状態で`inverse_of`をつけないと`validate`の中の`article.blog`が参照できずnilになりました。（inverse_ofをつけると参照できました）


## belolngs_toにinverse_ofが必要なケースを検証
（そもそも`= simple_form_for(@article)`のフォームから親のBlogを生成するケース自体、稀かもしれませんが…）

[実際に試してみたブランチ](https://github.com/kenchiki/rails-example-inverse_of/tree/feature-belongs-to-inverse-of)

## belongs_toでinverse_ofをつけた場合（ソース抜粋）

```ruby
# app/models/blog.rb
validate ->(blog) {
  if blog.articles.map(&:title).include?(blog.title)
    errors.add(:title, 'blogタイトルとarticleタイトルが同じではいけない')
  end
}

# app/models/article.rb
belongs_to :blog, inverse_of: :articles
accepts_nested_attributes_for :blog
```

フォームで送信したはずのArticleのデータ`blog.articles`が参照できませんでした。（デバッグのため`blog.articles.length`と書いても`0`が返ります）

`belongs_to`に`inverse_of`を書けば保存前の`blog.articles`が参照できると考えていましたが、実際にはそのような動きにはなりませんでした。


## 追記（2019年4月6日）
勉強会でご一緒した方に`has_many - belongs_to`の関係で`belongs_to`に設定した`inverse_of`は現状サポートされていないとの情報を共有いただきました。
情報共有いただきまして感謝いたします！

下記は[https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/belongs_to_association.rb#L111-L112](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/belongs_to_association.rb#L111-L112)からコメント抜粋

```text
# NOTE - for now, we're only supporting inverse setting from belongs_to back onto
# has_one associations.
```

## 参考
- [【Rails入門】ActiveRecordの関連付けでinverse_ofが使われないワケ](https://www.sejuku.net/blog/66868)
GCPのメール送信(GAE standard, GAE flexible, GCE) 

#問題点
Google App Engineフレキシブル環境では、SendGrid、Mailgun、Mailjet等のサードパーティーのサービスを利用してメールを送信するとされています。
Google App Engineスタンダード環境では、サードパーティーのサービスを使う以外にApp Engine Mail APIを利用することができます。
フレキシブル環境で、App Engine Mail APIは利用できませんが、App Engine Mail APIでメール送信するスタンダード環境のAPIサーバーを１個立てて、それをフレキシブル環境から呼び出すことによりメール送信することができます。
しかし、App Engine Mail APIは課金を有効にした場合でも一日100通（メール＊送信先）という制限があります。制限を解除するようGoogleに問い合わせてもサードパーティーのサービスを使うよう案内されます。（建前）

Compute Engineでもメール送信は、サードパーティーのサービスやG Suiteアカウントを使う、自社メールサーバーを使う等方法がありますが、いろいろあっても環境によっては全滅です。

#解決策
Gmail のアカウントを新たに取得して、GmailのSMTPを経由してメールを送信することができます。G Suiteは必要ありません。
smtp.gmail.com の587ポートで送信できます。
これで、GAEスタンダード環境、GAEフレキシブル環境、GCEに対応します。

Gmailの設定で、安全性の低いアプリからのアカウントへのアクセスを許可する必要があります。
>1,Google アカウントに移動します。
>2.左側のナビゲーション パネルで [セキュリティ] をクリックします。
>ページ下部の [安全性の低いアプリのアクセス] パネルで [アクセスを有効にする] をクリックします。
>この設定が表示されない場合、安全性の低いアプリによるアカウントへのアクセスを管理者が無効にしている可能性があります。

おそらく新しいサーバーIPから送信しようとしたとき、ブロックされる場合があります。
送信元のGmailアドレスに「重大なセキュリティ通知」「不正なログインがブロックされました」というメールが届きます。このメールのリンクからブロック解除することができます。
PC(Win10)とデバイス機器で要素検証

# デバイスで要素検証するための環境作成について

## ◆iphone
スマホサイトのiPhone表示をWindowsでデバッグする方法
iPhoneのWebインスペクタをWindowsで表示できる(ブラウザはChromeが必要)

デバイスを判定するために、itunesをいれてある必要あります。

[ios-webkit-debug-proxy-win32](https://github.com/google/ios-webkit-debug-proxy)をインストールし、Zipを解凍したら完了です。

※iPhoneの方では、Webインスペクタを有効にする必要です。
この設定は、設定アプリ→Safari→詳細にあります。環境構築はこれだけで完了です。
#### Webインスペクタを表示する
① iPhoneをWindowsにUSB接続します。
iPhoneで「このコンピュータを信頼しますか」と聞かれたら「信頼」をタップします。

② Windowsで、先程解凍したios-webkit-debug-proxy.exeを起動します。
iPhoneと通信できなくなったりするとエラーが表示されます
起動したときにWindowsのセキュリティ警告が出た場合は「アクセスを許可する」をクリックしてください。

③iPhoneでデバッグしたいサイトを開きます。
④ WindowsのChromeで[localhost:9221](localhost:9221)を開きます。
⑤ iPhoneのデバイス名のリンクが表示されるので、それをクリックします。さらに、safariで開いているページの一覧が表示されるので、デバッグしたいサイトをクリックします。

ChromeにWebインスペクタが表示され、デバッグできるようになりました。


#### PC(Chrome)とiphone端末を接続
![messageImage_1554028665635.jpg](https://qiita-image-store.s3.amazonaws.com/0/57249/03652ede-7962-57a2-3db9-2692c5554f38.jpeg)

![25746.jpg](https://qiita-image-store.s3.amazonaws.com/0/57249/0f0990b6-29ca-8e8c-a6ed-573134f99be4.jpeg)

## ◆Android
①　Android側で、設定＞システム＞端末情報＞ビルドをタップ、タップ・・
（機種によって変わる場合あり）
⇒　開発者向けオプションが使える状態になる

②　USBデバックにチェックを入れて、PCと接続。許可するを選択。

③  シークレットモードでChromeを開き、F12キー、または右クリックからの「検証」でデベロッパーツールを呼び出す。

④  [リンク１](https://developers.google.com/web/tools/chrome-devtools/remote-debugging/?hl=ja)の通りに手順を踏む

####PC(Chrome)とAndroid端末を接続
![messageImage_1554028312041.jpg](https://qiita-image-store.s3.amazonaws.com/0/57249/eaa5e813-c2d8-0814-d57e-c157e4616ffa.jpeg)

![25743.jpg](https://qiita-image-store.s3.amazonaws.com/0/57249/ca9a5218-e4d6-4b70-5476-6a7da6b53a41.jpeg)

ChromeにWebインスペクタが表示され、デバッグできるようになりました。

## 感想
30分程で環境作成して、作業が進められました。

## 参考
[リンク１](https://developers.google.com/web/tools/chrome-devtools/remote-debugging/?hl=ja)
[リンク２](https://github.com/google/ios-webkit-debug-proxy)
[リンク３](https://developers.google.com/web/tools/chrome-devtools/device-mode/?hl=ja)
Azure Web App（Linux）でLet's Encryptを使って無料でSSL化する方法

#はじめに
Azure Web AppでもOSがWindouwsServerだとポータルからGUIでできるようなのですが
Linuxはそうではないので書きます

#1.「SSLなう!」を使ってLet's Encryptに登録

色々とやりましたが「SSLなう!」が便利です。
画面からポチポチしていきましょう。


<img width="991" alt="Screen Shot 2019-03-31 at 19.47.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/242700/cf858bfd-1cac-082c-288b-2d84c3376de4.png">
<img width="995" alt="Screen Shot 2019-03-31 at 19.47.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/242700/b5a2ec4f-bd88-06e5-0c5a-b0f534488d61.png">

「SSLなう!」
https://sslnow.ml/

#2.サーバの設定
上記のURLにリダイレクした際に「ファイル内容（1行です）」の内容が返ってくる必要があります。

※URLは「http://ドメイン名/.well-known/acme-challenge/乱数」
ファイル内容は「乱数」

なので、Azureのポータルから対象となるAppを選んだ後、開発ツールにあるSSHからデプロイ先に接続します。

通常であれば/var/www/htmlがデプロイ先なので

下記コマンドでファイルを作成します。

```
mkdir .well-known
cd .well-known
mkdir acme-challenge
cd acme-challenge
mkdir 乱数
cd 乱数
vi index.php
```

そしてindex.phpの中に乱数を記載します。
（今回はphpを使いました）

#3.証明書発行申請&発行された証明書

再びSSLなう!に戻ってポチポチしていきます。
その際に証明書発行申請できたKeyを貼り付けたsample.keyファイルと
発行された証明書でできたcert.pem(サーバ証明書)の内容を貼り付けたcert.pemファイルを作成しましょう。

#4.鍵の変換
Azureにあげるには「.pfx」に変換する必要があるので下記コマンドを実行します。

```
openssl pkcs12 -export -in cert.pem -inkey Server.key -out sample.pfx 
```
パスワードも設定するように聞かれるので設定しましょう。

#5.Azureにアップロード&バインド
もう完了です。

証明書を下記からアップロードします。
<img width="1205" alt="Screen Shot 2019-03-31 at 20.04.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/242700/cdf5250f-d73b-36af-416c-a0ac77967898.png">


その後対象のドメインにバインドします。

#おわりに

GCPってデフォルトでSSLになるんじゃなかったけ…
エンジニアチームのリーダーとして考えてきたこと：不安編

- [前提編](https://qiita.com/tunacook/items/770252ea3c644b6cb2eb)
- [運用フェーズ編](https://qiita.com/tunacook/items/f27d464968363c9fdc65)
- [開発フェーズ編](https://qiita.com/tunacook/items/3942dbe55988d9e96412)

上記記事ではいろいろと考えてきたことを書きましたが、そう言っても人間不安は尽きないものです。

## 週の目安消化工数が目標よりも少なかった……

焦る気持ちは当然あるかも知れませんが我慢です。進捗を強制しても進捗が上がることは決してありません。**焦る態度はチームメンバーには見せないように心がけましょう。**

実装項目を減らしたり、人数を投入してもらえるように交渉したりと、リーダーのとれる行動はまだあります。へこんでいる暇があったら行動するべきです

## リファクタリングやカイゼンでプロダクトが壊れたらどうしよう

**プログラムなので、挙動には必ず理由があります。**

事前によく調べれば良いし、万一トラブってもそれには必ず理由があるので対処できます。我々の触っているプロダクトは超常現象ではないのです。

## プロジェクトが迷子になったらどうしよう

お客さんは我々と同じ方向を向いているものです。ステークホルダーと話し合いましょう。

**要件を満たして納期に間に合わせるという我々と同じ目的を持っている人には話が通じます。**そこは安心して良いです。

むしろ話が通じないのは、我々の業務とはなんの関わりもない人が多いです。

## 緊急対応に備えるって言うけど解決できなかったらどうしよう

前述の通り、現象には必ず理由があります。~~某イケメン大学教授も言ってます~~

**理由がわかれば必ず解決できます。**

## 新人教育するのに辞められたらどうしよう

もちろん上司がパワハラしたから辞めてしまうというケースもあるでしょうが、新人がついていけないと思うのは様々な要因があります。

本人の興味が違っている、教育するほど置いておける状況にない、パワハラじゃなくても上司が嫌われてしまった……etc

なのでもし教育した新人が辞めてしまっても、ちゃんと要因を分析することが大事です。辞める新人氏とも良い関係を築いておくべきでしょう。

## 開発が炎上したらどうしよう

開発が炎上する前に手を打っていくのがリーダーの仕事です。

メンバーと協力し、場合によってはメンバーから意見を募って問題をクリアしていきましょう。

## 最後に

これおすすめ

![](https://ohta-isan.co.jp/document/images/1411.png)

https://ohta-isan.co.jp/product/medicine//
現場で役立つシステム設計まとめ(前半)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/257568/be5dd5ea-a07b-991e-2b36-3ce752a28cbc.png)

リファクタリング時のコツ的な側面と、ドメイン駆動設計を噛み砕いて記載してある側面があるのでこちらの本を読んでまとめ

前半

## 小さくまとめて分かりやすくする
変更が大変なプログラムの特徴を押さえる

- メソッドが長い
- クラスが大きい
- 引数が多い

### プログラムの変更が楽になる書き方
- メソッド内の例
  - 分かりやすい名前を使う
  - 長いメソッドを段落毎に行間を開けてみる
  - 目的毎に変数を用意する
  - メソッドとして独立させる

### ドメインオブジェクトである事を意識する
- 業務用語に対応する対象領域をドメインと呼び、そのクラスをドメインオブジェクトと呼ぶ。ドメインへの理解に努力することで、プログラミングと一致させられ、変更が楽で安全になる

### 小さなクラスで分かりやすく安全にする
- データとロジックを概念的に切り分けて認識した上で、それらを分かり易く整理して組み合わせる
- 基本的なデータの種類を押さえる
  - 判断
  - 加工
  - 計算 

### 値用のクラスを作る
- 俗にいうイミュータブルオブジェクト
- 値オブジェクト(Value Object)
- setterを作らない 
- 値を重複させない

### 配列やコレクションはロジックを専用クラスに閉じ込める
- 複雑なので複数のことを1配列やコレクション処理の中でやらせない
  - コレクション操作のロジックをコレクションクラスに移動する
  - 同じ型のコレクションオブジェクトで返す
  - イミュータブルにして外部に渡す

## 場合分けのロジックを整理する
以下のオブジェクト指向設計の基本方針から外れない

- コードのかたまりは、メソッドとして抽出して独立させる
- 関連するデータとロジックは、1つのクラスにまとめる

### ifやswitchの使い方に注意する
- 区分ごとのロジックはプログラムを複雑にするのでそのまま書かない
- elseをなくす
- 早期リターンやガード節を使う

### 列挙型を活用する
- つまり多態を使う(enumはシンプルに記述できる)
- 区分ごとの業務ロジックをわかりやすく整理できる
- 区分ごとに別のクラスに分けると独立性を高めることができる
- 状態遷移などの管理に有効

## ドメインモデルの考え方で設計する
### ロジックとデータを持つクラスを一緒にする
- つまりドメインクラスにする
- 1メソッド1ロジックの置き場と考える(値だけそのまま返す処理にしない)
- 書きながら設計を見直す
- 短くして移動をし易くする
- メソッドは必ずインスタンス変数を使う

### 業務を俯瞰する
- パッケージなどを用いてクラスを整理する
- 3層(プレゼンテーション・アプリケーション・データソース) + ドメインモデルで考える

## アプリケーション機能を組み立てる
### 業務の関心事を分類する
- 3分類する
  - ヒト
  - モノ
  - コト
- 関係性を把握する
- コトは背景の業務ルールなどが前提となっているので重要

### 業務ルールを記述するドメインオブジェクトの基本パターン
|ドメインオブジェクト  |設計パターン  |
|---|---|
|値オブジェクト  |数値、日付、文字列をラッピングしてロジックを整理|
|コレクションオブジェクト  |配列やコレクションをラッピングしてロジックを整理  |
|区分オブジェクト  |区分の定義と区分ごとのロジックを整理 |
|列挙型の集合操作  |状態遷移ルールなどを列挙型の集合として整理  |

## 書籍情報
増田 亨, 現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 
https://amzn.to/2FkD62f

## 雑感
文献元を読んでからだと理解の度合いがまた違う
hamlを使う時に便利なものをまとめる

随時更新予定！

# hamlit
- 特徴
    - Slimやhamlより処理が高速
- 導入手順
    - Gemfileに「hamlit」と記載して、「bundle install」

# erb2haml
- 特徴
    - erbファイルをコマンドひとつでhamlファイルに一発置換
- 導入手順
    - Gemfileに「erb2haml」と記載して、「bundle install」
    - ターミナルで「rake haml:replace_erbs」とコマンド

# Convert HTML to HAML
- 特徴
    - html記法をコマンドひとつでhaml記法に一発置換
- 導入手順
    - [Convert HTML to HAML](http://htmltohaml.com/)でhtmlを貼り付けるのみ

# 参考
[Task2 トップ画面に商品一覧を表示する #2](https://github.com/writesomecode/ec_site/issues/2)

以上です。少しでも参考になりましたら、いいねやフォロー気軽にしていただけると励みになります！＼(^o^)／
python製の最新APIフレームワーク FastAPI を触ってみた

# FastAPIとは
FastAPIの[公式ページ](https://fastapi.tiangolo.com/)には次のように書かれています。

> FastAPIは、標準のPythonタイプヒントに基づいてPython 3.6+でAPIを構築するための最新の高速（高性能）Webフレームワークです。

> 主な機能は次のとおりです。

>Fast：NodeJSやGoと同等の非常に高いパフォーマンス（StarletteとPydanticのおかげで）。利用可能な最速のPythonフレームワークの1つ。

>速いコーディング：機能を開発する速度を約200％から300％*向上させます。

>バグを減らす：人間（開発者）が引き起こすエラーの約40％を減らします。*
直感的：優れたエディターサポート。至る所で完成。短時間でデバッグできます。
簡単：使いやすく学べるように設計されています。ドキュメントを読む時間が短くなります。
短：コードの重複を最小限に抑えます。各パラメータ宣言からの複数の機能。バグが少ない
堅牢：本番用のコードを入手してください。自動インタラクティブドキュメント付き。
標準ベース：APIのオープン標準に基づいており（そして完全に互換性があります）、OpenAPI（以前はSwaggerとして知られていました）とJSONスキーマ。

Nodejsやgo言語に匹敵するパフォーマンスらしい。
Python3.6以降が必須

# FastAPIの導入
自分はmac環境で導入しました。

## 必要条件

- Python 3.6以降

## インストール
```
pip install fastapi
```
```
pip install uvicorn
```

## ファイルの作成
```main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}
```

## サーバー起動
```
uvicorn main:app --reload
```


## アクセスしてみる
http://127.0.0.1:8000

```json
{ Hello: "World" }
```

http://127.0.0.1:8000/items/5?q=somequery

```json
{"item_id": 5, "q": "somequery"}
```

## apiドキュメントも自動で生成される
http://127.0.0.1:8000/docs

![alt](https://vps6-d.kuku.lu/files/20190331-1853_1ad6763ca92404706ea80e48e7dabc2d.png
)
Rubyでのハッシュの2種類の書き方

以下の記事で指摘を受けたので、ハッシュの書き方の違いを調べてまとめました
[SchooのRuby入門のまとめ](https://qiita.com/it31415/items/60468d03047edb48e4db)

# ロケットハッシュ

Rubyの昔からのハッシュの書き方は

```ruby

{ "key" => "value" }
=> {"key"=>"value"}
```

ロケットハッシュと言う



## 文字列と変数の違い


"key"みたいに文字列を使えばエラーは起きないが、keyみたいな変数だとこれより前で宣言していないといけない

```ruby

{ key => "value"}
NameError (undefined local variable or method `key` for main:Object)

key = "key1"
{ key => "value"}
=> {"key"=>"value"}
```


## シンボル


シンボルなら宣言しなくてもOK

```ruby

{ :key => "value"}
=> {:key=>"value"}
```

キーは文字列ではなくシンボルを使う方が普通らしい


```ruby

{ key: => "value"}
syntax error, unexpected '}', expecting end-of-input
{ key: => "value"}
                 ^
```

こういう書き方はだめ



## 文字列とシンボルの違い


文字列とシンボルは違うものなので

```ruby

{ "key" => "value" }
=> {"key"=>"value"}
と

{ :key => "value"}
=> {:key=>"value"}
```

は別のもの

ただ、Railsのライブラリでよくあるらしいが、どちらのタイプのハッシュを渡しても同じように扱ってくれることがあるらしい

それは渡した先のメソッドが違いを吸収してくれるらしい



## シンボルの2種類の書き方


:fooと:"foo"は全く同じシンボル

```ruby

:foo
=> :foo

:"foo"
=> :foo
```

""で囲めば数字で始まるシンボルとか，スペースを含むシンボルとか，空文字列に対応するシンボルを表せる

```ruby

:"1st" # 数字で始まるシンボル
:"foo bar" # スペースを含むシンボル
:"" # 空文字列に対応するシンボル
```


# Ruby1.9以降で追加されたシンボルを使ったハッシュの書き方


Railsではシンボルを使うのが普通なので、Ruby1.9からシンボルを使った新しい記法がサポートされた

```ruby

{ key: "value"}
=> {:key=>"value"}


{ key: :value}
=> {:key=>:value}

{ :key => :value}
=> {:key=>:value}
```

バリューの方をシンボルにしても大丈夫みたい



あまりしない方が良さそうだけど、ロケットハッシュとシンボルで書く方法を混ぜても大丈夫みたい

```ruby

{foo: 1, :bar => 2}
=> {:foo=>1, :bar=>2}

{:foo => 1, "bar": 2}
=> {:foo=>1, :bar=>2}
```

どちらも同じ出力になる

# おわりに
最後まで読んでいただきありがとうございました。
QiitaやTwitterなどにコメントをしてもらったり、SNSでシェアしてもらえるとうれしいです！

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Rubyでのハッシュの書き方の違いをまとめました<br><br>文字列とシンボルの違いがわかっていない人にもおすすめです！<br><br>Rubyでのハッシュの2種類の書き方 <a href="https://t.co/2slLcuaTOb">https://t.co/2slLcuaTOb</a> <a href="https://twitter.com/hashtag/Qiita?src=hash&amp;ref_src=twsrc%5Etfw">#Qiita</a></p>&mdash; ITのんびり@V字回復エンジニア (@it31415) <a href="https://twitter.com/it31415/status/1112671020782157824?ref_src=twsrc%5Etfw">2019年4月1日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
setAttribute / getAttribute について

java初学者です。
今回は、setAttribute / getAttribute についてアウトプットさせていただきます。
#setAttribute()
setAttributeで特定の名前を目印に値を格納
#getAttribute()
setAttributeでつけた名前を元に値を取り出す
#Q1: どこに格納しているのか？
例えば、

①`session.setAttribute("str","Qiita");`
上記の場合、**session**のなかにstrという名前をつけた"Qiita"という文字列を格納している。

②`request.setAttribute("language","Java");`
上記の場合、**request**のなかにlanguageという名前をつけた"Java"という文字列を格納している。
#取り出す時の書き方
①の場合、
`session.getAttribute("str");`
これで、"Qiita"という文字列を取得できる。

javaでは基本的に
**set**は格納
**get**は取り出し
このように捉えていいと思います。


※内容に間違い等があった場合、恐れ入りますがコメント欄から教えていただけると幸いです。
エンジニアチームのリーダーとして考えてきたこと：前提編

2018年12月に開発リーダーを務めていたプロダクトがリリースし、今年から異動により別チームとなりリーダー業務から卒業しました。2017年から今のチームのリーダーをやってきたので、かれこれ2年ほどになります。

ありがたいことに**「運用フェーズチームのリーダー」**と**「開発フェーズチームのリーダー」**両方を経験することができたので、それぞれのフェーズでどのようなことを考えて取り組んできたか、通常業務以外でどのような課題に取り組んできたかを書き残しておきたいと思います。

あまり詳しいことはNDAの関係で書けないため、ある程度応用の利くように抽象化して書いていきたいです。


# リーダーに必要な姿勢

結局のところ、チームの問題や課題というのは千差万別なので、これさえやっとけばOKというものは存在しないです。

ただ、どのようなチームにも問題や課題というものは持っており、**そんなものが存在しないと抜かすのは見えていないだけの戯言**です。

そういうものについていかに気づいていけるか、どのように対処するか、というのがリーダーの仕事であると思っています。

チームに長くいればいるほど抱えている問題に気づきにくいという側面ももちろん存在するので、常に目を皿のようにして課題に気づいていく姿勢が大事だと思います。また、新しくジョインしてきたメンバーに感想を求めるのも良いと思います。ぜひ耳を傾けましょう。


今回は受託開発での運用業務・新規開発業務のことであるというのが前提なので、自社開発やBtoC案件のもの、スタートアップ、非ゲーム案件といった状況が異なる場合は、また違った対応になってくるでしょう。

自社開発やスタートアップの場合の組織論とかチーム運用については、すでに優秀な人が本を執筆しているし、Web上にもまた私より優秀な人たちが資料をあげています。またチームに対して予算がつく場合もあるでしょうし、そうなればしめたもの。

アジャイルに則ってーとか、スクラムを使ってーなどとマネジメント技術を駆使できれば格好良かったのですが、それらを学んでみて実践しようとしても、結局のところは現実に起きている問題に対処していくしかないです。

マネジメント技術は起きている問題に対処していく手段、武器の一つに過ぎないので、結局のところマネジメント技術ありきではなくどう使うかの選択をどうしていくかというほうが重要なんじゃないかと思っています。

誤解しないでほしいのは、これらの技術を学ばなくても良いということでは**ないです。**技術を一通り学んだ上で、その時その時の状況を見て現場に対して何が使えるかの選択をしていきましょう。

何度でも書きますが、プロジェクトの状況を見て武器（やり方）を使い分けていくべきです。


# どんな状況のチーム？

ここで私の担当したチームの状況を書きます。状況に応じてチームやリーダーの動き方は大きく変わってきますが、ざっくり書くとこんな感じです。

- お客さんの案件を請け負う受託開発である
  - 勤務している会社の性格上、受託開発案件が多いのですが、多分に漏れず私の担当したチームも、お客さんから工数（人月）をいただいて開発を行っていくものでした
- 案件はブラウザゲーム
- 2012年からスタートしているが、3年程度周期で新規タイトル(続編)開発が行われる
- 2018年3月頃、3番目の続編開発が始まった
- そのため**新規開発といっても常に運用中のものが存在する**という結構特殊な環境であった

それぞれのフェーズで考えてきたこと、取り組んできたことを書いていきたいと思います。


# 今回書かないこと

なお、各フェーズにおける機能開発や具体的な実装技法については今回は割愛します。

また、主にこのようなフローで「通常開発」が行われましたが、これについても割愛します。

- 既存バグ修正
- 運用中、追加機能を実装する上での見積もり
  - 仕様内容すりあわせ
  - 工数の見積もりと実装内容の交渉
- 実装
- テスト
- 監視
- トラブル対応
- お客さんからの要望・質問に答え続ける

あまりにもエンジニアの日常すぎるので、今回は書いても仕方ないかなと思うためです。

- [運用フェーズ編](https://qiita.com/tunacook/items/f27d464968363c9fdc65)
- [開発フェーズ編](https://qiita.com/tunacook/items/3942dbe55988d9e96412)
- [不安編](https://qiita.com/tunacook/items/8d7cbbdf813833bc2dd8)
Flaskで作成したAPIをLANからアクセス可能にする。

# せっかくなら研究をWebアプリにしよう。

と思い立ちFlaskを利用したAPIとしてローカルPCでの実行、ブラウザからのアクセスができることを確認した。

研究室のLAN内からのアクセスを可能にしようと考え、サーバ上でAPIを実行させ、自分のPCからアクセスしようとしたところでやや詰まった。

# 参考記事
https://qiita.com/tomboyboy/items/122dfdb41188176e45b5
だけでは分からなかったので補足。

# 結局のところ

```python
app.run(debug=False, host='0.0.0.0', port=80)
```
の部分ですが`0.0.0.0`が特殊なアドレスらしく、そのままブラウザに入力しても機能しない。
サーバ自体のIPの指定したポート(ここでは80)にアクセスするとうまくいく。

ポートの解放も忘れずに。

うまくいかなかった場合には勉強込みでIISとかapacheとか使うことも考えましたが解決したのでよかったです。
NuxtアプリをGoogleCloudPlatformにデプロイする

## Nuxtアプリを作成
```
yarn create nuxt-app noracorn-gcp-nuxt
```

```
? Project name noracorn-gcp-nuxt
? Project description My exquisite Nuxt.js project
? Use a custom server framework none
? Choose features to install Axios
? Use a custom UI framework vuetify
? Use a custom test framework jest
? Choose rendering mode Universal
? Author name noracorn
? Choose a package manager yarn
```

## package.jsonを編集
```package.json
{
  "name": "noracorn-gcp-nuxt",
  "version": "1.0.0",
  "description": "My exquisite Nuxt.js project",
  "author": "noracorn",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build --no-lock", ←を変更
    "start": "HOST=0.0.0.0 PORT=8080 nuxt start", ←を変更
    "generate": "nuxt generate",
    "test": "jest"
  },
  "dependencies": {
    "cross-env": "^5.2.0",
    "nuxt": "^2.4.0",
    "vuetify": "^1.5.5",
    "vuetify-loader": "^1.2.1",
    "@nuxtjs/axios": "^5.3.6"
  },
  "devDependencies": {
    "nodemon": "^1.18.9",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.2",
    "@vue/test-utils": "^1.0.0-beta.27",
    "babel-core": "7.0.0-bridge.0",
    "babel-jest": "^24.1.0",
    "jest": "^24.1.0",
    "vue-jest": "^3.0.3"
  }
}

```

## app.yamlを追加
プロジェクト直下にapp.yamlを作成する

```yaml

runtime: nodejs10

instance_class: F2

handlers:
  - url: /_nuxt
    static_dir: .nuxt/dist/client
    secure: always

  - url: /(.*\.(gif|png|jpg|ico|txt))$
    static_files: static/\1
    upload: static/.*\.(gif|png|jpg|ico|txt)$
    secure: always

  - url: /.*
    script: auto
    secure: always

skip_files:
- node_modules/
- public/
- src/
- .browserslistrc
- .gitignore
- babel.config.js
- pakage.json
- postcss.config.js
- README.md
- tsconfig.json
- tslint.json
- yarn.lock

env_variables:
  HOST: '0.0.0.0'
  NODE_ENV: 'production'
```

## GoogleCloudPlatformでプロジェクト作成
ここでは、noracorn-gcp-nuxtにしました。
被っているプロジェクト名などの場合は、project-IDが別のものが振られるものものがあるので要確認

## ビルド
```
cd noracorn-gcp-nuxt
yarn build
```

## GoogleCloudPlatformにデプロイ
```
gcloud app deploy app.yaml --project noracorn-gcp-nuxt
```

## 確認

https://noracorn-gcp-nuxt.appspot.com
react-component/slider の exampleに騙された話

# 初めに

`react-component/slider` を ↓ のexample通りにTypeScriptで使ったら、 `maximumTrackStyle` なんてpropは無い、と怒られてビルドが通らなかった。
https://github.com/react-component/slider/blob/master/examples/slider.js#L161

(※ 出したPRがマージされたので現時点では既に問題無い)

# やったこと
```bash

$ yarn add rc-slider
$ yarn add --dev @types/rc-slider
```

```tsx

import Slider from 'rc-slider'

<Slider maximumTrackStyle={{ backgroundColor: 'rgba(0, 0, 0, 0)' }} />
```

などとすると、tscに怒られる。

```bash

$ yarn tsc
Property 'maximumTrackStyle' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Slider> & Readonly<SliderProps> & Readonly<{ children?: ReactNode; }>'.

139             <Slider
                 ~~~~~~
```

# 原因

exampleが古かった。↓ に、deprecatedになるからそのpropは使うな、と書いてある。

https://github.com/react-component/slider/blob/master/src/Slider.jsx#L33

# 結局

trackStyle / railStyle を使うようにしたら無事ビルドが通った。
せっかくなので修正するPRを出しておいた。

https://github.com/react-component/slider/pull/552

# 終わりに

OSSの管理をちょっとサボると結構困る人がいる、ということを目の当たりにする良い機会だった。

# (追記)

マージされてた。早い。
https://github.com/react-component/slider/pull/552
ベルサイユのばらを観終わったのでエンディング曲をJavaで再現してみた



みなさんはベルサイユのばらを観たことがあるだろうか？

当然あると思う。

私は最近になってベルばらを観たのだが、物語の終わりを受け止めきれなかったので、
ベルばらのエンディング曲を再現するクソコードを書いて寂寥感を埋めることにした。

こうして出来た虚無が以下のコードだ。

歌詞はググって下さい。


```java.TheRoseofVersailles

import java.util.*;

public class TheRoseofVersailles{
 public static String love="love";
 public static String loversName="Oscar";

 public static void main(String[] args) throws Exception {
        Amero();
 }
 
 public static void Amero(){
    int yourHeart=0;
    String love="suffering";
    while(love=="suffering"){
     yourHeart++;
     System.out.println("Love is "+love);
     if(yourHeart==10)love="love";
    }
     Bmero();
 }
 
 public static void Bmero(){
    String you="light";
    String me="shadow";
    String bond=you+" and "+me;
    System.out.println("you and me=="+bond);
    Sabi();
 }
 
 public static void Sabi(){
    for(int suffer=0;suffer<5;suffer++){
        love=love+love;
        System.out.println("suffer"+suffer);
        System.out.println(love);
    }
    quote();
 }

 public static void quote(){
    Love();
    if(!(love.matches("love*")))System.out.println("love=="+love);
    boolean myEyes=false;
    if(myEyes==false)System.out.println("myEyes=="+myEyes);
    System.out.println(loversName);
    System.out.println(loversName+"!!!!!!");
 }

public static void Love(){
 love="can't be called love";
 }
}

```
実行結果:

```
Love is suffering
Love is suffering
Love is suffering
Love is suffering
Love is suffering
Love is suffering
Love is suffering
Love is suffering
Love is suffering
Love is suffering
you and me==light and shadow
suffer0
lovelove
suffer1
lovelovelovelove
suffer2
lovelovelovelovelovelovelovelove
suffer3
lovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelove
suffer4
lovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelovelove
love==can't be called love
myEyes==false
Oscar
Oscar!!!!!!
```
さようなら、我が愛しのオスカル
ABC - 072- A&B&C

#AtCoder ABC 072 A&B&C
[AtCoder - 072](https://atcoder.jp/contests/abc072)

#A問題

 - Xグラムの砂が1秒当たり1g減っていく
 - T秒後に何g残っているのか？
 - ただし、T秒経過前に砂が0gになる場合がある

```java
	private void solveA() {
		long numX = nextLong();
		long numT = nextLong();

		out.println(numX - numT > 0 ? numX - numT : 0);
	}
```

#B問題

 - 先頭から奇数番目の文字だけ抜き出して文字列を生成
 - 先頭は1文字目
    - なので、配列としては偶数番目が文字列としての奇数番目に該当

```java
	private void solveB() {
		String wk = next();

		StringBuilder builder = IntStream.range(0, wk.length()).filter(i -> (i % 2 == 0))
				.collect(() -> new StringBuilder(), (t, i) -> {
					t.append(wk.charAt(i));
				}, (t, u) -> t.append(u));

		out.println(builder.toString());
	}

```

#C問題
 
 - 数列 {$1,2,3 ・・・ a_i$} 全ての数字に対して一度だけ下記操作を行う
    - $+1$する
    - $-1$する
    - 何もしない
 - 結果として得られる数列の内、一番数が多いものを出力する
 
 - 全探索しても何とかなりますがほぼTLE確定なので、


操作しなくてはいけない数列を表にすると下記になる。

|1|2|3|4|5|6|7|INDEX|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|-|-|-|-|-|-|-|-|
|3|1|4|1|5|9|2|この数列は、以下のように操作ができる|
|-|-|-|-|-|-|-|-|
|4|2|5|2|6|10|3|全て+1|
|3|1|4|1|5|9|2|何もしない|
|2|0|3|0|4|8|1|全て-1|

「全て+1、なにもしない、全て-1」の内、一番出現率が高い数字を出力すれば問題の解答となる。

 - 「全て+1、なにもしない、全て-1」をした結果の出現率をMapに変換する
 - Mapの中でvalueが最大のものが一番出現率が高い

```java
	private void solveC() {
		int numN = nextInt();

		long[] wk = LongStream.range(0, numN).map(i -> nextLong()).toArray();

		Map<Long, Long> wkCount = Arrays.stream(wk).collect(() -> new HashMap<Long, Long>(),
				(t, i) -> {
					long constVal = 1;
					t.merge(i, constVal, (oldV, newV) -> oldV + newV);
					t.merge(i + 1, constVal, (oldV, newV) -> oldV + newV);
					t.merge(i - 1, constVal, (oldV, newV) -> oldV + newV);
				},
				(t, u) -> t.putAll(u));

		Entry<Long, Long> entryWk = null;
		for (Entry<Long, Long> entry : wkCount.entrySet()) {
			if (entryWk == null) {
				entryWk = entry;
			} else {
				if (entryWk.getValue() < entry.getValue()) {
					entryWk = entry;
				}
			}
		}

		out.println(entryWk.getValue());
	}
```
Maven初心者メモ

Maven概要
--
- Mavenでは、プロジェクト情報の管理や特定タスク処理の登録・実行を行うことができる。
- 設定は、pom.xmlに定義を記載していくことで行う。
- 各タスク処理は、プラグインをインストールすることで拡張することが可能である。
- プラグインはタスク処理を実行するためのコマンドであるゴールを提供する。
- Mavenにはライフサイクルというビルドの流れを表現する概念がある。
- コマンドを実行する方法には、ライフサイクル、ゴールを利用する。

ライフサイクル
--
- ライフサイクルは、フェーズというステージによって構成されている。
- ライフサイクルには、ゴールを紐づけることが可能である。
- ライフサイクルにデフォルトでいくつかのゴールが紐づけられている。
- 下記がライフサイクルの主な構成、および紐づいているゴールの機能。

| 順番 | フェーズ | 紐づく機能 |
|:--:|:--|:--|
| 1 | validate | プロジェクトが正しいかどうかを検証する。 |
| 2 | compile | ソースコードをコンパイルする。 |
| 3 | test | テストクラスを実行する。 |
| 4 | package | ソースコードをパッケージングする（jarなど）。 |
| 5 | verify | パッケージを検証し、基準を満たすかを検証する。 |
| 6 | install | ローカルリポジトリに作成したパッケージを格納する。 |
※上記とは独立したclean、siteというライフサイクルもある。

処理の実行
--

```sh:
mvn ゴールもしくはライフサイクル名（複数指定可能）
```
- 処理を実行する際は、上記の形でコマンドを利用する。
- ゴールを指定すると対応する処理のみが実行される。
- 一方、ライフサイクルを指定すると対象までのライフサイクルに紐づくすべての機能が実行される。たとえば、installライフサイクルを指定すると、validate～installのライフサイクルに紐づくすべての機能が実行される。

メモ
--
- ライフサイクルにゴールを紐づける場合は、executionタグを利用する。
- 各ゴールにはオプションを指定することができる。一般的には下記手順にて確認することができる。

　1. 下記プラグイン一覧より対象プラグインを選択
　2. 左サイドメニューよりGoals選択
　3. 対象ゴールをメインメニューより選択
　4. 表示されるOptional Parametersが各ゴールで指定できるオプション

- ゴールに対してオプションを指定したい場合は、configurationタグを利用する。定義場所は以下。
  - 個々のゴールに対して指定したい場合　→　executionタグ配下
  - 全てのゴールに対して指定したい場合　→　pluginタグ配下


プラグイン一覧
--
- [プラグイン一覧] (https://maven.apache.org/plugins/)

ライフサイクル
--
- [ライフサイクル] (https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)

リファレンス
--
- [POMリファレンス] (https://maven.apache.org/pom.html)
Protobuf.jsを使って.protoファイルからTypeScriptの型定義ファイルを生成する

## 概要

[Protobuf.jsを使って.protoファイルからNode.jsのgRPC clientコードを生成する](https://qiita.com/daikiojm/items/577d4f6675b298440ef6)では、javascriptのmessage定義とclient実装を自動生成しましたが、今回は、これらのjavascriptに対応する型定義ファイル(.d.ts)を自動生成してみたいと思います。


## 前提

[Protobuf.jsを使って.protoファイルからNode.jsのgRPC clientコードを生成する](https://qiita.com/daikiojm/items/577d4f6675b298440ef6))の [生成する](https://qiita.com/daikiojm/items/577d4f6675b298440ef6#%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B)までを手元で動作させていることが前提です。


## 型定義ファイルを生成する

次のコマンドを実行して型定義ファイルを生成する。

```bash
pbts \
--out ./hero_pb.d.ts \
./hero_pb.js
```

Protobuf.jsでは、.protoファイルから直接 `.d.ts` を生成するのではなく、 pbjsで生成したjsファイルをインプットとして `.d.ts` を生成するようになっています。


## 生成されるファイルの確認

- hero_pb.d.ts
    - hero_pb.jsに対する型定義ファイル


## 参考

- https://github.com/dcodeIO/ProtoBuf.js/
railsでDBのデータを一括で削除する裏技的なやつ

テーブルに入ってるコメントのデータを一括で消したいなーと思いながら
`Comment.find(ここはコメントのid).destroy`
でちまちま作業してる時にいい方法を発見したのでまとめてみる。

方法としては、**マイグレーションをやり直すだけ**でいい。
まず,

```:ターミナル
$ bundle exec rails db:migrate:down VERSION=20190329162955
```
で消したいデータが入ってるテーブルのマイグレーションを取り消す。VERSIONはマイグレーションファイルの作成日時を入力。

```:ターミナル
$ rails db:migrate:status
```
で、マイグレーション状況を確認。

```:ターミナル
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190325124958  Devise create users
   up     20190325135456  Create lectures
   up     20190325135509  Create circles
  down    20190329162955  Create comments
```
消したいマイグレーションファイルがdownになってればOK。

ここで、

```:ターミナル
$ bundle exec rails db:migrate:up VERSION=(downしたマイグレーションファイルと同じ)
```

これで、

```:ターミナル
Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190325124958  Devise create users
   up     20190325135456  Create lectures
   up     20190325135509  Create circles
   up     20190329162955  Create comments
```

upになってれば成功！

これでテーブルの中に入っていたデータが全部消せてる。

サンプルユーザーとか、投稿機能で試しに打ち込んだデータをまとめて消せるのですごく便利だなーーと感動。。。（正しい処理なのか不明だけど笑）

消えてるというよりは、カラムを一回外して、また別のとこに付け直してるイメージだから、繋がりが切れただけでデータ自体はデータベースに残ってるのかな？


このペースで開発頑張っていこう。


追記：この処理がダメなのか大丈夫なのか、どなたか助言していただけると幸いです。
分報を書けば書くほど英語力がメキメキ伸びていく話

# 背景

Slackの分報めっちゃ書く人になった

[Slackで「分報」を導入したらめっちゃ作業効率があがった](https://note.mu/reoleo/n/n102308f5b4e3)

このエネルギーを何かに使えないかと思い、自分の発言を英訳させてみると英語の勉強になるのではないかと思った

# 成果物

英訳してechoするSlack Botです

![スクリーンショット 2019-01-14 1.26.26.jpg](https://qiita-image-store.s3.amazonaws.com/0/79697/26104b6e-bff2-405c-0f65-8da002c8047d.jpeg)


# 実装

![image2019-1-14_12-54-7.png](https://qiita-image-store.s3.amazonaws.com/0/79697/279022c4-8da7-a9db-5a3c-e3829e1f44f4.png)

https://github.com/t-morisawa/slack-translate-bot

# 工夫したところ

日本語以外には反応しないようにした

# 苦労したところ

 - [Outgoing Webhooksのリクエストmime-typeがapplication/jsonじゃなかった事件](https://qiita.com/taumu/items/b72bd4393d5ca9dd7d2d)

 - Outgoing Webhooksが自分の発言を拾って無限ループ事件
   - 今回はマジックワード（☕️）を付与してループを回避

![image2019-1-14_13-35-51.png](https://qiita-image-store.s3.amazonaws.com/0/79697/f923a3bd-8b94-13b2-a40d-bc770541b962.png)

## PythonでのCloud Functionsの使用感

Outgoing Webhooksの仕様で、Cloud Functions側のレスポンスを `application/json` で返す必要がありましたが、 `json(dict)` をそのままreturnすることはできません。

Cloud Funtionsのリクエスト・レスポンスはFlaskのRequest・Response型をラッパしており、application/jsonでレスポンスする場合はこのあたりの理解が必要になります。

# 料金

## Cloud Translation

$20 / 100 万文字（翻訳元の文字数・マルチバイト文字も1文字扱い）
イメージしやすい値に変換すると、1日500ツイートすると月額1000円程度（1USD=109円、ツイートの文字数の平均を30とした場合）

## Cloud Functions

翻訳APIと比べるとほぼ無視できそう

# 今後の課題

実際に英語力が伸びたことを証明する OR このタイトルが景表法に抵触しないかどうかを調べる
お気に入りボタンの設置の設置(投稿のお気に入りを登録・解除できる)

# 実装イメージ
https://desolate-peak-43756.herokuapp.com/
適当に会員登録をして、ログインをしてください。

#github
https://github.com/a-itabashi/InstagramClone
ソースコードはこちらで確認してください。

# 環境
ruby 2.6.2
Rails 5.2.3
psql (PostgreSQL) 11.2

# テーブル構成(アソシエーション)の確認
![Untitled Diagram.png](https://qiita-image-store.s3.amazonaws.com/0/114933/2604302e-5a23-439d-0b66-ac831348f213.png)


※まずは、実装後のUIと上のER図を常に念頭に置く。

# モデルの定義
app/models/user.rb

```ruby
has_many :posts
has_many :favorites, dependent: :destroy
```  
* * *
app/models/favorite.rb     

```ruby
belongs_to :user
belongs_to :post
```
* * *
app/models/post.rb

```ruby
belongs_to :user
has_many   :favorites, dependent: :destroy
has_many   :favorite_users, through: :favorites, source: :user
```
throughオプションを使うことにより、今後、レコードの取得が容易になる。
今回は、任意のpost.idと一致するuserの情報を取得したいので、
favorite_usersメソッドを定義している。
※メソッド名は、自分で好き勝手につけて良いが、分かりやすい物を
※sources: :userのuserは、favoriteモデルで定義した、

```ruby
belongs_to :user
```
のuserに起因する。
* * *
config/routes.rb

```ruby:routes.rb
resources :users
resources :posts
resources :favorites, only:[:create, :destroy]
```
* * *
今回は、ブログの詳細ページ先(app/views/posts/show.html.erb)にお気に入りボタンを配置する。
※ヘルバーメソッドとして、current_user(ログイン中のユーザーを取得し、インスタンス変数：@current_userを返すメソッド)を定義している前提で進めます。

app/controllers/posts_controller.rb

```ruby:post_controller.rb
def show
  @favorite = current_user.favorites.find_by(post_id: @post.id)
  @favorites= @post.favorite_users
end
```
@favoriteでログイン中のユーザがお気に入りしている全投稿の中で、特定の投稿(post_id)を取得
@favoritesで特定の投稿に対して、お気に入りをしている全ユーザーを取得(先のthroughオプションで定義したメソッドを使用)

* * *

app/views/posts/show.html.erb

```ruby:posts/show.html.erb
<% unless @post.user_id == current_user.id %>
  <% if @favorite.present? %>
      <h2>この投稿のお気に入りを解除しますか？<h2>
      <div class="like-btn">
        <%= link_to "解除する", favorite_path(id: @favorite.id), method: :delete, class: "btn btn-danger" %>
      </div>
  <% else %>
      <h2>この投稿のお気に入りに登録しますか？<h2>
      <div class="like-btn">
        <%= link_to "登録をする", favorites_path(post_id: @post.id), method: :post, class:"btn btn-primary like-btn" %>
      </div>
  <% end %>
<% end %>
&nbsp
<h1>この投稿をお気に入りしたユーザー一覧</h1>
  <% @favorites.each do |favorite| %>
  <%= image_tag(favorite.user_image,class: "member-img") if favorite.user_image && favorite.user_image.url %>
     <%= favorite.name %>
  <% end %>
```
* * *

app/controllers/favorites_controller.rb

```ruby:favorites_controller.rb
class FavoritesController < ApplicationController
  def create
    favorite = current_user.favorites.create(post_id: params[:post_id])
    flash[:success] = "この投稿をお気に入りに登録しました"
    redirect_to post_path(favorite.post.id)
  end

  def destroy
    favorite = current_user.favorites.find_by(id: params[:id]).destroy
    flash[:danger] = "この投稿のお気に入りを解除しました"
    redirect_to post_path(favorite.post.id)
  end
end

```
コントローラーに渡すパラメーター(post_idなどの引数)を意識することが重要。
✖ Nuxt Fatal Error Error: Lock is already released

## 問題点
yarn buildで、以下のエラーが出た

```
 FATAL  Lock is already released                                                                                                                                          18:10:50

  at callback (node_modules/proper-lockfile/lib/lockfile.js:241:60)
  at Promise (node_modules/proper-lockfile/lib/adapter.js:39:9)
  at new Promise (<anonymous>)
  at args (node_modules/proper-lockfile/lib/adapter.js:30:25)
  at NuxtCommand.lockRelease [as _lockRelease] (node_modules/@nuxt/utils/dist/utils.js:139:11)
  at NuxtCommand.releaseLock (node_modules/@nuxt/cli/dist/cli-chunk.js:244:18)
  at NuxtCommand.run (node_modules/@nuxt/cli/dist/cli-chunk.js:159:18)
  at process._tickCallback (internal/process/next_tick.js:68:7)


   ╭─────────────────────────────────────╮
   │                                     │
   │   ✖ Nuxt Fatal Error                │
   │                                     │
   │   Error: Lock is already released   │
   │                                     │
   ╰─────────────────────────────────────╯

error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
```

## Nuxtのリポジトリでも問題になっているみたい

https://github.com/nuxt/nuxt.js/issues/5324

## 解決方法
```package.json
{
  "name": "noracorn-heroku-nuxt",
  "version": "1.0.0",
  "description": "My spectacular Nuxt.js project",
  "author": "noracorn",
  "private": true,
  "scripts": {
    "dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
    "build": "nuxt build --no-lock",  ←ここを変更 --no-lock
    "start": "HOST=0.0.0.0 PORT=8080 nuxt start",
    "generate": "nuxt generate"
  },
  "dependencies": {
    "@nuxtjs/axios": "^5.3.6",
    "cross-env": "^5.2.0",
    "express": "^4.16.4",
    "nuxt": "^2.4.0",
    "vuetify": "^1.5.8",
    "vuetify-loader": "^1.2.1"
  },
  "devDependencies": {
    "nodemon": "^1.18.9",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.2"
  }
}

```
【OpenSiv3D】規定のCSVファイルをOpenSiv3D対応のバイナリファイルとソースコードに変換するツールの紹介

#【はじめに】
OpenSiv3Dゲームやアプリを開発しているとき、外部ファイルでパラメータが定義されたファイルを用意して、プログラム中から読み込ませて使用するといったことはよくあると思いますが、
その外部ファイルがCSVファイルやテキストファイル管理のままだったりすると、実際にゲームやアプリを公開した時に中身がユーザから<b>丸見え</b>になってしまいます。(※OpenSSL等で暗号化することで丸見えは回避できますが、記事の趣旨から外れるので割愛します)
また、開発中でもCSVのカラム数が増減した時に一々ソースコードの中身をCSVと比較しながら読み込み順に気をつけて書いたり、CSVファイルの中に記述された文字列をプログラム内で使用している型へキャストしたりするのは面倒ではありませんか？

今回は、そんな問題を解消する、CSVの記述を元にシリアライズしたバイナリファイルとそのバイナリファイルに対応したソースコードを出力するツール(以下、<b>MasterDataMakerForOpenSiv3D</b>)を作ったので、紹介したいと思います。

#【想定している対象者】
* OpenSiv3Dでゲームやアプリを作っている方
* 現在外部データをCSVやテキストで管理をしていて(しようとしていて)、できれば公開するときにデータの丸見えは避けたい方
* 外部データ読み込み時のパフォーマンスを上げたい方

# 【OpenSiv3Dのバージョン】
Windows Desktop 0.3.1
※今後もサポートできる間はサポートしていきます。

#【ソースコードの在り処】
今回はコード量が多いので、[ここ](https://github.com/Militum/MasterDataMakerForOpenSiv3D)でソースコードを公開しています。
ライセンスは現状、<b>Mit License</b>としています。

# 【ライブラリ】
また、このツールで出力したソースコードは、
[こちら]
(https://gist.githubusercontent.com/Militum/117fd182c939e0ac0020fdfc96fb4eb9/raw/4a381988125c67fafa782a0bd7a0a5b4842175d4/MasterData.hpp)のソースコードをダウンロードし、プロジェクトに追加してください。

# 【ツールの説明】

##【CSVの構造について】
今回のツールで対応しているCSVの構造です。

* 1行目 カラム名(変数名、C++予約語禁止)
* 2行目 カラムの型名(ツールで対応している型は後述)
* 3行目以降 データ行(型に沿ったデータ)
となっているものを用意してください。

### 具体例
`Character.csv`

|id|name|hp|attack|
|:--:|:--:|:--:|:--:|
|uint32|string|int32|int32|
|1000|Siv3Dくん|100|20|
|1001|Siv3Dくん２|200|10|

##【ツールで変換に対応している型】

CSVの2行目に記述した型は下記のルールに則って変換されます。
下記に無い型を指定した場合は、ツールの実行に失敗します。

|CSV側の定義|シリアライズ時に変換される型|
|:--:|:--:|
|int|int32|
|int32|int32|
|int32_t|int32|
|int64|int64|
|int64_t|int64|
|uint|uint32|
|uint32|uint32|
|uint32_t|uint32|
|uint64|uint64|
|uint64_t|uint64|
|float|float|
|double|double|
|String|String|

##【Configファイルについて】
MasterDataMakerForOpenSiv3Dでは、下記5つのパラメータを外部設定することができます。

* 入力に使用するCSVのディレクトリ
* シリアライズしたバイナリファイルの出力先となるディレクトリ
* シリアライズしたバイナリファイルと対になるソースコードの出力先となるディレクトリ
* 出力するソースコードの名前空間
* 実際にゲームやアプリで読み込む際に指定するバイナリファイルが置かれているディレクトリ

#【今後の展望】
* 無効行やコメント行のサポートする
* Configファイルで設定できる内容を増やす(型の組み合わせ拡張)
* ID重複等、CSVの設定ミスを検出する
* エラーメッセージを親切にする

他にもこういった機能が欲しいといった意見は、ツールを改善する上でとても参考になりますので、コメント等いただけますと幸いです。

#【まとめ】
OpenSiv3D のゲームやアプリ開発で使用する<b>MasterDataMakerForOpenSiv3D</b>ツールを作成しました。
このツールを使用することで、開発でCSVを使用している際の手間を削減することが見込めますので、是非使ってみてください。

#【参考】

* [早い・簡単・便利な Config ファイルクラスを作る (C++/OpenSiv3D)](https://qiita.com/Reputeless/items/24701e9596ab9221c937)
ドキュメント制作が苦痛なので上手なドキュメント作成の方法をしらべた

## 書こうと思った理由
ドキュメントの制作が苦痛でしょうがないのでなんとか何事もなく早くドキュメンテーションを終わらせるために上手なドキュメントの制作に関して調べてみた。

## ドキュメント作成時に気をつけるポイント
- 必要な情報は余さず書く
    - ドキュメントを見ただけでは〇〇がわからなかったというなるべく質問がないように。
        - 例えば画面設計書なら画面イメージと項目名だけ書くのではなく、入力項目の種類（テキストボックス等）、属性（半角数字、全角文字）、入力必須・任意等、誰がなんの目的でこのドキュメントを見るのか考えつつ**必要な情報**を書く。
- 全体像を把握しやすいようにする
    - 詳細を書くのは大切だが同時に**全体像**もわかるようにする。 
        - ドキュメント冒頭になにが書いてあるのか（概要）を書く
        - 目次を書く
        - ページに見出しを書く
        - 一覧を書く（APIについて書くのであればAPI一覧を書く等）
- 必要なことがわかれば**簡素**でよい
    - ドキュメントに掛ける時間はなるべく小さいほうがよい。細かく書きすぎると時間がかかるのでどの程度の粒度まで書くのか最初に決める。
        - 対象者/必要スキルを定める（ドキュメントを読む際に前提となるスキルについて簡単でも良いので書いておく等）
- その会社が過去のプロジェクトで作ったドキュメントがあるなら参考にする。でもあらかじめスタイルが決まっているのでない限り、全く同じように書く必要はない（はず。）

### ドキュメントの種類
大体以下のような種類がある。

1. 設計書、仕様書
1. 計画書
2. 提案書
3. 手順書、ユーザーマニュアル
4. 報告書 

このうちエンジニアが書くのは大抵1.の「設計書」（基本設計書・詳細設計書）。仕様書を書いたり、社内向けに手順書を書いたりする場合や、まれにユーザーマニュアルを書く場合もある。

## ドキュメント（仕様書）の例
### QiitaのAPI仕様書
QiitaのAPI仕様書が[これ](https://qiita.com/api/v2/docs)。
### これに対する指摘
[この記事](https://qiita.com/tag1216/items/60e8d760fd1cb5366ee8)で指摘されているQiitaのAPI仕様書に対する指摘。以下にこの指摘を引用。

- API一覧がない
    - 初めて見た時にどんなことができるのかが最後まで読まないとわからない
    - APIの詳細を見たい時に素早く参照することができない
- Qiita:Team用APIも混在して書かれている
    - いきなり「グループ」「プロジェクト」という単語が出てくるので「Qiitaにこんなのあったっけ？」ってなる
- 認証状態(未認証/認証済)によって使えるAPIの違いがわからない
    - なんとなく予想はできるけど、詳細を見ても明記されていない

### 修正後
上記指摘をした人が修正した仕様書が[こちら](https://qiita.com/tag1216/items/b0b90e30c7e581aa2b00)。以下に「各セクションの意図」を引用。

- Qiita APIとは
    - 対象を簡潔に説明することで、初めての人でも理解しやすくする
- 認証状態とユーザータイプによる違い
    - 使えるAPIが違うことを説明
    - この後の一覧でグルーピングの意味がわかるようにする
- 認証認可
- モデル一覧
- API一覧
    - 全機能が一望できるようにする
    - 目次として機能するようにリンクにする
    - 興味のないAPIを読み飛ばせるようにグルーピング

## 個人的な経験から
- データアクセス、あるいはSQL設計書というようなデータIOに関する部分は書くのに時間が掛かる。
    - SQLをほとんどそのまま書くような形になってしまうのは避けること
        - SQLほとんどそのままだと書くのにも読むのにも時間が掛かるため
- 仕様が根本から変わるような仕様変更があると、そのたびに設計書等のドキュメントが書き直しになってしまう。
    - ウォーターフォールで進めるなら要件定義フェイズでちゃんと仕様を決めておくこと。
    - アジャイルで進めるなら複数回仕様変更が入ることが予想されるが、だからといってその度にいわゆる「中間成果物としてのドキュメント」を大幅に書き直すのでは大きな手戻りになり大きな時間のロスにつながる。どのようなドキュメントをどのような粒度でどのような目的で書くのかきちんと考えておく。
webpackを使ってhtmlをテンプレートとして利用する

サイトをhtmlで作るときに
ヘッダー、フッター等の共通するパーツを
ぺージごとに静的に埋め込むのがめんどくさい…

と思いhtmlのままでテンプレートとして使う方法がないか調べて実際に導入した方法です。

#実行環境
webpack 4.28.2

#使用したパッケージ
HTML Loader
https://github.com/webpack-contrib/html-loader
※今回はインストールしたhtml-loaderのバージョンは^0.5.5です。

#インストール
`npm i -D html-loader`

#ソース
##ディレクトリ
root/
┗ src/
　┣ template/
　┃　┗ header.html
　index.html

##テンプレートとして扱うファイル

```html:header.html
<header>
	<nav>
		<ul>
			<li>menu1</li>
			<li>menu2</li>
			<li>menu3</li>
		</ul>
	</nav>
</header>
```

##テンプレートを読み込むファイル

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
<%= require('html-loader!./template/header.html') %>
<main>
	<p>メインコンテンツ</p>
</main>
</body>
</html>
```
`<%= require('html-loader!`以降のパスはファイルごとに調整してください。

これだけでwebpackの`mode`が`develop`のときでも`production`でも
`header.html`の内容を`index.html`に読み込むことができました！
webpack環境でhtmlサイトを作成する際には
共通部分を気軽に扱えるので積極的に取り入れたい方法だと感じました。