やる気がストロングZERO

やる気のストロングスタイル

【DB設計】データ複製して持ちたくないと思ってる理由

僕はデータを複製して持ちたくないとずっと思っているけど、 色んな意見聞いてると自分でもそれが本当に良い事なのかわからなくなりそうだったので、 なぜ複製が嫌いなのか書きながら考えを整理してみた。

  • データを複製すると不整合が起きるから嫌だ
  • 計算結果を持つのもデータ複製の一種と考えている
  • あるデータ、ある処理に変更を加えたときに「関連してこっちも変更しないといけない」というのをできるだけ意識したくない
  • 算出による処理速度が問題になる場合はキャッシュを使う
  • 複製して持つべきものもある
  • スナップショットも導出できるならするべき?
  • 外部サービス連携はデータ複製してもっているのでは?

データを複製すると不整合が起きるから嫌だ

ECショップシステムにて
「商品マスターデータ一覧から商品を選んで[販売する]ボタンを押すと、ECショップに商品が表示されて販売開始される」
のような機能があった時、以下のようなテーブル設計を考えてみる。

続きを読む

SSHポートフォワードメモ

ローカルポートフォワード

参考)

SSHポートフォワーディングを知った話 - Qiita

serverAからしかアクセス出来ないserverBにあるhttpコンテンツをlocalからみたい場合

localマシンにて、

ssh serverA -L 8080:serverB:80 -N

と実行してから、localマシンのブラウザでlocalhost:8080とアクセスするとserverBのhttpコンテンツを見れる(ハズ)。

続きを読む

個人開発でも業務クオリティを目指すのが重要

今、個人開発で「俺が考える最強の契約管理システム」の作成作業をしている。
作成作業しながら「個人開発でも業務クオリティを目指すのが重要だな」と感じたのでその理由を書く。

個人開発は業務と違う方向で良い経験を詰める場であるが、いくらでも手を抜けてしまえるので、業務クオリティを目指すことで良い経験を積めるように仕向ける必要がある。

ちなみにこの作成作業はYouTubeで公開していて、作業リポジトリGitHubにある。

[YouTube]
www.youtube.com

[GitHub]
github.com

個人開発は得た知識を存分に試せる場所だ

なんで個人開発をするのか?

なぜなら業務での開発では、自分の思い通りに作業できない事が多いからだ。

これは組織の一員として開発を行うからには当然だ。
すべての責任を自分で負えるわけではないからだ。

しかし、僕にもいろいろ試したい設計や書き方や技術がある。
これらを試せる「誰にも邪魔されない環境」とは個人開発しかない。

「あのときレビューで反対された設計で実際に突き進んでいたらどうなったのか?」等、存分に試すのである。

手を抜いてしまうという個人開発の罠

個人開発は自由なので、いくらでも手を抜けてしまう。
「自分しか使わないし、ログイン機能はパスワード固定にしておいたら良いか」
「自分しか使わないし、httpsでなくてもいいか」
みたいな感じである。

業務だったらどんなめんどくさい実装も強烈なプレッシャーによってやらざるを得ない状況になり、それがスキルとして蓄積されていく。
そして大抵は面倒くさい事が必要なスキルだったり必要な機能なのである。

そういうものを避けて開発を行っても大したものは出来ない。

僕は今まで個人開発でいくつかのサービスやらツールやらを作った。

  • エロ動画リンク収集ボット
  • 集めたリンクでアフィリエイトサイトの構築
  • 芸能人に似たAV女優を探して紐付けるシステム
  • 株価をトラッキングしてある条件を検出したら教えてくれるシステム
  • twitterで特定のハッシュタグで投稿された画像リンクを収集するシステム
  • twitterで収集した画像リンクを一覧表示させるサイト
  • 持ち物リスト共有するサービス

これらは上記で言う手を抜いた個人開発で、動きはしているもののサービスとして低機能で完成度は低い。

しかし無意味だったかと言えばそうではなくて、お小遣い程度の稼ぎと、エンジニアとしての転職時には大いに役立った。

また、得られた一番大きなものとして、
「僕はサービスを完成させられる」という自信を得る事ができた。

