Kawaii Lab

プログラミングとかサービス開発とか

スリープしてもSSHしているサーバーとのセッションが切れないようにする設定

Code

Host *
  ServerAliveInterval 60
  ControlMaster  auto
  ControlPath    /tmp/%r@%h:%p

解説

ServerAliveInterval

設定したsec毎にサーバーに対してリクエストを送り続けてセッションを維持する 会社支給のPCの場合、短時間でスリープさせられるのでセッションが切れることを恐れてトイレを我慢する必要がなくなる

ControlMaster

セッションを集約する。
ターミナルでとりあえず繋いでおけば、VScodeのターミナルでファイル転送するときにパスワード入力しなくても住むようになる。
ちなみにrsyncではリモート先のパスもTABで予測変換できるが、これを設定しておかないとTABおす毎にパスワード聞かれるので切れそうになる。

GASで文字列を置換、整形し出力する

概要

Googleスプレッドシート便利ですよね。 でもテストデータを作るときに繋げる単語をカラム毎にわけて、Join()でつなげる作業が辛くなってきたので要素だけ放り込んで出力するスクリプトを書きました。

コード

簡単に言うと、B列に書かれた文字列をresoceStatementに入れられた文字列と結合させて、同じ行のC列に出力します。 重複するデータは削除するのでいちいちGrepしなくていいので楽チンです。

まあリソースの重複削除しちゃってるので、そこは作業用シートにコピーして作業したほうがやったほうがいいかも。

function main() {
  const activeSheet = SpreadsheetApp.getActiveSheet();

  // 重複データの削除
  removeDupllicateRow(activeSheet,'B:B');
  
  // 置換文字列の設定
  const resoceStatement = "this is :'beforeReplaceKey'";
  
  // データセット
  const keyValues = activeSheet.getRange('B:B').getValues();
  getExistDataList(keyValues).forEach(function(key, index) {
    write(activeSheet, getStatement(resoceStatement, "beforeReplaceKey", key), index, 3);
  })
}

// 重複行を削除する
// targetSheet: 対象のシート
// range: 範囲
function removeDupllicateRow(targetSheet, range) {
  targetSheet.getRange(range).removeDuplicates();
}

// 値が存在するカラムのみ抽出する
// rowDataList: 範囲データが入った配列
function getExistDataList(rowDataList) {
  const list = new Array();
  rowDataList.forEach(function(value){
    if(value != null && value != "") {
      list.push(value);
    }});
  
  return list
}

// 文字列を置換する
// resorceString: 対象文字列
// beforeString: 置換前文字列
// afterString: 置換後文字列
function getStatement(resorceString, beforeString, afterString) {
   const reg = new RegExp(beforeString, "g");
   return resorceString.replace(reg, afterString);
}

// 値を書き込む
// targetSheet:対象のシート
// changeValue: 書き込む値
// rowIndex: 列番号
// columnIndex: 行番号
function write(targetSheet, changeValue, rowIndex, columnIndex) {
      targetSheet.getRange(rowIndex+1, columnIndex).setValue(changeValue);
}

PRを出すときに個人的に気をつけていること

はじめに

PRの内容は原則ステークホルダー(e.g. :PO、ユーザー)に向けて見せることを意識した構成にしましょう。
レビュワー(もしくは未来のコミッター)はPRを見たときに知りたいことは、コードの流れや処理ではなく背景や実現したいことのはずです。
達成したことを簡潔に、まとまっていて、コードに理解がない人でも分かるように説明する時、その場にはステークホルダーがいるはずですから意識しやすくなるでしょう。

次の項目からは個人的にPRに含めたほうがいい内容と、何故そう思うのかを残しておきます。

WHY(何故)

PRには必ず出すことになった背景や原因があるはずです。
もしこれがPRに書かれていなければ、レビュワーは把握するために関連するJiraやesaなどを探し回ることになるでしょう。
また、レビュワーはプランニングの時の他者の内容まで全て記憶している訳ではないので、認識齟齬を起こす可能性もあると思います。
レビュワーの行動はPR内で完結するように心がけましょう。

WHAT(目的)

PRで達成したい目的を記述します。 レビュワーは目的を認識することで、達成するためのプロセスを考え、もしかしたらコミッターでは思いつかない解決方法を提案してくれるかもしれません。
また、レビュワーは目的から逆算し正しく要件に対して担保されているかを考えると思うので、認知できていない達成するべきことに対してはレビューができません。明文化しておきましょう。

QA(担保)

PRでは要件に対し最善となる解決手段であるか、要件に対して担保されているか、事業ロードマップと見比べて拡張性があるか等について討論すべきです。
UTが通っているか、バグが発生していないか(論外!)についてレビュワーは意識すべきではありません。もし常に低次元的な問題と常に向き合わなければならない状況が続けばコードレビューに対して消極的になっていくでしょう。 レビュワーが気にしなくてもいいように、UTやITは事前に実施し担保されていることを教えて安心させてあげましょう。もしかしたら、ユーズケースが足りないなどの指摘が発生するかもしれませんが受け入れ条件に対しての討論になるので有意義だと思っています。

