- 投稿日:2020-10-20T22:08:10+09:00
[day: 3]小さな効率化とリーダブルコード
小さな効率化とリーダブルコード
はじめに
2020/4/1にエンジニアになりました。
scala/Play、TypeScript/Angular
ほぼ日記みたいな内容です。
毎日の学習のアウトプットが目的です。小さな効率化
小さいですが、積み重なると大きい効率化をしました。
それはHotKeyを利用してiTerm2を開くことです。
今までは別の画面からiTerm2を開くときにはcommand + tab
を使って切り替えてました。
キーボードのホームポジションから大きく左手がずれてしまうのと、タブでの選択を間違えてしまうと大きく時間をロスしてしまいます。
ショートカットでHotKeyを設定すると一瞬で今いる画面の上に被さる形でiTerm2を表示できるので、調べ物から開発に切り替える際の動きが格段に早くなりました。
自分はoption + enter
で設定しています。
おすすめなので皆さんも試して見てはいかがでしょうか。参考にした記事
iTerm2のおすすめ設定〜ターミナル作業を効率化する〜リーダブルコード
リーダブルコードを読みましたので、簡単にまとめたいと思います。
リーダブルコード――より良いコードを書くためのシンプルで実践的なテクニック1章 理解しやすいコード
- コードは他人にとって理解しやすく書く
- コードは他人が最短時間で理解できるように書く
- 理解する時間が短い > コードが短い
- このコードは見やすいか確認する
2章 名前位に情報を詰め込む
- 名前に情報を詰め込む
- 名前は小さなコメントである
- 明確な単語を選ぶ
- 適格な意味を持つ単語を選択する
- シソーラスで検索して調べる
- 気取った言い回しよりも正確で明確な単語を選ぶ
- 汎用的な名前を避ける 例)tmpやretval
- 情報の保存期間が一瞬であれば汎用的で良い
- 抽象的な名前よりも具体的な名前を使う
- 変数名が抽象的だと使用者によって解釈が異なる
- 何をするのか明確にわかる名前をつける
- 名前に情報を追加する
- 絶対に伝えたい情報は名前に入れる
- 単位など
- 名前の長さを決める
- 名前は長すぎないようにする
- スコープの範囲が短い場合には短くても良い
- 理解しにくい省略形の名前はつけない
- 名前のフォーマットで情報を伝える
- クラスや変数で使用するフォーマットを変えると読みやすくなる
- プロジェクトでの一貫性が大事
3章 誤解されない名前
- 他人が違う意味に誤解しないか確認する
- 否定形を避ける
4章 美しさ
- 優れたコードは目に優しいものである
- 似ているコードは似ているように書く
- インデントを揃えて縦の線を真っ直ぐにする
- コードを段落に落とし込む
5章 コメントすべきことを知る
- コメントの目的は書き手の意図を読み手に知らせることである
- コメントを読んだ方が理解がはやか?
- 優れたコード > ひどいコード+コメント
- 変数名を変えることでコメントが不要にならないか考える
- プログラマーが使う典型的な意味 -TODO:後で手をつける
- FIXME:既知の不具合があるコード
- HACK:あまりキレイじゃない解決法
- XXX:危険!大きな問題がある
- 質問されそうな箇所を考える
- 新しく入ったメンバーが理解に時間がかかる箇所などを考える
- 巨大な関数の流れをコメントで把握できるようにする
6章 コメントは正確で簡潔に
- コメントは簡潔に
- 曖昧な代名詞を避ける
- 小さな領域に情報を詰め込む
7章 制御フローを読みやすくする
- 条件式の引数の並び順
- 左;変化する、右;変化しない
- if文の記述
- 肯定系を優先して使う
- 単純な処理を先に書く
- 目立たせたい処理を先に書く
- ネストを浅くする
8章 巨大な式を分解する
- 説明変数:式の意味を説明する
- 要約変数:式の内容を小さく分割できる、その式の内容を要約している
9章 変数と読みやすさ
- 不要な変数を削除する
- 変数が減るとコードは簡潔になる
- 本当にその変数が必要か確認する
- 変数のコードを縮める
- グローバルな変数は削除する
10章 無関係な下位問題を抽出する
- 汎用的なコードを作成する
- 高レベルの解決に集中する
- 下位問題は分解して抽出する
11章 1度に一つのことを
- 2つ以上のことを行っているコードは分解する
- ヘルパーメソッドを利用する
- ヘルパーメソッドとは他の関数に依存することなくある特定の処理を行うメソッド
12章 コードに思いを込める
- 簡単にわかりやすく説明できなければ理解したとは言えない
- おばあちゃんにも理解できるように説明できますか?
- コードの動作を同僚に簡単な言葉で説明してみる
- 説明の中で使用したキーワードやフレーズに注目する
- その説明に合わせてコードを書く
13章 短いコードを書く
- ライブラリが何を提供しているのかを知る
- 普段使用しているライブラリの提供しているものを定期的にじっくり見てみる
- 標準ライブラリで解決できる問題があることがある
- 今書いているそれらのコードは本当に必要か?
- 1日にエンジニアが出荷するコードは10行である
- 不要な機能はプロダクトから削除する
- メモリの消費を抑える
- 過剰な機能はもたせない
- 最も簡単に問題を解決する方法を考える
最後に
- 実際にやる
- 当たり前にする
- コードでつたる
毎日投稿について
- 完全な自己満足
- アウトプットの習慣づけ
- インプットした内容の記憶の定着を促進
- 継続 > クオリティ
- 昨日の自分より成長している実感を得る
- 投稿日:2020-10-20T18:50:26+09:00
PDF(SBI証券、くりっく株365、取引残高報告書)からCSV(テキスト)を作成する
はじめに
世界の株価指数に投資することが出来る金融商品として、
くりっく株365があります。上場CFD(東京金融取引所に上場する株価指数証拠金取引)ですが、
個人だと申告分離課税、
法人だと法人税と、
確定申告をしなければなりません。年1回、取引残高報告書に基づいて申告する
のですが、
SBI証券の場合、PDFなのですよ。これを手作業で集計するのが面倒なので、
PDF、取引残高報告書のうち(2頁〜)証拠金入出金明細書を
CSV(テキスト)にします。これを会計ソフトと税務ソフト(eTaxの①預貯金)反映させることを目的としています。
注意点
テスト不足です。
・複数頁にまたがる場合は、どうだろう。。
・未使用と思われる列にデータがあると、誤動作するでしょう。
想定PDF
7列の表ですが、
摘要(3列)と備考(7列)にはデータが無いと想定しています。
使い方
使い方.Rsource( "PDF_CFD_SBI.R" ) # PDFのあるディレクトリーを指定 d <- file.path( ... ,"B_0988_SBI証券" ,"CFD" ) 出入 <- CFD.main( d )PDF_CFD_SBI.R# pdfデータをインポートするため library( pdftools ) # install.packages( 'pdftools' ) CFD.main <- function( d ) { print( d ) CFD <- CFD.init() # ファイル別 files <- dir( d ,pattern=".pdf$" ,ignore.case=T ) for( f in files) { p <- pdf_info( file.path( d ,f ) )$pages df <- pdf_data( file.path( d ,f ) ) print( c( f , p ) ) CFD <- rbind( CFD ,CFD.pdf( df ,p ) ) } return( CFD.fin( CFD ) ) } print( c( "CFD.main()" ,CFD.main ) ) CFD.pdf <- function( df ,p ) { CFD <- CFD.init() # PDF別 for( i in 1:p ) { # i <- 2 print( i ) df_p <- sapply( df[[ i ]] ,"[" ) [ ,c("x","y","text") ] x <- as.integer( df_p[ ,"x" ] ) y <- as.integer( df_p[ ,"y" ] ) h1 <- subset( df_p ,df_p[,"text"] == "証拠金入出金明細書" ) h1_y <- as.integer( h1[,"y"] ) if ( nrow( h1 ) == 0 ) next print( h1 ) h2 <- subset( df_p ,df_p[,"text"] == "受渡日" ) h2_y <- as.integer( h2[,"y"] ) m <- df_p[ y > h2_y , ] r <- subset( m, m[ ,"x"] == 25 ) CFD <- CFD.line( m ,r ) } return( CFD ) } print( c( "CFD.pdf()" ,CFD.pdf ) ) CFD.line <- function( m ,r ) { CFD <- CFD.init() for( j in 1:nrow( r ) ) { CFD[ j ,1 ] <- r[ j,"text"] 行 <- subset( m ,m[ ,"y" ]==r[ j , "y" ] ) CFD[ j ,2 ] <- 行[ 2,"text"] if( as.integer( 行[ 3,"x"] ) <= 488 ) { CFD[ j ,4 ] <- 行[ 3,"text"] } else { CFD[ j ,5 ] <- 行[ 3,"text"] } CFD[ j ,6 ] <- 行[ 4,"text"] # 想定外かも? switch( ( nrow( 行 ) - 4 ) ,"1" = { print( 行 ) } ) } return( CFD ) } print( c( "CFD.line()" ,CFD.line ) ) CFD.fin <- function( 出入 ) { 出入[ ,1] <- gsub( "/" ,"-" ,出入[ ,1] ) 出入[ ,4] <- as.integer( gsub( "," ,"" ,出入[ ,4] ) ) 出入[ ,5] <- as.integer( gsub( "," ,"" ,出入[ ,5] ) ) 出入[ ,6] <- as.integer( gsub( "," ,"" ,出入[ ,6] ) ) return( 出入 ) } print( c( "CFD.fin()" ,CFD.fin ) ) CFD.init <- function( n=1 ) { # 列数 df <- data.frame( matrix( NA ,0 ,7 ) ) # 列名 colnames( df ) <- c( "受渡日=" # 列1 ,"区分=" # 列2 ,"摘要=" # 列3 ,"証拠金の減少=" #,"証拠金の減少(円)=" # 列4 ,"証拠金の増加=" #,"証拠金の残高(円)=" # 列5 ,"証拠金の残高=" #,"証拠金の残高(円)=" # 列6 ,"備考=" # 列7 ) switch( n , "1" = { # (2頁〜)証拠金入出金明細書 # print( sapply( df ,mode ) ) } ) return( df ) } print( c( "CFD.init()" ,CFD.init ) ) #
- 投稿日:2020-10-20T16:11:20+09:00
コマンドラインから日本化粧品工業連合会の成分表示名称リスト検索するのに使ったツールたち。
コマンドラインから日本化粧品工業連合会の成分表示名称リスト検索するのに使ったツールたち。
化粧品の輸入をする場合INCI名で書かれた成分リストを日本語のものに変換する作業が絶対に必要になる。日本化粧品工業連合会のWEBで検索してポチポチとやっていたのだが、めんどくさくなったのでコマンドライン から作業した時の記録。
前提条件
- mac
- zsh
- xmllint
- sed
- mktemp
作ったfunction
- chochodo_search_from_jcia [SEACH_WORDS]: 緩やかな検索用(xml取得)
- chochodo_search_from_jcia_by_inci [INCI_NAME]: スタティックな検索用(xml取得)
- chochodo_get_data_by_inci [INCI_NAME]: INCI名から「INCI名,表示名称,No,INCI名(検索結果)」のカンマ区切りを得る
- chochodo_trim [STRING]: 前後のトリム(って言わないの?)
- chochodo_get_inci_csv [FILE_PATH] : INCI名のリスト(1行に1INCI名が入ったテキストファイル)を順に検索していって、INCI名と表示名称の入ったcsvを出力する
ファイルへの書き込みはchochodo_get_inci_csv 中でmktempを使った場所のみなので心が苦しくならない。
function chochodo_search_from_jcia(){ if test -z $1 ; then echo "usage : chochodo_search_from_jcia [SEARCH_WORDS]" echo "ex) chochodo_search_from_jcia BG" return fi ( PHPSESSID=$(curl 'https://www.jcia.org/user/business/ingredients/search' \ -H 'Connection: keep-alive' \ -H 'Accept: */*' \ -H 'X-Requested-With: XMLHttpRequest' \ -H 'sec-ch-ua-mobile: ?0' \ -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \ -H 'Origin: https://www.jcia.org' \ -H 'Sec-Fetch-Site: same-origin' \ -H 'Sec-Fetch-Mode: cors' \ -H 'Sec-Fetch-Dest: empty' \ -H 'Referer: https://www.jcia.org/user/business/ingredients/namelist' \ -H 'Accept-Language: ja,en-US;q=0.9,en;q=0.8' \ --data-raw 'search%5Bfreeword%5D='"$1" \ --compressed -i | grep 'Set-Cookie: PHPSESSID=' | cut -d '=' -f2 | cut -d ';' -f1) curl 'https://www.jcia.org/user/business/ingredients/list/page/0' \ -H 'Connection: keep-alive' \ -H 'Accept: text/plain, */*; q=0.01' \ -H 'sec-ch-ua-mobile: ?0' \ -H 'X-Requested-With: XMLHttpRequest' \ -H 'Sec-Fetch-Site: same-origin' \ -H 'Sec-Fetch-Mode: cors' \ -H 'Sec-Fetch-Dest: empty' \ -H 'Referer: https://www.jcia.org/user/business/ingredients/namelist' \ -H 'Accept-Language: ja,en-US;q=0.9,en;q=0.8' \ -H 'Cookie: PHPSESSID='$PHPSESSID';' \ --compressed | xmllint --encode utf8 --noblanks - ) } function chochodo_search_from_jcia_by_inci(){ if test -z $1 ; then echo "usage : chochodo_search_from_jcia_by_inci [INCI_NAME]" echo "ex) chochodo_search_from_jcia_by_inci BG" return fi ( chochodo_search_from_jcia '@'"$1" ) } function chochodo_get_data_by_inci(){ ( INCI_NAME_FROM_FILE=$1 RESULT_XML=$(chochodo_search_from_jcia_by_inci $INCI_NAME_FROM_FILE) ROW=$(echo $RESULT_XML|xmllint --xpath '/return_data/rows/row[1]' - |xmllint --encode utf8 --noblanks -) NAME=$(chochodo_trim "$(echo $ROW|head -5| tail -1 )") NO=$(chochodo_trim "$(echo $ROW|head -3| tail -1 )") INCI_NAME=$(chochodo_trim "$(echo $ROW|head -7| tail -1 )") echo '"'$INCI_NAME_FROM_FILE'","'$NAME'","'$NO'","'$INCI_NAME'"' ) } function chochodo_trim(){ (echo $1|sed 's/^[[:blank:]]*//'|sed 's/[[:blank:]]*$//') } function chochodo_get_inci_csv(){ ( FILE_NAME=$1 CSV_FILE_NAME=$(mktemp) echo "INCI_NAME_FROM_FILE,NAME,NO,INCI_NAME" >$CSV_FILE_NAME while read INCI_NAME do echo $(chochodo_get_data_by_inci "$(trim $INCI_NAME)") >> $CSV_FILE_NAME done < $FILE_NAME cat $CSV_FILE_NAME rm $CSV_FILE_NAME ) }
- 投稿日:2020-10-20T13:18:39+09:00
brew install mtr macOS10.15
homebrewでmtrを導入したらパスが通っていなかったメモ
結論だけ知りたい方は、まとめ参照
homebrewでmtrをインストール
% brew install mtr | | ? /usr/local/Cellar/mtr/0.94 mtr requires root privileges so you will need to run `sudo mtr`. You should be certain that you trust any software you grant root privileges.8.8.8.8に向けてmtrを実行したが、mtrがないらしい
% sudo mtr 8.8.8.8 Password: sudo: mtr: command not foundパスを見てみると、/usr/local/Cellar/mtr/0.94らしい。
~ % brew link mtr Warning: Already linked: /usr/local/Cellar/mtr/0.94 To relink: brew unlink mtr && brew link mtr中身を見てみると、それっぽいのがない
% ls /usr/local/Cellar/mtr/0.94 AUTHORS INSTALL_RECEIPT.json README.md sbin COPYING NEWS TODO shareこっちにあった。
% ls /usr/local/Cellar/mtr/0.94/sbin mtr mtr-packetリンク作成①
% ln /usr/local/Cellar/mtr/0.94/sbin/mtr /usr/local/bin/mtr再度実行すると、mtr-packetもいるらしい
% sudo mtr 8.8.8.8 mtr: Failure to start mtr-packet: Invalid argumentリンク作成②
% ln /usr/local/Cellar/mtr/0.94/sbin/mtr-packet /usr/local/bin/mtr-packetもっかい実行、動いた
My traceroute [v0.94] xxxxx-MacBook-Pro.local (172.31.xxx.xxx) -> 8.8.8.8 2020-10-15T23:41:13+0900 Keys: Help Display mode Restart statistics Order of fields quit Packets Pings Host Loss% Snt Last Avg Best Wrst StDev 1. 172.31.xxx.xxx 0.0% 5 1.7 3.3 1.7 9.4 3.4 2. 10.255.xxx.xxx 0.0% 5 2.0 3.2 1.9 8.0 2.7 3. xxxxxxxxxxxxxxx.ppp-bb.dion.ne.jp 0.0% 5 4.2 3.8 3.4 4.2 0.3 4. xxxxxxxxxxxx.bb.kddi.ne.jp 0.0% 5 6.4 5.5 5.0 6.4 0.5 5. xxxxxxxxx.bb.kddi.ne.jp 0.0% 5 16.5 8.3 5.1 16.5 4.7 6. 27.85.xxx.xx 0.0% 5 9.3 9.8 7.1 17.1 4.2 7. 27.85.xxx.xx 0.0% 5 9.7 8.4 6.2 13.3 3.1 8. 72.14.xxx.xx 0.0% 5 7.1 9.5 6.2 13.9 3.5 9. 209.85.xxx.xx 0.0% 5 5.7 6.4 5.7 7.7 0.8 10. 72.14.xxx.xxx 0.0% 4 5.9 8.5 5.9 12.9 3.2 11. dns.google 0.0% 4 6.3 6.7 5.7 8.0 1.0まとめ
% brew install mtr % ln /usr/local/Cellar/mtr/0.94/sbin/mtr /usr/local/bin/mtr % ln /usr/local/Cellar/mtr/0.94/sbin/mtr-packet /usr/local/bin/mtr-packet以上
- 投稿日:2020-10-20T11:37:09+09:00
macでsshpassをインストールする
個人用メモ
# 普通に brew install sshpass # ダメでした # urlから brew install https://raw.githubusercontent.com/kadwanev/bigboybrew/master/Library/Formula/sshpass.rb #これもダメ brew install hudochenkov/sshpass/sshpass # めでたし
- 投稿日:2020-10-20T10:02:59+09:00
【Python】iterdir()など使用時に出る[Errno 20] Not a directory: '***/.DS_Store'
Pythonでiterdir()などを使うと、タイトルのようなエラーが出てきます。
Mac独自の.DS_Storeという隠しファイルのせいで、関数が実行できない時出てきます。
対処としては、.DS_Storeを消せば良いだけです。そもそも.DS_Storeとは
.DS_Store は、Finderがフォルダの設定を記録するためのファイルです。
参考サイト対処
ファインダーでもコマンドラインでもいいので消します。
コマンドラインの場合、
邪魔な.DS_Storeが入っているフォルダに移動しfind . -name ".DS_Store" -deleteで消します。
参考サイト終了です。