この経験から「個人開発の目標」はその人のスキルによって目指すべき段階があると考えるようになった。

まずは「完成させること」を目指し、自信がついたら「クオリティ」を目指す

僕がそうだったのだが、まだ経験が浅く何かを作りきった事がないなら「完成させる事」を目標にする。
完成させる為に最短距離を行く。できるだけ機能は削ぎ落とす。

自分が完成させられるかもわからない状態で、細かい部分にこだわっていてもモチベーションが続かない。
完成に近づく事がモチベーションになる。

そうして「完成させられる自信」がついたら、次はクオリティを目指す。

業務で行うのと同レベルに妥協の無いものを作る。
実際に使えるものを作る。
高品質な機能が追加されることがモチベーションになる。

ただし、かけられる時間は少ないので機能は絞り込む。

業務でもなかなか出来ない経験を個人開発で得る

例えば「ログイン機能」だが、大抵の場合は既に実装されていて、なかなか自分で作ることって少ない。

なんとなく作り方は知っていても、実際に作るとなると「パスワードリセットはセキュリティ的にどのようにすればいいのか?」意外にに調べる事は多い。

「作り方を一応知っている」と「実際に実装したことがある」ではかなり違う。
こういう経験を個人開発でどんどん得ていく。

こんなセッションIDは嫌だ

ログイン周りってだいたい既に出来上がってて自分で実装したことなかった。
知識としてはなんとなく知ってたけど「俺が考える最強の契約管理システム」でもログイン機能つけないといけないなーと思ってセキュリティを含めて改めて勉強したのでメモ。

参考)まだ前半しか読んでないけど、説明が丁寧で読みやすくて、内容自体も面白いしおすすめです。

ログイン状態はセッションIDで管理してる

ログイン状態の保持は、ブラウザではcookieとsessionを使って実現してる。

A君がログインページでログイン認証が成功したら、サーバー側のsession情報にA君のuser_idを覚えさせる。

session_id data
1 user_id = 10 (A君のid)
2 user_id = 121(他の人のid)

そして、ブラウザのcookieにsession_id = 1を覚えさせる。

A君が自分のプロフィールページにアクセスするとき、ブラウザはcookieをサーバーへ送出する。

ブラウザは受け取ったcookieの中からsession_id = 1を見つけ、それを使ってsession情報からuser_id = 10を見つける。

ブラウザはuser_id = 10のプロフィール情報を表示したページをブラウザへ返す。

セッションIDがバレるとマズい

ここで、B君が何らかの方法でA君のsession_idが1であることを知ったとする。

B君は自分のブラウザを操作してcookieにsession_id = 1をセットし、サーバーへアクセスすると、、

ブラウザは受け取ったcookieの中からsession_id = 1を見つけ、それを使ってsession情報からuser_id = 10(A君のid)を見つける。

ブラウザはuser_id = 10の(A君の)プロフィール情報を表示したページを(B君の)ブラウザへ返す。(情報漏えい)

だからセッションIDはバレてはいけない。

こんなセッションIDは嫌だ

プロトコルがHTTPだ

HTTPは暗号化されていないのでネットワーク経路上でsession_idが丸見えだ。
HTTPSであれ。

URLに付加されている

こんなやつ。
https://example.com/your_profile/?session_id=xxxxxxxxx

ブラウザをのぞき見たり、履歴からセッションIDがバレる。

他にも、B君がA君にこのurlを踏ませてログインさせることで、B君はA君のセッションIDがxxxxxxxであることを知っている状態になる。
※ただしサーバー側がログイン時点でセッションIDを変えていたら漏洩は防げる

セッションIDが連番だ

セッションIDがログイン順に連番で発行されていると、セッションIDを予測することが出来る。
例えば、B君がログインしてセッションIDが10だったので、その後ログインしたA君のセッションIDは11だろう、と予測が出来てしまう。
セッションIDは予測出来ないものでないといけない。

「予測できない」というのを自前で用意するのは難しい。
このあたりは暗号まわりと関連が深くて「自前で仕組みを作らず、用意されている仕組みを使え」という感じ。