(ITを貼るときは他者が再現できるようにしておいてください。これは切実な願いです。)

Appendix

レビュワーはあなたとは違う人間ですから、異なる観点でレビューを行いたいと思うかもしれません。
上記のケースの場合、貴方が認知していない領域の情報が必要になりますから、PRに関する情報だけど他の項目に書くほどでもない理由はここに書いておきましょう。
それはきっとレビュワーがレビューするための大切な助けになるはずです。

健全なスクラムチームを目指すための大事なこと

コミットメントを宣言することができる

  • ストーリーの背景を理解し、ACの適切な設定ができること
  • ACを満たすまでのプロセスをイメージすることができ、チームの基準を参考にポイントを算出できること
  • プランニングでホワイトボードなどを使ってプロセスを説明できること(分からなそうであればメンバーが補完する)

曖昧さを持つストーリーを取ることができる

  • 曖昧な要素を持つストーリーであることをプランニングの時点でチームと共有する手段が存在すること
  • 調査タスクを加味したポイントを設定すること(膨れ上がる前提でプランニングをする)
  • POと認識を共有して、ACを随時相談し変更できる環境にしておくこと(ストーリー分割できるようにしておくこと)
  • チームのWAを定めておくこと(なるべく曖昧さを排除しておく)

新しいスキルを必要とするストーリーを取ることができる

  • サポーター(レビュワー)を設定し、担当者が相談できるということを自明にしておくこと
  • 担当者が疑問を気軽に投下できるようなチャットルームを用意しておくこと(雑談系統が望ましい)
  • 初めてのストーリーはキャッチアップストーリーであること
  • 常に一つのストーリーのみを担当すること

自分のキャリアビジョンを晒す

タイムラインでキャリアビジョンを公開しているのを見ました。 私もそろそろ転職活動を決めないといけない時期にきているのでここで整理しておきます。

興味

ユーザーが本当にやるべきことに対して集中して価値を出せるプラットフォームを作りたい。

既存のワークフローは、旧来のアナログなやり方にとって最適化されているので、一部を改善しただけではワークフローが上手く稼働せずユーザーにむしろ負担をかけてしまう。 時と場合によっては改善する為に導入したサービスすら導入を撤廃し、工数と費用を消費しただけになってしまう。

私は上記のような不幸な出来事を無くしていきたいと思っていて、これを解決する為にはワークフローの一部だけではなく前後全ての問題を解決するプラットフォームが必要だと考えている。 つまり、一つのサービスだけではなく横軸で複数のサービスを展開していくことで会社基盤、あるいは社会基盤そのものを一つのプラットフォームとして提供する世界感を実現したい。

原動力

プライベートを充実させる

私にとってプライベートとは家族との時間、イラストで自己表現をする時間、プログラミングをして自己成長をすること全てを指している。
上記の時間を削って事業に対してコミットすることは考えられない。プライベートで活動した結果、事業の成長に繋がることはあったとしても。

改善サイクルを回す

複数の事業が含まれているが、一貫して既存の問題に対して解決し改善するという意識が必要である。 上記の点において、私と相性がいい領域は自ずと絞られきており、何より既存の問題を発見し、改善して、次の問題に対してNext Actionを組み立てることが純粋に楽しく、プラットフォームもよりよくなっていくのでWinWinだと思っている

可能性を知る

私は既存のプロセスを組み立てて、達成するということがとても好きです。 技術領域に置いて言えば、言語、設計、チーム等、無数の組み合わせられるプロセスがあり、これらを理解して学んでいくことは楽しい。

分からないことが怖く、そこに飛び込んでしまうことに対して萎縮しまいがちなところがあるが、そこを理解してくれるエンジニアという職種の人たちがいるからこそ飛び込んでいけるし、最近は楽しくすら感じている自分がいる。

成長像

テックリード

ある要件に対して、最適な技術を選択できるような技術者になりたいと思っている。

ここでの要件とは1機能の単位ではなく、サービス全体を指している。 要件にとって最適な技術を選択する為には、インフラ、サーバーサイド、クライアントサイド全領域の知識が広く必要だと思っているので各アーキテクチャの強みと弱みを理解できるレベルになりたい。

一つの領域に強く特化していきたいとは今のところ考えていないので、積極的にキャッチアップしていきたいとは思っているが、場合に応じてメンバーと上手く分業していきたいと思っている。

技術へは関わっていきたい

私は技術自体が好きだし、技術を使って既存の問題を解決していきたいと思っているので、技術に対して理解がないプロダクトオーナーや事業部長になるつもりはない。 私自身の考えとして、サービスの内部をコードレベルまで理解し、責任を持つことでユーザに対して自信を持って提供していきたいと考えている。

CodilityのLesson2をGoで解いてみた(続き)

概要

オンラインコーディングの試験であるCodilityのLesson2を自分なりに解いてみました。(続き) CyclicRotation coding task - Learn to Code - Codility

前提

以下の条件で配列が生成される

  • 要素: N個
  • シフト数: K回
  • 要素は配列の終端に達した後、シフトすると先頭に移動する

func Solution(A []int, K int) []int は 配列を取得すると、K回シフトさせた配列を返します。

