Kotshi+MVVMをカジュアルに採用してみた。

GWも過ぎて、ハイテンションで迎えた令和もすでに鬱々とした気分で過ごす日々です。
今回はKotlinでアウトプットする機会があったので、便利ライブラリを簡単に紹介します。



ネイティブアプリケーション開発においては、バックエンド側のWeb-APIRailsなどで用意することが多く、Kotlinで開発するクライアント側はリクエストを送信し、レスポンスに乗っているJsonを整形することで表示するデータを取得します。


しかし、null許容を搭載しているKotlinにおいてはKotlinJsonAdapterFactoryなるものを追加しない場合に空のJsonをパースする際にぬるぽが発生したり、
Moshiなるアダプターを使用するもののリフレクションを搭載している為に解釈が遅いといった問題があります。


Jsonを解析する時の問題

まだこれらの利点を払拭するような実感は得ていませんが、今回はKotshiというライブラリを使用することにしました。

よくある画像とコメントをリスト形式でレスポンスするAPIを例に、下記のようなクラスを実装しています。


Response


{
params: {
total: 100, # 総レコード数
offset: 50, # オフセット
limit: 5 # リクエスト時指定の取得数
},
album_records: [
{
"image_url": "https://album-records.herokuapp.com/images/hoge.jpg",
"comment": "Hoge",
"tag": "programming",
"recorded_at": "2019-05-10 00:04:00"
},
{
"image_url": "https://album-records.herokuapp.com/images/fuga.jpg",
"comment": "Fuga",
"tag": "programming",
"recorded_at": "2019-05-10 10:12:50"
},
...

Client


// 実際にJsonを解析するアダプタークラス
@KotshiJsonAdapterFactory
data class Album(
@field:Json(name = "params") var params: GetDataParams,
@field:Json(name = "album_records") var albumRecords: List
) {

companion object {
val INSTANCE: AlbumRecord.Companion = AlbumRecord
@ToJson fun toJson(writer: JsonWriter, value: AlbumRecord, stringAdapter: JsonAdapter) {
stringAdapter.toJson(writer, value)
}
}
}

// 取得したいインナークラス(album_recordsの中身)
data class AlbumRecord(
val image_url: String?,
val comment: String,
@Json(name = "tag") val tag: String?,
val recorded_at: String?
)

// リクエスト時のパラメータ(今回は使わない部分)
@JsonSerializable
data class GetDataParams(
val total: String,
val offet: String,
val limit: String
)

// レスポンスを格納するViewModel
class AlbumRecordViewModel: ViewModel() {
val albumRecoLiveData = MediatorLiveData>()
}




@field:Json(name = "params") のように指定することで、Jsonを解析してくれる名前を与える事が出来、後置の名前でクラスのメンバとして振る舞います。
Kotlinのdata classはtoStringなどが備わっているので、パースで入り用の際にはデータを処理するメソッドを用意する手間を無くし、憂鬱な気持ちも軽減してくれます。


今回はリスト形式のオブジェクトが含まれていた為に、クラスを切り分けつつうまく解釈してくれるような構造にしました。不必要な部分については無視してくれる便利なアノテーションも存在しますが、下記のエラーに対応していて実装はしませんでした。


Exception in thread "main" java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 16 path $.response
https://stackoverflow.com/questions/41649731/gson-expected-a-string-but-was-begin-object
つまりはStringとして期待されたメンバはオブジェクトでやってきちゃったよ!
どうしろ言うんじゃい!!!

と言うKotlin(もといJava)様の叫びです。
これは上のようにparamsとalbum_recordを切り分けずにひとつのクラスで解析しようとしていたところ頻発して、メンバ宣言の位置変えをしてみてもうまくいきませんでした。


で、実際に解析をしたいメンバを連ねるだけではダメで。
companionに書かれている専用解析変数&メソッドが鍵となります。
解析したいクラスの情報を渡して、そこではどんな感じにパースすんのと言うメソッドもimplementします。(書かなければ@FromJsonか@ToJson実装しないとこれ使えへんでと言われる)


リクエストをどうするか問題

今回リクエストに使うライブラリはOkHttp3にしてみました。触った事なかったから。
こいつはGETする時にはパラメータを変えたいなと思った時に、インスタンスがイミュータブルなもので、もうひとつ新たなものを用意しないと調整ができないと言うものでした。

Web触っていた時にはerbさんが非同期でリクエスト取ってきてくれていたものだけど、今回扱ってるものは小さなパソコン、Androidなので極力パフォーマンスも考慮して実装していきたい。

そこで画面回転があろうとインスタンスを死守してくれるViewModelさんの力を借りました。

プライベートアプリなのであらかじめ全てのデータを取得して、適当にページングして少しずつ見せる感じに。画像の表示はPicassoを使ったのでスマートにキャッシュを持ってくれて、表示もサクサクです。



諸事情でデモやコードは上げてないですが、許可が取れたら上げてみます。
今回の反省点はと言うと、なんだかんだと困ったらすぐに検索してしまい、ライブラリのソースコードをきちんと読むことを疎かにしていたって事です。ライブラリもコードなの、ああそういえば昔参加してる勉強会でひたすらコードリーディングしてる人いたけど、あれが正なのかなあ…




(イケてる開発者のトレンドはまだまだ理解できないよ…)

基本情報技術者を受けてきた

お疲れさまです。今年の本命枠とも言える資格試験を受けてきましたが、惨敗の結果に終わりました。。

理由は明白で、午後試験の対策をぬかっていたところだと思います。
基本情報技術者(以下基本情報)は午前と午後科目に分かれており、両方の試験で6割以上を期待され、それを超えることによって初めて合格となります。

本年の講評的に、万遍なく計算問題などは出題されていたものの、ハードウェアやトリッキーな問題は出ず(回路もすごく無難なものが出た)、他年度に比べて平易だったと言います。。
自己採点では午前は6割を超える事が出来ましたが、午後は50%程度しか得点できず、悔しい結果となりました。

午後試験問題の反省点

ソフトウェア設計(WebAPI)、アルゴリズムでの大コケ

一番痛かったのは、認めたくはないですがWebAPIでの大コケです。

DB, WebAPIの仕様が羅列されており、これを要約した内容に解答したり、
機能実装の例に解答するような問題です。
絵を描いて関連を把握したのは悪くなかったとは思うのですが、実際に動作するところまでを冷静に想像する必要があったと思います。ただ前提の内容を真に受けるようではダメ…

1番最初の問題はとっても基本的な問いです。
認証関連WebAPIと、登録ツールからアクセスできる。よって、申し込みDBに格納されている情報は_________である。


ここは申込者IDと解答しましたが、正解は申込者情報と検査農産物情報なのでした。(5)検査管理システムに登録された検査結果を確認して、申込者に検査結果を報告する とあるので、検査農産物テーブルは中間テーブルの役割をしていたと考えられます。

申込者←→検査農産物←→検査結果情報

こんな感じで参照することができた。


アルゴリズムについては正直テンパりながら問題を読んでいたので、お絵かきと表が全然合わなくてさらにテンパっていた

後半に進むにつれて時間が全然足りなくて、焦りが次第に諦念に変わった感じだったな…

解答の順番はこんな感じでした。
(プログラミング)Java→情報セキュリティ→DB→ネットワーク→ソフトウェア→プロジェクトマネジメント→アルゴリズム


午後問題のよかった点

データベースとマネジメントはしっかりと得点できていた

といっても上記以外の基本的な問題の得点はしっかり得られていたと思います。
業務でも触った事があったLIKEや前提に解答が書いてあるものは簡単に感じました。(ギリギリで=でワイルドカードが使えるのかを迷ってしまったのは内緒。)
主キー=UNIQUEやろ!!みたいな思い込みが失点の原因となってしまいました。

マネジメントは計算もピッタリと合っていて、利用部門から仕様変更の依頼などは業務内でもよくある光景なので
「あーうちもこんな感じでふるいがいればいいのにな…」と感想が出るくらいには問題と向き合う余裕がありました。

午前は?

午前については再帰的呼び出し、dpiの計算、ホストアドレスの個数などを落としてしまったのが悔しかった。機械学習関連の問題だったり、メル●リ的なプロダクトについて問題が出たのは今時だったな。
HEMSについてはニュースで見たから解答できた。

個人的総評・令和第1回目に向けて

時間に追われて得点を落としてしまったので、この先に必要なのは特に問題の読み込みに対する慣れと、アルゴリズム問題に対するアレルギーをなくすことだと思ってます。

午前の計算問題に対しても理解を伴って解答できればさらに得点できるかも。
とはいえ、次回の難度は上がりそうなので覚悟を決めてもう一度学習に取り掛かろうと思います。アルゴリズムは本当に対策しないと大変だぞー…


ちな勉強法

・参考書、過去問1冊
道場

Nuxtの環境構築をDockerでサクッと実現する

時間がない人の為のDockerfile

FROM node:10-alpine

RUN apk add git emacs

RUN npm install -g vue-cli
WORKDIR /app
ENV HOST 0.0.0.0
EXPOSE 3000
version: '3'
services:
  app:
    build: .
    tty: true
    volumes:
      - "./../app:/app"
    ports:
      - "3000:3000"



足りないものは自分で継ぎ足してね(・ω・`) 要らないもの然り。
brewなど入れてあるのでgitでpushやら最低限のことはできるはず
今回はベンチマーク取ってないけど、 体感的にAlphineを使ったほうが適当なイメージをpullしたり、拾ったDockerfileを使うよりもファンが昂ぶらなくて良いと思った。 OSって色々詰まってるんだね。
npm触り出すとすぐ依存性とか詰まるから、今の所は助かってる。。

docker-compose build

docker-compose up

docker ps (idチェック)

docker exec -it (container_id) sh brew入れ方はLinux Brewのページを参照する

uname -a (動いているサーバのお名前頂戴) Linux e8aa47ead274 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 Linux
appプロジェクト配下で npm i --save npm run dev




うわあああああん!!(別案件)

f:id:letterneginr:20190408100348p:plain
docker内でvueのエラーする図

ご参考 https://github.com/Linuxbrew/brew/wiki/Alpine-Linux https://techblog.zozo.com/entry/docker_image_slim_in_alpinelinux https://qiita.com/tukiyo3/items/247f853c81bf00e82c11

MotionLayoutでリッチなUXをxmlのみで表現してみました

長いこと更新をサボってました。。 最近はもっぱらKotlinでのAndroid開発に従事していますが、ビューの原則はMaterialDesignを取り入れ、バラツキのあるデバイスの端末性能を吸収する優秀なプラグインが用意してあったりと、奥深く、ネイティブは楽しい分野だと感じています!

(デザイナーさんから思いもよらぬ仕様を叩きつけられることもありますが…)

勉強がてらに新しい部品に触る事も楽しいです!

そんな感じでいただいたデザインと納期の間で不安に苛まれていたとある日、何某Kotlinイベントに参加してみました。 Droid会議直後の温まった会場でMotionLayoutについて教えていただく機会があり、実装してみたので軽くレビューしていきます🐕

1. xmlファイルでリッチな動きが実現するMotionLayout

実装例・導入方法など詳しくはこちらをご覧ください💁‍♀️

https://github.com/googlesamples/android-ConstraintLayoutExamples

Google I/O 2018で紹介されているようですね♩ youtu.be

< 実装例gif >(でかくて申し訳ない…)

gfycat.com

RecyclerViewは別途Adapterクラスなどの実装が必要なので、実装にはこちらを参照してください。

2. 導入 : build.gradle

build.gradle

dependencies {
  implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha3'
}

3. ベースのxmlを記述する

base.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".HogeActivity">

    <android.support.constraint.motion.MotionLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/design_default_color_primary"
        app:layoutDescription="@xml/motion"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">   
 
       <android.support.v7.widget.RecyclerView
            android:id="@+id/top_recycler_view"
            android:layout_width="wrap_content"
            android:layout_height="500dp"
            android:paddingTop="30dp"
            android:background="@drawable/recycler_view_bkground"
            android:scrollbars="vertical">

        </android.support.v7.widget.RecyclerView>
    </android.support.constraint.motion.MotionLayout>
</android.support.constraint.ConstraintLayout>

4. motionタグの追加

motion.xml

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:motion="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <Transition
        motion:constraintSetStart="@id/base_state"
        motion:constraintSetEnd="@id/open_state"
        motion:duration="3000">
        <OnSwipe
            motion:dragDirection="dragUp"
            motion:touchAnchorId="@id/top_recycler_view"
            motion:touchAnchorSide="top">
        </OnSwipe>
    </Transition>

    <ConstraintSet android:id="@+id/base_state">
        <Constraint android:id="@id/top_recycler_view">
            <Layout
                motion:layout_width="400dp"
                motion:layout_height="100dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintVertical_bias="1.0">

            </Layout>
        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/open_state">
        <Constraint android:id="@id/top_recycler_view">
            <Layout
                motion:layout_width="400dp"
                motion:layout_height="500dp"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent">
            </Layout>
        </Constraint>
    </ConstraintSet>
</MotionScene>

非常にさっくりと説明すると、app:layoutDescription="@xml/motion_activity_first_visit"のように設定したmotion.xmlで該当の部品のアニメーションを指定します。 今回のアニメーションはベースの状態(@id/base_state)とアニメーション終了時の状態(@id/open_state)です。 motionタグで囲う範囲については、アニメーションの可動域となるので、くれぐれも他の要素が消え去らないように注意してください。(プレビューすれば一目瞭然ですが…)

今回はmotion.xmlで、部品上部において上にスワイプする操作で、ビューがプルアップ+ダウンする挙動を制御しています。 フリック(軽く指で弾くような動作、スライドショーをめくるような動き)では反応しないので、適宜使用するタグを付け替えてみてください。

公式のリポジトリの例が豊富なので非常におすすめです。

https://github.com/googlesamples/android-ConstraintLayoutExamples

報告者を指定日時で通知するスクリプト<Slackユーザー向け / コード付き>

N番煎じ?

月末に部門定例会があるので、公平にみんなの中から報告者を決めることにしました💁‍♀️



Slack当番通知
Slack当番通知


GoogleAppScript

var postUrl = 'https://hooks.slack.com/services/HOGE/HOGEHOGE/HOGEHOGEHOGE'; …①

var icon = ':hatching_chick:';
var index = 0;
var checked_engeneer = '';
var icon_url = 'https://hogehoge-team.slack.com/team/HOGEHOGE'


var engeneer_ids = ['<@hoge1_slackId>', '<@hoge2_slackId>', '<@hoge3_slackId>', '<@hoge4_slackId>', '<@hoge5_slackId>'] …②



function shuffleReporter() {

index = Math.floor(Math.random()*6)

var id = engeneer_ids[index]

var jsonData =
{
"username" : '悪意のないchick',
"channel" : "#development",
"icon_emoji" : icon,
"text" : '今月の開発部門報告者は' + id + 'さんだよー\n開発のみんなの1ヶ月のタスクと、最近自分ががんばったことを話してね!',
"icon_url" : icon_url
};

var payload = JSON.stringify(jsonData);

var options =
{
"method" : "post",
"contentType" : "application/json",
"payload" : payload,
};

UrlFetchApp.fetch(postUrl, options);
}

①… SlackのwebhookAppをオンにして、出力URLを取得しましょう。
②… メンション用の個人タグです。付けないとメンション飛びません。個人の詳細ページからmemberIdとして取得できます。



悪意のないひよこが教えてくれます。(これはKotlin因み…🐤)
Cronもあるらしいけど、今回は手動で時間設定。
時間主導型の設定フローは下記画像を参考にしてください。
時間主導型設定フロー

カレンダーのイベント抜いて設定したら、また更新します。

2018年振り返り+2019やりたい事まとめ🐶

生活面

## 遅まきにはじめた一人暮らしが存外に快適だった。

- 杉並区は都内までのアクセスがよくて(JRとメトロの駅が15分圏内のとこにいる)、割と飲食系の有名店も多い。
- 家は全然広くないけど、一人だと部屋のメンテが超楽。
- アニメ充と引きこもりが捗る(家の裏にファミマがある)
- クロスバイクに乗り始めたけど運動解消にいい。コミュニティとかにも参加したい。

## 生活リズム狂いがち。

- 無職時代は1年前と違って昼起床がデフォになりつつあった。
- 料理し始めるのはいいが、モチベーションがそこまで上がらない😊(テンプレをローテーション)
- 割と情緒不安定な時期とかあった。
- 自己投資と称した散財は割と多かった💸💸💸


仕事面

## 2年前よりはコードを書く機会が増えた。

- エンジニアとしてやっていけるか超不安で、センスもないと思い込んでいたけど、
頼まれごとも割と増えて去年よりは自信がついた。
- MAMPの設定もよくわからんかった自分ですが、GCPでDBサーバ建てて通信したり、ドメイン取ったりしてデプロイが出来た。
- 貧弱資格だがRuby Association Programmer Silverを取得した。Goldは5問正答が足らず落ちてしまったので、やる機会あればまた受ける。
- web系あるあるなフロント周り、頑張ろうと思えば極められたけど、技術を摘み喰いしてしまった結果サーバサイド寄りな事をやっていた😇
- ↓↓やった事たち↓↓

---書いた
Ruby, Ruby on Rails, slim, SaSS, js(jQuery, erb, ECMA2015), Kotlin

---触るもしくは眺める程度
Docker, GCP(GA, GKE), AWS, Elasticsearch, Vue.js
mysql, postgres
Ubuntu, Debian stretch
Photoshop
Dialogflow
vim, zsh周り


## 転職できたー🎉🎉🎉㊗️

- ほんとは前職で3年くらいいる予定でいたが、技術的な方の自分のテンションが上がってしまった為、転職する事にした。
- 10件強面談とかして4件内定もらえた。実感したのは自分の頑固さや人と話すことの下手さ😇
- ビズよりな知識も不足している。もうちょっとニュース見たり官報見たり、経営の勉強してもいいよね。

- GCP, Kubernetes, Kotlin, Swift, Java, Ruby, Railsが主な活動範囲の会社です。
 アウトプットサボらず頑張ろう。

## プログラミングという行為を通して人見知りが解消してきたような気がする。

- 勉強会・もくもく会行きまくった。(connpass上の勉強会は21件参加してた)
- 同業の人たちとお話しする機会があってとても良かった。特に同世代からは刺激を受けた。
- 何気に下手くそなLTをもくもく会で披露したりした。



2019年やりたい事

- アプリのデプロイ回数を増やす

Herokuを年中disり、無駄課金を言い訳にあまり捗らなかったところがある。

- 英語

ドキュメントを読んだり、外注の人とやり取りするだけに止まった。スピーキング力を上げたい。
 現在の職場の先輩曰く、本になっている情報は古い。
 (本に書いてある情報を知らない事もあるので本を読むなという意味ではない😇)

- 余暇の過ごし方

  技術と食べる事以外にそんなに頑張っていない。カメラとか二輪取得に向かって頑張りたいところ。
 多分素材が集まれば個人HP作るだろう(管理費も会社から支給されないかしら)

- 資格取る

 基本情報技術者かな…とりあえず受かるまで受ける😇

- 技術的なポリシーを打ち立てて勉強を進めたい

 頼まれて実装することは多くても、保守性を意識してコーディング出来ていなかった気がする。
 アプリやDB設計周りの勉強は続けたいし、テストを書く習慣を付けていきたい。
 Goを触りたいという気持ちでいるけど、実務で私の書いたKotlinが受け入れられてから考えることにする。

SQLアンチパターン論理設計編の追記

こんばんわ!Paypayを導入した翌日に20%還元イベントが終了した者です。
意外にコンビニで「Paypayで」とお願いすると困惑される事も多くて、まだまだ10日では日本国民に浸透していない雰囲気ありますね?
セブンイレブンでは怪訝な反応をされましたが、ファミマはPaypayアナウンスが入る程度に対応が早かったですね)

しかしアマゾンとメルカリさんが経団連の面子に入ったことから、IT分野が経済圏の掌握をしていく未来は避けられなさそうですね。扱うジャンルのものにも依ると思うのですが、再度金融商品周りの勉強をしても損はなさそうな気がしています。
UI周りの重要度の認識も上がるといいのですけど!
あとは著作物の権利関係かな。民間資格で言うとビジネス著作権検定などもありますので、資格コレクターな方は是非是非。


経営面も強くなりたいので、バランスシートを読む練習はしたいなーと思いつつ全然やってないですね…
会社を持つ気にはなれないのですが、身を置いている会社がどんな状況にあるかは把握しておきたい的なやつです。
今話題の基本用法技術者の出題範囲でもあります。

それよりもカジュアルに、エンジニアによるエンジニアの為の生存戦略ベンチャーの経営状況を把握するみたいな標題の勉強会がそのうち開催されることを夢見てます。笑



本題です。なんとSQLアンチパターンまとめの目次抜けがありました🤣
自らまとめると意気込んだにも関わらず、この体たらくです。本は1回読んだだけじゃダメですね。
自分はかなり物覚えも悪いので、だいたい目に付くところに提出書類をまとめたファイルをぶら下げてあります。
とりあえず目に入らない情報は綺麗に忘れていく

エンジニアの勉強で難しいところは、個人的に触って実践できる部分と、本番でなければその利点や使いづらさを身にしみて理解できない部分があるところだと思います。

本番の再現ができる技術レベルでもない限り、私たちにできることは、なんとなく勉強会などで聞きかじったことを、経験のある人に話題として振ってみるくらいのことしかできないので、
今後は自分のスキルを積み上げる為にも、初心に戻ってシステム開発の基礎+他言語+フレームワークを触る予定でいます。
近いうちに〇〇と〇〇ができる人!って感じに頼られたいですからね!笑


ようやく本題。今回ご紹介するDB設計アンチパターンはこの2つ!

マルチカラムアトリビュート(複数列属性)
メタデータトリブル(メタデータ大増殖)


マルチカラムアトリビュート(複数列属性)

この事例を読んだ時には、「あー。これこれ。よくやるやつ本当これ」ActiveRecordを触っていた時によく思っていたこととがっつり同期しました。

なんか増えそうな項目なんだけど、とりあえずカテゴリ分けしておきたい時
Bugsというテーブルがあったとします。
このテーブルは単一テーブルでバグの発生日時、発生順、バグの内容、バグの起因を表現しています。

bug_id バグの発生順
reported_at バグの発生日時
issue バグの内容
case1 バグの起因(ユーザー起因)
case2 バグの起因(開発者起因)
case3 バグの起因(運用起因)

こんな感じで設計してみました。ただ、このcase*カラムは未使用のものに関してNULLを返す仕様になっています。

この設計で困る時

なんか検索クエリ長い

起因が複数にまたがる時は以下のようなクエリを発行したくなります。(INを使えばもう少しマシになる)

select * from Bugs
where (case1 = 'user' or case2 = 'developer' or case3 = 'customer service')
and (case1 = 'user' or case2 = 'developer' or case3 = 'customer service');

値を更新したいけど更新処理が突合しないか

どの列が空いていないかを確認し、更新処理をかけたところで他のユーザーが同じデータの列に更新処理をかける可能性も否めないわけです。
しかし、この事例ではNULLIF関数を使用することでそれが避けられそうだというソリューションが乗っていました。

update Bugs
set case1 = NULLIF(case1, 'user'),
set case2 = NULLIF(case2, 'developer'),
set case3 = NULLIF(case3, 'customer service')
where bug_id = 1234;

ちょう便利!しかし、これでfalseを返す場合にデータの更新処理は行われません。
従ってIF文を書かなければいけないわけです(もうコレアプリ側でやるやつやん…

万が一属性が増えた場合に、クエリがさらに長くなる
スキーマを変更したいときにテーブル自体をロックしなければいけない可能性
新規テーブルを定義して既存テーブルをコピーしてマイグレートするサードパーティ製品もあるので気をつける(地獄

ソリューション

caseを切り出してテーブルにしてしまうのが良いようです。縦管理で心置きなくdelete文を発行できます😇

メタデータトリブル(メタデータ大増殖)

本棚を買ったけど、スペースがどうにも気になって読まない本まで入れてしまうやつ。

本書の事例では、ある顧客管理テーブルと関連性を持った年毎の顧客データ格納テーブルを設計した話が記載されています。
使用用途はアクティブな顧客を一目でわかるようにしたいとのこと。

しかし毎度クエリを発行するのがめんどくさい怠惰なCSチームはもれなくこのテーブルを放置プレイする訳です。おめーらが作れって言うてたやんけ!
開発者の中ではこのテーブルをどう活用するのか議論になりますが、下記のようにおえかきじゆうちょうもびっくりなフリーダムなテーブルへと変貌を遂げます。

年毎のテーブルを毎年createする必要がある
データの整合性をチェックする必要がある

私は正規表現などで弾くものかと思ってましたが、
CHECK制限を儲けるとこのあたりは捗るみたいです。

create table Bugs_2018 (
date_reported DATE CHECK (EXTRACT(YEAR FROM date_reported) = 2018)
);

他の年度とjoinしたテーブルから特定の値を抜きたい要件では、発行するクエリがめんどくさい感じになる…

ソリューション

パーティショニングする
やっぱり別枠で切り出す😇

パーティショニング is 何?

私もこの章を読んで初めて知りました。パーティショニングとは、

テーブルをデータベース内部で複数の領域(指定キー)に分割する機能

だそうです。

私のイメージではAテーブルにA'というテーブルが違うレイヤーにあるイメージとして捉えています。

本書で発行されるクエリは以下のようなものです。

水平パーティショニングされたテーブルの作成の例

4分割されたテーブルにdate_reportedがはいる。

create table Bugs(
bug_id SERIAL_PRIMALY_KEY
date_reported DATE
) PARTITION BY HASH ( YEAR(date_reported) )
PARTITIONS 4;

パーティションはpostgres, Oracle, mysqlではざっと対応していそう)

垂直パーティショニング

水平パーティショニングは行で(1レコードずつ)分割するが、
垂直パーティショニングは列で分割をする。格納データが膨大な場合に後者を使用する。


\-- 関連テーブルを外部キーで参照するのもパーティショニングのテクニック

create table ProductionInstallers (
product_id BIGINT UNSIGNED PRIMARY KEY,
installer_image BLOB,
FOREIGN KEY (product_id) REFERENCES Products(product_id)
);

例えば、ブログ記事に見出し画像を設定したい場合にバイナリで持つ場合にした時に関連テーブルを持たせる雰囲気です。(BlogDetail?)

この辺あやふやなので後ほど加筆します!



ラクル社の提供する講座&pdf
第10回 パーティションについて
https://www.oracle.com/technetwork/jp/ondemand/database/db-technique/d-12-disk-1484778-ja.pdf