関係ないサイトにもセッションIDが送出されている

アマゾンへ送出されるべきセッションIDが楽天へ送られてしまうと、楽天の人にセッションIDがバレてしまう。

通常はドメインで送出先が制限されているのでそんなことは起こらないが、
設定によっては、example.comへのセッションIDが、a.example.comへも送出されることはある。

仮にレンタルサーバー事業者などで、a.example.comが別の管理者のサイトになっている場合、
example.comのセッションIDがa.example.comの管理者にバレる事になる。

逆に、関係ないサイトのセッションIDを送出してしまうケースがある。
クッキーモンスターバグ」というバグが原因で、無関係のサイトのセッションIDを送出させられることで、セッションIDを強制させられ使用セッションIDがバレるというケースもある。

ログイン先サイトが脆弱だ

ログイン先のサイトのセキュリティ意識が低いと、様々な方法でセッションIDを知ることが出来てしまう。

攻撃者が用意したurlを踏ませるだけでセッションIDがバレてしまったりする。

vimとtmuxの設定メモ

エンジニアになった当初からターミナル作業を華麗にやることに憧れている。

現状の設定と操作方法をメモっとく。

以下、参考にしました

https://blog.craftz.dog/my-dev-workflow-using-tmux-vim-48f73cc4f39e

マスタリングVim

マスタリングVim

事前準備

fishとfzfとghqをインストール

【覚書】Ubuntuのシェルをfishにした - やる気がストロングZERO

Ackをインストール

sudo apt-get update
sudo apt-get install ack-grep

dotfiles用意

ドットファイルのクローン

ghq get https://github.com/mixmaru/dotfiles.git

各種設定ファイルをリンク

ln -s  ~/ghq/github.com/mixmaru/dotfiles/.vimrc ~/.vimrc
ln -s  ~/ghq/github.com/mixmaru/dotfiles/.tigrc ~/.tigrc
ln -s  ~/ghq/github.com/mixmaru/dotfiles/.tmux.conf ~/.tmux.conf
ln -s  ~/ghq/github.com/mixmaru/dotfiles/ide ~/bin/ide

使い方メモ

fish

gitリポジトリ移動
ctrl + g

コマンド履歴検索
ctrl + r

ディレクトリ移動
ctrl + o

tmux

画面分割
ide

ペイン移動
ctrl + b h 左移動
ctrl + b j 上移動
ctrl + b k 下移動
ctrl + b l 左移動

window移動
shift + ctrl + 矢印キー

vim

ディレクトリ一覧表示
-

ファイルやバッファから開くファイルを検索
ctrl + p

指定箇所に移動(vim-easymothon)
\\ w 前方移動
\\b 後方移動

検索
:Ack 文字列

折りたたみ
zR 全部開く
zM 全部閉じる
za トグル

画面分割
ss 縦分割
sv 横分割

画面移動
ctrl + w h
ctrl + w j
ctrl + w k
ctrl + w l

タブ切り替え
shift + tab 正方向
shift + ctrl + tab 逆方向

「良いコード」と「良くないコード」の特徴

自分が思ってる「良いコード」と「良くないコード」の特徴を書きなぐってみる。

関数

良い

引数と返り値を見て、何をしているのかなんとなくわかる。

c = add(a, b)

# aとbが加算されてるっぽい

良くない

引数と返り値を見ても、何をしているのかよくわからない。

c = add()

# なにかを加算してるらしいけど、何が加算されているのか、、(内部でdbからデータを取得して加算して返してたりする)

どういうこと?

処理の詳細を隠して一言(関数名)で表される事で抽象化を行って理解しやすいコードにするのが関数の一つの役目。
中身を見ないと理解できない関数は、中身が隠蔽されている分理解しづらくなっているだけなので良くない。

関数は外から見てやっていることが、どういう実装なのかは考えずに解ることが大事だとおもう。

カスタマイズ

ある一連の処理にて、実験的に一部の処理をスキップさせたい。

良い

単に該当部分をコメントアウトし、値が帰ってきたことにすれば意図通りに実行できる。

良くない