アルゴリズムを組み立てる際の情報

  • NとKの範囲は[0..100]
  • 要素の整数範囲は[−1,000..1,000]

Sample Data

data1

A = [3, 8, 9, 7, 6] K = 3

data2

A = [0, 0, 0] K = 1

data3

A = [1, 2, 3, 4] K = 4

Code

package main

import (
    "fmt"
)

func main() {
    // 問題文の仮定リスト
    intList := []int{3, 8, 9, 7, 6}
    fmt.Println(`before:`, intList)
    fmt.Println(`rotated:`, Solution(intList, 3))
    fmt.Println(``)

    intList = []int{0, 0, 0}
    fmt.Println(`before:`, intList)
    fmt.Println(`rotated:`, Solution(intList, 1))
        fmt.Println(``)

    intList = []int{1, 2, 3, 4}
    fmt.Println(`before:`, intList)
    fmt.Println(`rotated:`, Solution(intList, 4))
    fmt.Println(``)

}

// Solution の概要
// arg1: A []int [−1,000..1,000]の範囲の値をもつ[0..100]の要素数で構成された配列
// arg2: K int [0..100]の範囲をもつ数値
// return: arg1 を arg2 右側にシフトさせた配列
func Solution(A []int, K int) []int {
    // 要素数が0,もしくは1の場合シフトさせても結果が変わらないので
    // 早期リターンする
    if len(A) == 0 {
        return A
    } else if len(A) == 1 {
        return A
    }

    // 取り出した数値を確保する領域
    var popInt = 0

    // K回分要素を右にシフトさせる
    // 厳密には要素を取り出して、取り出す前の要素と取り出した要素を結合する
    for index := 0; index < K; index++ {
        // 終端から要素を取り出す
        popInt = A[len(A)-1]
        
        // 終端を取り除いた要素を作成
        A = A[:len(A)-1]

        // 要素を先頭に追加した配列を結合して作成
        A = append([]int{popInt}, A...)
    }

    return A
}
結果

before: [3 8 9 7 6]
rotated: [9 7 6 3 8]

before: [0 0 0]
rotated: [0 0 0]

before: [1 2 3 4]
rotated: [1 2 3 4]

解説

あまり書くことがありませんが、強いて言えば論理演算子を使わないことですかね。
論理演算子を使うと、頭の中でパターンを想定しなければなりませんが条件式が一つの時と比べて 考えることが多くなりバグを生む可能性が高くなります。

しょうもないヒューマンエラーを生んで悩む可能性を孕むよりは、多少の美しさは捨てるべきだと思っています。
美しさ = 可読性ではないですからね。

CodilityのLesson2をGoで解いてみた

概要

オンラインコーディングの試験であるCodilityのLesson2を自分なりに解いてみました。 https://app.codility.com/programmers/lessons/2-arrays/odd_occurrences_in_array/

問題の要約

以下の条件で配列が生成される

  • 要素: N個
  • 空ではない
  • 値は必ず奇数
  • 同じ値はペアとして扱う

func Solution(A []int) int は 配列を取得するとペアではない値を返します

アルゴリズムを組み立てる際の情報

  • Nの範囲は[1..1,000,000]
  • 値の範囲は[1..1,000,000,000]
  • 一つを除く全ての値が偶数回発生する(ペアになる)

Sample Data

[9,3,9,3,9,7,9]

コード

package main

import (
 "fmt"
 "os"
)

func main() {
 // 問題文の仮定リスト
 intList := []int{9, 3, 9, 3, 9, 7, 9}

 fmt.Println(`Solo Number:`, Solution(intList))

}

// Solution はN個の要素数と奇数値のみで構成されたInt型の配列を受け取る
// 値の中でペアになっていない値を返却する
func Solution(A []int) int {

 // 配列が空の場合終了
 if len(A) == 0 {
  fmt.Println("Not Include Items in Array")
  os.Exit(1)
 }

 // 重複判別用のmapを作成
 mapForDecidePear := make(map[int]int)

 // 重複した分の数をValueにsetしていく
 // 要素が偶数の場合異常な値として処理
 for _, val := range A {
  if val%2 == 0 {
   fmt.Println("Include Even Number in Array")
   os.Exit(1)
   break
  }

  mapForDecidePear[val] = mapForDecidePear[val] + 1
 }

 // 重複していない要素はValueが1なのでそれを取り出す
 // 重複していない要素は一つしかないので見つかり次第抜けだす
 var soloValue = 0
 for key, val := range mapForDecidePear {
  if val == 1 {
   soloValue = key
   break
  }
 }

 return soloValue
}
結果

Solo Number: 7

解説

重複していない要素を判別する方法として,以下の方法も考えられました

  • 配列に{key,value}の構造体を格納する
  • 配列をsort module を使ってオブジェクトのvalueの順番で並び替える
  • 配列から先頭を取り出して返す

ただ、今回こちらの方法を取ったのは以下の理由になります。

  • 配列を回す回数は変わらないが、sortの中で匿名関数を使う必要があるため、複雑になってしまうこと
  • 構造体を定義する必要がないこと

結論n+1問題を回避すればいいと思うので、特段問題ないと思います。