どこが該当処理なのかよくわからない。
ここだと思う部分をコメントアウトして実行すると、別の場所でエラーが出る。
見てみるとコメントアウトした処理が実行されたときにDBにデータが挿入されており、その値がないので後続処理でエラーになっていた。

どういうこと?

良いコードは処理と処理が独立していて、ある処理が別の処理に直接影響していることがない。(処理の結果値を次の処理がもらうことはあるが、値が必要なだけで処理自体が必要なわけではない)
だから、次の処理のために仮の値を用意してやることで簡単にスキップすることができる。

良くないコードは、ある処理の副作用が別の処理に依存されていたりして、処理を書き換えることが簡単にはできない。中を調べて何が行われているかを知り、別の処理に影響がでないように変更してやる必要がある。

仕様確認が簡単にできる

あるapiのバリデーションルールを知りたい。

良い

そのapiのバリデーション定義見てすぐ理解できる。

良くない

そのapiのバリデーション定義を見ると、複数のapiから共有して使われており、多数の条件分岐が存在していた。リクエストパラメータによる分岐もあり、どういう値が渡ってくるのかも把握しないといけない(しかしそれは今回の対象apiでは渡ってこないものなのかもしれない)。 先頭から条件分岐を追っていかないとルールが把握できない。。

どういうこと?

設計されずにその場しのぎでコードがいじられると陥る。
アドホックにif分岐で対応され続けた結果、論理的な構造を持たないコードの塊になってしまっている状態。

リファクタリング

メソッドの定義位置に違和感が出てきたので別のクラスにメソッドを移動させたい。

良い

メソッド定義場所を移動させ、呼び出し元を書き換えて、少し調整すれば移動できた。

良くない

メソッド定義場所を移動させ、呼び出し元を書き換えて、少し調整したがエラーがでた。
調べると内部でdbデータの読み書きを行っており、そのためにライブラリを使っているが、移動先にはライブラリがインポートされていない。
移動先にライブラリをインポートして、DB接続初期化処理を用意してやらないといけない??

どういう事?

何らかの処理メソッドなのに、内部でdbアクセスまでやってる(もしくは別のオブジェクトに副作用を与えてる)から、保存ライブラリや別オブジェクトに依存した形になってる。

計算して結果を返し、別オブジェクトへの干渉は別途やっていれば(つまり一つのことだけ行うようにしていれば)メソッド定義場所の変更は容易なはず。

テーブル定義

良い

テーブル構造とデータをみれば、コードを追わなくても状態が把握できる。 どのようにデータを変更すればどのような状態になるのか、コードを追わなくても解る

良くない

テーブル構造とデータの中にフラグが多数あり、どのフラグがどうなっているかによって、データの見方が複雑に変化するので理解が追いつかない。
「こういうデータは存在しえない」とか「typeが○○のときoptionには××の情報が入っている」とか、データの見方に暗黙のルールがたくさんある。

どういうこと?

  • テーブル設計が詰めきれておらず、コード側で補完してる。(だから処理と組み合わせて見ないと理解できない。)
  • 処理のためのデータが存在してでそれがノイズになってる。(それはコードを見ないとどのように使われているのかわからない)

こういうのは大抵コード側も複雑な事になってる。。

導出できる値の扱い方

例えば「消費税」をどのように扱うか?

良い

算出メソッドが定義されてて、必要なとき実行し定価から算出されるようになっている。

良くない

算出した消費税額を保持していて、定価が変化(値引きなど)するたび再計算して保持し直している。

どういうこと?

こういう事をする動機としては「一旦計算した値を保持することで何度も計算せずにすむ」とかなのかなと思うが、
だいたい管理できなくなって事あるごとに再計算処理を実行するような感じに陥ってたりする。

例)
* ここで定価を変更した、このあと消費税の再計算を実行しているかよくわからず不安だから再計算を実行しておく。
* ここで消費税が必要だけど、どこかで消費税計算実行が漏れていたら怖いから再計算処理を実行しておく。

結果、なんどもなんども消費税の再計算が不要に行われてたりする。(何度も計算せずに済むはずだったのに。。)

つまり、データの整合性を自力で取っていかないといけないので複雑正が増している。