作りたいものがありすぎる

40歳を過ぎてプログラミングを始めた人の顛末とこれからなど

Laravelのブラウザテストでテストメソッド毎にシーディングを毎回しない方法

前置き

アプリをある程度作り込んでから、自動テストやTDD(テスト駆動開発)を覚え、いざ自分のアプリで実践しようとした所、かなり手を入れないとろくなユニットテストができない状態という事が分りました。
なにしろユーザーのロール権限が5つもあり、権限毎に表示や動作が異なる箇所が多々ある。(どうしてこうなった)
メソッドの中で他のメソッドを呼びまくり、値を拾っては他に投げ、みたいな入出力の制御が複雑で大変危うい処理もある。
また、例えばあちらのバグをつぶすと、こちらでバグになる。とか、この権限での仕様を変えたけど、他の権限での動作や表示には対応してる?といった確認作業も多くなりました。

で、やむなく現在のアプリを自動ブラウザテストでそれぞれの権限での表示や動作を検証する、という事をしてます。要は自分で画面見て、操作して、というのを機械にやらせる処理を淡々と書く作業です。(正直しんどい)

本題

で、その際によくあるのが setUp() メソッド(テストのメソッド毎に実行される処理)に、シーディング処理を書く奴、こんなのです。

<?php

namespace Tests\Browser;
// use 省略
class Profile_superAdmin_user_Test extends DuskTestCase
{

    use RefreshDatabase;

    protected function setUp()
    {
        parent::setUp();
        Artisan::call('migrate:refresh');
        Artisan::call('db:seed');
    }
    // 以下略
}

この処理なんですが、setUp()はこの下に書かれるブラウザテストの複数のメソッド実行前に毎回実施されます。なので、DBの再構成をテストメソッド毎に毎回やると、テスト実施に結構時間がかかってしまいます。

なので、この中の処理をテストクラスの最初の1回のみ実施される、 setUpBeforeClass()を書いたのですが、理由は忘れましたがうまく行きませんでした。(BrowserテストにsetUpBeforeClass()が無かったか? Artisanコマンドが使えなかった?だったと思います。)

では上手い方法はないか?と調べた所、以下のページの記述に当たりました。

How Do I Seed My Database in the setupBeforeClass Method in a Laravel 4 Unit Test?

日本語直訳サイト
Laravel 4ユニットテストでsetupBeforeClassメソッドにデータベースをシードするにはどうすればよいですか?

<?php

namespace Tests\Browser;
// use 略

class Admin_Community_superAdmin_user_Test extends DuskTestCase
{
    protected static $db_inited = false;
    use RefreshDatabase;

    protected static function initDB()
    {
        Artisan::call('migrate:refresh');
        Artisan::call('db:seed');
    } 

    protected function setUp()
    {
        parent::setUp();
        if (!static::$db_inited) {
            static::$db_inited = true;
            static::initDB();
        }
    }
    // 略
}

setUp() メソッドをあたかもsetUpBeforeClass()の様にクラスインスタンス後に1度だけやってくれる書き方です。
$db_initedという静的プロパティを持たせてsetUp()で一度 true にしてしまったら、 setUp()内の ifの処理で以降は Artisanファサードを呼ばない。という実装。ピタゴラスイッチ的な動きですよね。こういうのって見ればそれなりに動き追えますが、自分で書ける気がしません。が、なにはともあれ解決。

しかしこれだと、テストクラス内でDBの値を変更してしまう処理を書くと、以降のテストに影響がでてしまうのですが、そこは、テストクラスを上手く分けて書いて行けば解決できそうです。

追記

その後以下の様にテストメソッド内に Artisanファサードを使ってDBのシーディングを行う処理を書くことで、さらに必要な時にだけ、シーディングが行えることがわかりました。このまま行くとsetUp()メソッドが無くても何とかなるる感じですね。

<?php

    /**
     * @test
     */
    public function DBを編集するテスト()
    {
        // 省略
    }

    /**
     * @test
     */
    public function 後処理()
    {
        $this->browse(function ($browser) {
            $browser->visit('/user/edit?id=1')
               // assert が書かれて無いとテスト完了時に警告が出る為、便宜上入れた assert
                ->assertSeeIn('.comp-title', 'プロフィール編集');
                echo 'now seeding!';
                Artisan::call('migrate:refresh');
                Artisan::call('db:seed');
        });
    } 

Let's Encrypt のTLS-SNI-01から http-01 方式への変更をした備忘録

無料で使えるSSL認証Let's Encrypt から以下の様なメールが来ました。

Action required: Let's Encrypt certificate renewals

Hello,

Action may be required to prevent your Let's Encrypt certificate renewals
from breaking.

If you already received a similar e-mail, this one contains updated
information.

Your Let's Encrypt client used ACME TLS-SNI-01 domain validation to issue
a certificate in the past 60 days. Below is a list of names and IP
addresses validated (max of one per account):

 www.livelynk.jp (160.16.207.76) on 2018-12-25

TLS-SNI-01 validation is reaching end-of-life. It will stop working
temporarily on February 13th, 2019, and permanently on March 13th, 2019.
Any certificates issued before then will continue to work for 90 days
after their issuance date.

You need to update your ACME client to use an alternative validation
method (HTTP-01, DNS-01 or TLS-ALPN-01) before this date or your
certificate renewals will break and existing certificates will start to
expire.

Our staging environment already has TLS-SNI-01 disabled, so if you'd like
to test whether your system will work after February 13, you can run
against staging: https://letsencrypt.org/docs/staging-environment/

If you're a Certbot user, you can find more information here:
https://community.letsencrypt.org/t/how-to-stop-using-tls-sni-01-with-certbot/83210

Our forum has many threads on this topic. Please search to see if your
question has been answered, then open a new thread if it has not:
https://community.letsencrypt.org/

For more information about the TLS-SNI-01 end-of-life please see our API
announcement:
https://community.letsencrypt.org/t/february-13-2019-end-of-life-for-all-tls-sni-01-validation-support/74209

Thank you,
Let's Encrypt Staff

Google翻訳にかけてみる

必要なアクション:証明書の更新を暗号化しましょう

こんにちは、

あなたのLet's Encrypt証明書の更新
が壊れないようにするための行動が必要かもしれません。

すでに同じようなEメールを受け取っている場合は、これには更新された
情報が含まれています。

Let's Encryptクライアント
が過去60日間に証明書を発行するためにACME TLS-SNI-01ドメイン検証を使用しました。以下は
検証された名前とIP アドレスのリストです(アカウントごとに最大1つ):2018-12-25の

 www.livelynk.jp(160.16.207.76)

TLS-SNI-01検証は廃止予定です。それは動作を停止します
2月13日、2019年に一時的に、かつ永久月13日に、2019年
それ以前に発行された証明書は90日間働き続ける
彼らの発行日後。


この日までに ACMEクライアントを更新して別の検証方法(HTTP-01、DNS-01、またはTLS-ALPN-01)を使用する必要があります。そうしないと
証明書の更新が中断され、既存の証明書の
有効期限が切れます。

私たちのステージング環境は、すでにあなたが好きなので、もし、TLS-SNI-01無効になってい
2月13日後にシステムが動作するかどうかをテストするために、あなたが実行することができます
ステージングに対して:https://letsencrypt.org/docs/s taging環境/

あなたがCertbotユーザーであるならば、あなたはここでより多くの情報を見つけることができます:
https://community.letsencrypt。org / t /どうやってtls-snを使うのかi-01-with-certbot / 83210

このフォーラムにはたくさんのスレッドがあります。あなたのかどうかを確認するために検索してください
質問が答えられたら、新しいスレッドを開いてください(
https://community.letsencrypt)。org /

TLS-SNI-01のサポート終了についての詳細は、当社のAPI 
発表
https://community.letsencryptをご覧ください。org / t / 2月13日 - 1919年 - すべてのtls-sni-01- validation-support / 74209

ありがとう、
スタッフを暗号化しましょう

とのことで、従来の検証方法TLS-SNI-01から HTTP-01、DNS-01、またはTLS-ALPN-01 へのいずれかへの変更が必要とのことで、ググって対応しました。

結論から言うと、先人方が既に変更方法を確立されており、同様の方法で事が済みましたが、参考にさせていただいたサイトのリンクと、その方法を張り付けておきます。
サーバー環境はさくらVPSのcentos7となります。

Let’s encryptのドメイン認証の方法をHTTP-01に変更するための準備で試行錯誤した件。
Let’s Encryptの更新エラーを直す(certbot renew失敗)
Let’s EncryptのTLS-SNI-01認証のバリデーションに伴う対応策まとめ

まず サーバーにログインして rootになって Let's Encryptを更新します。

# yum update certbot*

次に以下のサイトを参考に設定変更のコマンドを叩きました

Let’s encryptのドメイン認証の方法をHTTP-01に変更するための準備で試行錯誤した件。

# certbot renew –dry-run –preferred-challenges http-01,dns-01

ところが何やらエラーが

Traceback (most recent call last):
  File "/bin/certbot", line 5, in <module>
    from pkg_resources import load_entry_point
  File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 3011, in <module>
    parse_requirements(__requires__), Environment()
  File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 626, in resolve
    raise DistributionNotFound(req)
pkg_resources.DistributionNotFound: acme>=0.29.0

なんかよくわかりませんが、大事な事は最初か最後に書いてあるので、今回は最後の1行でググると以下のサイトの情報に行き当たりました。 Let’s Encryptの更新エラーを直す(certbot renew失敗)

同じエラーが載ってるのでドンピシャです。 手順も全く同じ経緯で原因の特定と解決ができました。

# yum search acme
読み込んだプラグイン:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: ftp.iij.ad.jp
 * epel: mirrors.aliyun.com
 * extras: ftp.iij.ad.jp
 * remi-safe: ftp.riken.jp
 * updates: ftp.iij.ad.jp
====================================================== N/S matched: acme ======================================================
acme-tiny-core.noarch : core python module of acme-tiny
python2-acme.noarch : Python library for the ACME protocol
acme-tiny.noarch : Tiny auditable script to issue, renew Let's Encrypt certificates
dehydrated.noarch : A client for signing certificates with an ACME server

  Name and summary matches only, use "search all" for everything.

python2-acme.noarch の更新が必要とのことで、epelからupdate

# yum --enablerepo=epel update python2-acme

依存性解決をしてアップデートができました。

再度以下のサイトを参考に本来の目的である、Let's Encrypt のTLS-SNI-01から http-01 方式への変更を行います。
Let’s EncryptのTLS-SNI-01認証のバリデーションに伴う対応策まとめ

本当に最新か確認

# certbot --version
certbot 0.29.1

現時点でリンク先のバージョンと同じなので、まず大丈夫でしょう。 そして

新しいバージョンの場合は自動的にHTTP-01の認証が実行されるようです。 とありますが、一応リンク先同様、 -dry-run オプションで更新テストをしてみます。

# certbot renew --dry-run --preferred-challenges http

出力内容

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/www.livelynk.jp.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator apache, Installer apache
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for www.livelynk.jp
Waiting for verification...
Cleaning up challenges
Resetting dropped connection: acme-staging-v02.api.letsencrypt.org

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed with reload of apache server; fullchain is
/etc/letsencrypt/live/www.livelynk.jp/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/www.livelynk.jp/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.

Performing the following challenges:

http-01 challenge for www.livelynk.jp

//中略

Congratulations, all renewals succeeded. The following certs have been renewed:

翻訳:おめでとうございます、すべての更新は成功しました。以下の証明書が更新されました。

という訳で無事完了。普段サーバーの設定関連は散々ググって悩んで解決するのですが、今回は皆が同じ対応を迫られている時期だったこともあり、とても簡単に問題が解決できました。良かった。

【輪読会資料】基礎から学ぶVue.js CHAPTER1 Vue.jsとフレームワークの基礎知識 読書メモ

以下の記事は2019/1/31 コワーキングスペース秋葉原Weeybleで行われる輪読会
[秋葉原] 基礎から学ぶVue.js輪読会 #初回 ch1 フレームワークの基礎知識(初心者歓迎!) のための読書メモとなります。
以下の書籍の CHAPTER1 Vue.jsとフレームワークの基礎知識 のメモです。

基礎から学ぶ Vue.js

基礎から学ぶ Vue.js

目次

  • CHAPTER 1 Vue.jsとフレームワークの基礎知識
    • 01 Vue.jsについて
    • 02 Vue.jsのキーコンセプト
    • 03 豊富なリソースを活用しよう
    • 04 Vue.jsのインストール
    • 05 Vue.jsの基本機能
    • 06 オプションの構成を見てみよう
    • まとめ

はじめに

書籍の為のがっつりしたサイトがあります!必見!!なんて手厚いサポート体制なんでしょう!
基礎から学ぶ Vue.js

書籍内のコードはまずここを参考にすると良いでしょう
基礎から学ぶ Vue.js コード&動作メモ

CHAPTER 1 Vue.jsとフレームワークの基礎知識

01 Vue.jsについて

Laravelのフロントエンドで採用されて今人気!色々アツい!
jQuery的な手軽さがあり、学習コストが低い
日本語ドキュメントが充実
フレームワークとの相性が良い

02 Vue.jsのキーコンセプト

データ駆動のしくみ
× DOMが存在してそれを読み込んで操作
○ 最初にデータが存在、そのデータに適したDOMを構築する

テンプレートを使う

<div v-if="show">Hello Vue.js</div>

v-ifは仮想DOMをつくるテンプレートの記法

<body>
    <div id="app"></div><!-- ここに配置できる -->
</body>

#app配置する要素とアプリケーションを紐づけることをmountと呼ぶ

データバインディング

データと描画を同期させる仕組み
生JSだと色々面倒だし管理も大変だけどVue.jsなら簡単

DOMの更新はフレームワークに任せよう

それを解決するのがデータでバインディング型のライブライリ、やフレームワーク
Vue.jsもデータでバインディングの多くの機能を持つHTMLを扱う感覚で機能を使用できる

v- からはじまるディレクティブ

htmlの属性にv-if,v-bind,key,等で始まるやつをディレクティブといい、データディバイングを行うために使われる。

<div key="id"></div><!-- 1 -->
<div v-bind:key="id"></div><!-- 2 -->

1,は単純に[id]という文字列を表す
2,はv-で始まるディレクティブJSの変数idで、正確にはアプリに登録されたidというプロパティになる
例外はあるがひとまず、v-で始まってなければ単なる文字列と考えて良い

コンポーネント指向の画面構成

1ファイルの中に例えば部品であるheader,main,footer毎のファイルを作る。その個別のファイル毎にHTML,CSS,JS を書いて管理する。
1ファイルの中にHTML,CSS,JS を書いて管理することもある。
さらに従来のcssの使い方としてポピュラーな方法である、共有コードを別ファイルまとめて書くこともできる。

コンポーネントが増えても大丈夫

コンポーネントはVue.jsのもっとも強力な機能
コンポーネントのネスト化、構造化が容易
複雑な構造化が必要な場合は以下の拡張機能等を導入するとよい

静的サイトジェネレート機能のあるVue.jsの拡張フレームワーク

  • Nuxt.js (Weeybleさんで輪読会やるらしいです)
  • VuePress

03 豊富なリソースを活用しよう

jQueryやBootstlapを使わずとも、Vue.jsに最適化されたコンポ―ネントUIがWebにたくさんあるらしい

Vue.jsと相性のいいライブラリ

代表的なコンポーネント

04 Vue.jsのインストール

  • この本の6章まではスタンドアローン版の「Vue.js」ファイルを使う
  • 開発モードで使う(非minファイルという)
  • 本番環境では「vue.min.js」に置き換えた最適化ファイルを使う

ダウンロード版もありますが、手っ取り早くCDN(コンテンツデリバリーネットワーク  htmlのheadタグ内にscriptとして読み込む1行を書く)の方が良いと思います。

ダウンロードの場合
Vue.js GET STANDARD > インストール(左メニュー) > 開発バージョン(ボタン)

CDNの場合 下記いずれかを使用htmlのheadに記述する。
学習では当然開発バージョン

<!-- 開発バージョン、便利なコンソールの警告が含まれています -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<!-- 本番バージョン、サイズと速度のために最適化されています -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

学習用のひな形ファイルを作る index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Vue.js App</title>
  <link href="main.css" rel="stylesheet">
</head>
<body>
  <div id="app">
    <!-- この#appの内側に色々なサンプルを書き込んでいく -->
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
  <script src="main.js"></script>
</body>
</html>

main.js

var app = new Vue({
  el: '#app'
})

これで適当なフォルダに保存したhtmlファイルをブラウザで開き、開発用コンソールを立ち上げる
chromeなら ctrl + shift + I

本にはないがcssも作った方が良い
main.css

body {
   /* ひとまず適当に書いて反映を確認してみる */
    color: blue;
}

さらにブラウザがchromeならこのような開発用の拡張機能をインストールすると便利そう
(但しlocalサーバー環境で無いと起動しない様です)
Vue.js devtools

05 Vue.jsの基本機能

htmlがわかる人なら簡単に扱えるそうです。

index.html 抜粋

  <div id="app">
    <p>{{ message }}</p><!-- ここに一行追加 -->
  </div>

main.js

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!'
  }
})

これでブラウザの画面にはHello Vue.js!が出力される

開発タブの Consoleに以下を入力すると…

console.log(app.message);

Hello Vue.js!と出力される

繰り返しの描画

一覧要素はdataオプションに登録され、そこに入れる配列やオブジェクトからv-forディレクティブで描画できる。

index.html

<ol>
  <li v-for="item in list">{{ item }}</li>
</ol>

main.js

var app = new Vue({
  el: '#app',
  data: {
    list: ['りんご', 'ばなな', 'いちご']
  }
})

開発用コンソールにapp.list.push('おれんじ')と入力すると、要素が追加できる。

1.りんご   
2.ばなな   
3.いちご   
4.おれんじ   

イベントの利用

クリックや選択要素が変わった際などのDOMイベントはv-onディレクティブを使う。
詳細はCHAPTER3
クリックするとhandleClickメソッドが呼ばれる例

index.html

<button v-on:click="handleClick">Click</button>

main.js

var app = new Vue({
  el: '#app',
  methods: {
    handleClick: function (event) {
      alert(event.target) // [object HTMLButtonElement]
    }
  }
})

ボタンが表示されクリックでalertがポップアップされるようになる

フォーム入力との同期

v-modelディレクティブを使用する
入力や選択で即時DOMに変更が反映される
詳細はCHAPTER3

index.html

<p>{{ message }}</p>
<input v-model="message">

main.js

var app = new Vue({
  el: '#app',
  data: {
    message: '初期メッセージ'
  }
})

フォームに入力した内容を編集するとmessage 部分に即反映されるのが確認できる

条件分岐

v-ifディレクティブを使用
詳細はCHAPTER2

index.html

<button v-on:click="show=!show">切り替え</button>
<p v-if="show">Hello Vue.js!</p>

main.js

var app = new Vue({
  el: '#app',
  data: {
    show: true
  }
})

showプロパティがtrueの際だけ<p>要素を出力する
コンソールにapp.show=false,app.show=trueと入力することでも表示の切り替えが出来る

トランジション&アニメーション

組み込みコンポーネント<transition>タグを使うと、CSSトランジションやアニメーションが使える
詳細はCHAPTER6

index.html

<button v-on:click="show=!show">切り替え</button>
<transition>
  <p v-if="show">Hello Vue.js!</p>
</transition>

main.js

var app = new Vue({
  el: '#app',
  data: {
    show: true
  }
})

main.css

.v-enter-active, .v-leave-active {
  transition: opacity 1s;
}
/* opacity:0から1へのフェードイン&フェードアウト */
.v-enter, .v-leave-to {
  opacity: 0;
}

ボタンを押す際にフェードアウト、フェードインでの表示切替アニメーション効果が適用される。

06 オプションの構成を見てみよう

基本的なオプションの構成

だいたいこんな感じらしいです。

var app = new Vue({

    // mountする要素
    el: '#app',
    // アプリケーションを紐づける要素のセレクタ

    // アプリケーションで使用するデータ
    data: {
        show: true
    }
    // `data`はアプリで使用するデータ、配列、オブジェクトが登録可能

    // 算出プロパティ
    computed: {
      computedMessage: function () {
        return this.message + '!'
      }
    }
    // `computed`関数によって算出されたデータ ここで処理した結果を返せる

    // ライフサイクルフック
    created: function () {  // created はすぐ実施される処理、他にも予約語がある。
      // 行いたい処理
    },
    // あらかじめ登録した処理を自動呼出しする`フック`と呼ばれる割り込み処理

    // アプリケーションで使用するメソッド
    methods: {
      myMethod: function () {
        // 行いたい処理
      }
    }
    // 処理の分割、細かな実装等で使う

})

created - ライフサイクルフック

あらかじめ登録した処理を自動呼出しするフックと呼ばれる割り込み処理が予約語でいくつかある。

ライフサイクルフック各種

メソッド タイミング
beforeCreate インスタンスが初期化されリアクティブの初期化がされる前
created インスタンスが初期化されリアクティブの初期化がされる後
beforeMount インスタンスがマウントされる前
mounted インスタンスがマウントされる後
beforeUpdate データが更新され、DOMに適用される前
updated データが更新され、DOMに適用される後
beforeDestroy Vueインスタンスが吐きされる前
destroyed Vueインスタンスが吐きされる後
errorCaptured 任意の子孫コンポーネントからエラーが補足されたとき

参考
Vue.jsのライフサイクルメモ

実施されるタイミングのダイアグラムは以下のリンク先を参照すると良いでしょう。
(書籍P48には日本語での同様の図がある)
Vue.jsのライフサイクルダイアグラム図

コラム要約

ちなみに、1行目にある new Vue() を実行するのは基本的に、操作したい全ての部品を包含している要素に対して1つだけ new Vue() を行う。
そこにコンポ―ネントとしてのUI部品を追加してゆくらしい

まとめ

  • Vue.jsではDOM構造の本体はJavaScriptのデータ
  • ディレクティブの値はJavaScriptの式になっている
  • HTMLコーディングの為にコンポーネントを使っても良い
  • 必要なデータやメソッドはオプションに定義してゆく
  • new Vue()は1つ作りコンポーネントでUIを構築する

Laravel本の輪読会を完走した

二か月以上毎週通ったLaravel本の輪読会が先日、最終回を迎えて完走出来ました。

weeyble-php.connpass.com

読んだのは以下の本

PHPフレームワーク Laravel Webアプリケーション開発 バージョン5.5 LTS対応

PHPフレームワーク Laravel Webアプリケーション開発 バージョン5.5 LTS対応

ここでの記事にもしましたが、書籍を毎回1章毎に、参加者のいずれかが担当となって、あらかじめ読み込んで場合によっては資料を書いてそれを元に担当者が解説してゆく、というスタイルです。

PHPフレームワーク Laravel入門

PHPフレームワーク Laravel入門

Laravelの基礎は上の青い本で学び、有志の日本語リファレンスやウェブのノウハウで覚えてきましたが、この本は、さらにその上を行く難しさを感じる様なハードな内容となっていて、おそらく一人で読んで実践していたら心が何度も折れて挫折していたと思います。

これまでプログラム関連のイベントはもくもく会や勉強会等にも通っていましたが、自分が積極的に学んでいるフレームワークの、より高い水準での知識やノウハウを毎回学びつつ、知識を共有できる場に通い、自分よりも多くの知識や技術を持った人に、なんでも質問できたという事は、普段個人でコツコツやっている自分にとって、とても貴重な時間となりました。

最初は担当者の方の話をひたすら聞いてなんとかついてゆくのが精いっぱいでした、実際2章、3章は今でも理解できない事が多く、もう一度読み込もうと思ってますが、4章以降は、実際にアプリを作った自分が見て既存の部分も多くありつつ、新たなノウハウもたくさん学べました。おそらくこの会を一番ありがたがり、最も得たものが多いという自信があります。(なんだそれ)

『9章 テスト』の輪読担当になった事で、マジにやらないとマズイ状況に自らを追い込み、自ら学び、説明できる所までなんとかもって行き、つたないながらも、何とか担当をこなす事が出来ました。
知識の習得は大変でしたが、説明するのは講師の経験が生きたかもしれません。

また、つい先日、最終章の『テスト駆動開発の実践』を事前予習して、いわゆるTDD(テスト駆動開発)を本の内容に基づいて実践してみましたが、これまでプログラミングをして行く上で何度かあった、パッと世界が開ける瞬間を、再び味わう事ができました。

この本は私個人はサンプルとなるソースコードから、暗黙的な筆者の方のメッセージを強く感じました。例えば『3章 アプリケーションアーキテクチャ』『5章 データベース』『9章 テスト』等では、簡単なアプリを実装した上での解説があるのですが、そもそもの本題ではないアプリケーションの書き方に、強いポリシーを感じるのです。

その理論の詳細や意図は実は3章で語られてはいるのですが、私はほとんど理解できてないと思います。ただ、意図の様なものは強く伝わって来る。
そしてこの様なコードの書き方でアプリケーションを作る事の真意が、最終章では体感として理解できるものになっていたのかもしれません。

最後の『テスト駆動開発の実践』ではこれまでこの本で語られたノウハウが全て詰まった状態で簡単なアプリを実装してゆくのですが、まるでゲームの最終面で各面のボスが再度一気に攻めて来るアレの様な感覚ながらも、それを理解しながら、テンポの良い開発をサクサク行い、これまでは理解出来なかった処理の細かな分離などの理由が身をもって体感できました。

それはつまりテスト前提の開発とメンテナンス性ゆえの処理の細分化なのだな、というのが身をもってわかるのです。これはとても快感でした。

しかし、この快感をしってしまうと、自分がこれまで作ったアプリがいかにメンテナンス性の悪い拡張し辛くテストし辛いものであるのか、というのも見えてしまい。自分の作ったものが、エラいヤバいモノに見えてきてしまうのです。
なのでついつい中身を全部作り変えたい衝動に駆られますが、そこはぐっと堪えて、ここで得たノウハウを元に最小のリソースで如何に効果的に安定したものを早く供給できるか、に集中しようと思っています。

しかし、この快感までに辿り付けた輪読会メンバーは残念ながらあまり多くはありませんでしたが、その分、なんとなくゆるい結束力のようなものは出来たかもしれないですね。

次回以降も引き続きVue.jsの輪読会が始まるので、今度はフロント側をリッチにするノウハウを身に付けたいと思います。引き続き新たな知識をどんどん身に付けて、より良いものを作りたい次第。

【感想】知らないと失敗する ソーシャルメディアの黄金法則

こんな本を読んだのでその感想をば。

知らないと失敗する ソーシャルメディアの黄金法則: ?たった一つのメソッドがコミュニティをイキイキさせる? (MyISBN - デザインエッグ社)

知らないと失敗する ソーシャルメディアの黄金法則: ?たった一つのメソッドがコミュニティをイキイキさせる? (MyISBN - デザインエッグ社)

  • 作者: 福岡秀幸,古田英一朗,リンクデザイン株式会社,伊藤みゆき
  • 出版社/メーカー: デザインエッグ社
  • 発売日: 2019/01/01
  • メディア: オンデマンド (ペーパーバック)
  • この商品を含むブログを見る

実は私もソーシャルメディアでコミュニティ的なものを運営した経験があるし、逆に様々なコミュニティに参加してきているが、そこでの共通する法則がうまく言語化されている本です。
概要としては短編小説の体でソーシャルメディアの専門家が対話形式でそのノウハウや法則について詳しく話してくれる構成となってます。
ウェブやリアルに関わらずコミュニティを運営していたり、人が集まる事を価値とする仕事や趣味で携わる人が読むと、とても納得できる様な事が書いてありました。

各章の終わりに本のタイトルにもある法則の要約が書かれているのですが、それをズバリ書いてしまうと、本を読む楽しみが減ってしまうので、個人的な超要約でまとめると以下の3項目に集約されるかもしれません。

  1. 自分が盛り上げようと頑張っても息切れしてしまう
  2. 人を繋げる、紹介する、という事に気を使う
  3. 悪い事が起こらない様、最低限の行動やガイドライン作りのみ行う

私自身がコミュニティを作って維持しようとした際を振り返ってみるとスタートダッシュの際に1,番を極端に頑張って途中で息切れしてしまい、結果として2, をおろそかにして、トラブルが起こった際に3,の方法を取らず、やはり頑張り過ぎて疲れちゃったんだな。というのを、振り返って気付いた次第。

じゃあ、どうすればいいの?という事がこの本には書いてあります。ただ、ページ数も100ページ程で少々物足りなさがあるかもしれませんし、もしかしたらちょっと肩透かしをくらう様な結論かもしれませんが、コミュニティを運営してゆく上での心構えみたいなものが集約されていて、沢山の人の集まりを主催する方や、維持する方にとってはとても良い本ではないかと思います。

実は著者の方は知り合いだったりして、裏話を伺うとこの本は数年以上前に書かれて寝かせていたものだそうで、当時は今より勢いのあったSNSというもののウェブ上のコミュニティ運営のノウハウをご自身の経験から集約したものとなっているそうです。
たしかこの執筆の前後あたりにギークオフィスを立ち上げて、普段はウェブでコミュニティのメンバーがゆるく繋がり、リアルな集まる場所としてのオフィス兼イベントスペースとしての、コミュニティを現在も運営されています。
今流行りのコワーキングスペースの走りみたいなもので、それよりももっと人のつながりを重視するコミュニティ寄りなものを5年以上前からしてるので、かなり時代の先取り感ありますよね。

長い事寝かせておいて、今になって発売に漕ぎつけたのは、実は表紙や中のイラストを描いてくれる方が、ギークオフィスのメンバーなったから、というのも面白いエピソードだと思います。

実はこのブログで紹介した、私が作った滞在者確認アプリはこの方のニーズから生まれたサービスで、今後はこのようなリアルとウェブが融合したコミュニティの価値や存在がもっと大事になって、このような場所から様々なイノベーションが生まれる筈、という見解をもっており、私も完全同意しています。そしてそれは、最近徐々に形になりつつある。

が、もし今またこのような本を書いたら、ギークオフィスをはじめとしたさまざまなコミュニティの新たな見解やノウハウが山の様に溜まっているので、もっと面白い視点で色んな話を読めるかもしれません。
本人をその気にさせる為にも上のリンクからポチっとするのも良いかもしれませんね。

windows vagrant Homestead環境でLaravelアプリを追加する際の覚書

最近windows環境でLaravelを複数追加することがおおくなったので、メモを兼ねて記述しておきます。変な所あったらコメントもらえると助かります。

気を付ける事

まず Homestead.yamlの設定とhostsの設定からおこない、windows側と仮想環境側のフォルダが共有状態になる様に設定が出来るまでがんばる。
これを後回しにして .envの設定やコードとか書いてしまっても、場合によってはフォルダ内のアプリまるごと行方不明になるので、要注意。

Homestead.yamlの設定

# 例えば一つ目のアプリが以下の様にあった場合
folders:
    - map: C:/Vagrant/larabook
      to: /home/vagrant/larabook

sites:
    - map: larabook.test
      to: /home/vagrant/larabook/chapter09/public


Homestead.yamlの設定 二つ目のアプリを追加

---
ip: "192.168.10.10"
# 省略

# こんな風に設定を追加する
folders:
    - map: C:/Vagrant/larabook
      to: /home/vagrant/larabook

# 追加
    # map がwindows側のフォルダ、 larabook_tdd フォルダを作る事
    # to は仮想環境側のディレクトリ やはり larabook_tdd を mkdirする
    - map: C:/Vagrant/add_app_name
      to: /home/vagrant/add_app_name

sites:
    - map: larabook.test
      to: /home/vagrant/larabook/chapter09/public

#追加
    # map はローカル環境で使いたいドメインを指定、.dev .app は設定しない方が良い
    # to は上同様仮想環境側のディレクトリだが、laravelアプリ内のディレクトリ publicまでを指定する
    - map: add_app_name.test
      to: /home/vagrant/add_app_name/public


hostsの設定

windows10の場合以下のファイルを編集する。
最初は読み取り専用だとおもうので、書き込みできるようにwindowsのプロパティ等で設定する。
C:\Windows\System32\drivers\etc\hosts

host ファイル内の最後の行に以下の様に追加
yaml の最初にあるIPとローカル環境で使用したいyamlに設定したドメインを入れる
#でコメント入れられるので、何で追加したかメモとして残しておくと良い

192.168.10.10       larabook.test        # vagrant Laravel study setting
192.168.10.10       add_app_name.test     #Add vagrant Laravel study setting

設定をしたらvagrant 立ち上げてない場合は以下のコマンド
vagrant up

立ち上げてた場合は以下のコマンド(ssh で入っていた場合はいったんexitしてからコマンド)
vagrant provision
変更したyamlの設定ファイルの状態で再度vagrant が動作しますので、windows側、仮想環境側、両方のフォルダを開けて、どちらかにtest様にフォルダなりファイルなりを入れてみてください。
設定が上手くいっていれば、片方に入れたファイルが、もう片方の環境にも反映されるはずです。
上手いかなかった場合は yaml の設定が誤っているか、設定が再度読み込まれていないので、再度確認して、修正してから、 vagrant provisonを行って上手く行くまで試してみてください。
個人的にはこの設定が苦手で何度もやり直すことが多いです。

ファイルが両方の環境で無事共有できるようになったら、laravelをインストールなり、リポジトリクローンなりをして、該当のフォルダ内にLaravelアプリを入れれば設定完了です。

Laravel5.6インストール

以下のコマンドを仮想環境の /home/vagrant で実行する(Laravel5.6を入れる場合)

composer create-project --prefer-dist laravel/laravel add_app_name "5.6.*"

そうすると、一つ下の先ほどmkdirしたフォルダ内 /home/vagrant/add_app_name にアプリがインストールされます。
インストールが終わったら、ブラウザで http://add_app_name.test にアクセスして、すっぴんのLaravelの画面が出れば、設定完了!

しかし、更新しちゃうとマズいファイルはちゃんとエディタで色分けされてない。どうもこのインストール方法だとGitフォルダは作られていないので、add_app_name フォルダ内に移動してからgit init した方が良いですね。.gitignoreファイルは既にあるので、Gitが適用されれば編集しちゃいけないファイルは開発用エディタなら、色が薄く表示されるはずです。
あとはwindows側でエディタを開いて編集してごりごり.envの設定して開発を始める感じです。

【輪読会資料】達人に学ぶSQL徹底指南書第2版 第二部後半 読書メモ

以下の記事は2019/1/16 コワーキングスペース秋葉原Weeybleで行われる輪読会
[秋葉原] 達人に学ぶSQL徹底指南書 輪読会 第2部 魔法のSQL(第2部 RDBの世界) のための読書メモとなります。
以下の書籍の 第二部 9 18 GROUP BY と PARTITION BY ~ 23 SQLにおける存在の改装 のメモです。

達人に学ぶSQL徹底指南書 第2版 初級者で終わりたくないあなたへ (CodeZine BOOKS)

達人に学ぶSQL徹底指南書 第2版 初級者で終わりたくないあなたへ (CodeZine BOOKS)


前提として

私のSQLスキルはMySQLを前提として基本的な知識のみで、書籍としてSQL本を読むのは、リファレンスを除いてこれが2冊目となります。まだまだ知らない事だらけ、という事を前提に以下のメモを読んでいただければ幸いです。

18 GROUP BY と PARTITION BY

GROUP BY と PARTITION BYは似てる、ということだが、そもそもPARTITION BYを使った事がなった。

GOROUP BY は分けたあとに代表だけ表示
PARTITION BY は分けた後にそのまま全て表示

しかし、この2つはいずれも『指定されたキーで分割をしている』という事らしい、違いはGROUP BY はキーで分割後に『集約してまとめる』操作が入る。
これらで集合されたものは以下の特徴を持つ

  1. いずれも空集合でない
  2. ずべての部分集合の輪が分割する前の集合一致
  3. 互いにことなる任意の2つの部分集合が共通部分を持たない

集合論的にはパッキリ割れるし余りや重複も出ない。完全な割り当てをしてくれる。

この集合部分のひと塊を『類(るい)』と呼ぶ


群論SQL

MODという除算の余りを出す関数がSQLにはある(PHPだと %)これを使って、多数のデータのランダムサンプリング、もしくは、ほぼ同等のデータに振り分けをすることが簡単にできるので、MODでの振り分けは覚えておくと良いかもしれない。

SELECT MOD(num, 3) AS modulo,
    num
FROM Natural
ORDER BY modulo, num;

3で割った際の余りの数で振り分けをした例

modulo     num
--------   -----
0             0
0             3
0             6
1             1
1             4
1             7
2             2
2             5
2             8
...

当たり前だが多数のレコードのあるテーブルのユニークID(抜け漏れなし)を特定の数の余りで振り分けると、ほぼ同じ数でのグルーピングが可能となる。


19 手続き型から宣言型・集合指向へ頭を切り替える7箇条

はじめに

SQLはプログラミングにある手続き型の言語ではなく、宣言・集合型言語である、ここはこの概念を理解し生かすための実践ガイドとする章。

1. IF文やCASE文は、CASE式で置き換える。SQLはむしろ関数型言語と考え方が近い

MySQLにあるIFはむしろ特殊、またCASEは文(手続き)ではなく、一種の関数(数式の方の意味)としてとらえる

2. ループはGROUP BY句とウィンドウ関数で置き換える

SQLには文単位のループも存在しない。

3. テーブルの行に順序はない

テーブルはファイルよりも抽象度が高い。テーブルのレコードを『ファイル』の様に捉えない、テーブルは数学の「集合(set)」の一種である。 ビューにORDER BY を入れても意味はない、Oracleのrownum の様な考えも特殊な仕様ととらえる。

4. テーブルを集合とみなそう

テーブルの抽象性を理解するには自己結合を使ってみると良い。自己結合を使うと、好きな数だけ、集合を追加し、操作することができる。

5. EXISTS述語と「量化」の概念を理解する

SQLを支える理論は集合の他にも『述語論理』がある。「複数行を一単位として」扱う際、述語理論では『量化子』だが、SQLではEXISTSとなる。 また、使いこなす必要があるのは NOT EXISTSの方が大事。読みづらいがパフォーマンスが格段に良い。

6. HAVING句の真価を学ぶ

WHEREと異なりSQL集合論としてとらえる事が出来るHAVING, をもっと活用しよう HAVINGの練習をすると知らず知らずに集合論の本質の理解が進むでしょう。

7. 四角を描くな、円を描け

SQLは手続きではない四角と矢印の手順図とは概念がことなり、ベン図(〇の中に〇が現れる図)として集合でとらえる事が重要

感想

俄然なにが筆者をここまで執拗にSQL集合論を書かせるに至ったのかに興味がわいてきた。


20 神のいない理論

SQLの元になる論理学の話。従来は真と偽になる2値原理の古典論理が、1920年代に新たな3値論理が生まれSQLに生かされたらしい。

汝、場合により命題の真偽を捨てよ

3値論理学の体形をはじめて作ったのはポーランドの論理学者J.ウカシェヴィッツ関数型言語ポーランド記法「3+2」を「+3 2」を考案した人
論理学で真偽の二つ以外にも、「わからない、未知」となる概念の存在を提案した。

論理学の革命

神、宗教が支配していた時代は神による論理が主となる、神は全てを知っており、全ての真偽を知っている。という思想から、2値原理を当然としていたが、人間は全ての真理を知らないし、神に全てを訪ねも答えてくれる訳ではないので、「知らない、未知」という状態を論理学として取り入れるべき、という流れが出て来た。そもそもこのような提案ができたのは、宗教による支配が弱くなった時代背景もある。

人間の為の論理

データベースを扱うのは神ではなく人間なので、人間の認知や知識を表現するのに適した論理である3価理論(NULL, unknown)が採用された。 しかし、皮肉にもそれによって、人間の直感に反する奇妙な論理計算を導入せざるを得なくなった。


21 SQL再帰集合

集合のなかに集合を含む入れ子の集合、「再帰集合」の扱いを知るのは重要という話。

実務の中の再帰集合

そもそもノイマンは何故自然数再帰集合で定義しようとしたのか?(P57)

ノイマンによる自然数帰納的定義

0 = ∅
1 = {0}
2 = {0, 1}
3 ={0, 1, 2}
...

ノイマンの先輩たち

ノイマン以前に自然数を集合で定義した数学者、哲学者がいる。
ゴットローブ・フレーゲ 哲学者 述語理論をほぼ独力で創始した
エルンスト・ツェルメロ 数学者 集合論の体系整備、整列可能定理と選択公理

それぞれの自然数の機能的定義

自然数 ノイマン ツェルメロ型 フレーゲ
0 {∅}
1 {∅} {∅} {∅,{∅}}
2 {∅,∅} {{∅}} {∅,{∅},{∅,{∅}}}
3 {∅,∅,∅} {{{∅}}} {∅,{∅},{∅,{∅}}{∅},{∅,{∅}}}}
...

疑問

  1. 自然数の定義がこんなにたくさんあっていいのか?定義というのは普通1つなのでは?
  2. 何で自然数の定義に「集合」を使おうと思ったのか?

数とは何か?

ペアノの自然数の5つの公理

  1. 最初の数が存在する
  2. 任意の自然数aはその後者が存在する
  3. 最初の数はいかなる自然数の後者でもない
  4. 異なる自然数は異なる後者を持つ
  5. 最初の数がある性質を満たし、aがある性質を満たせばその後者もその性質を満たすとき、すべての自然数はその性質を満たす

ある自然数の次を数える関数を、後者関数と呼び suc(x) とかく。

0 = 0
1 = suc(0)
2 = suc(1) = suc(suc(0))
3 = suc(2) = suc(suc(suc(0)))
...

ノイマンペアノの自然数の定義に見合う構成方法を考えたといえる。 これにより、自然数を構成する材料として∅を使う必要もなくなった。

0: λfx.x
1: λfx.fx
2: λfx. f(fx)
3: λfx.f(f(fx))

正直この辺までくるとちょっとよくわからない…

SQLの魔術と科学

ランキング算出のクエリの理屈にこういうものがある、と把握することによって世界が広がり理解が深まるのではないだろうか?


22 NULL撲滅委員会

実務に置いて厄介なNULLにどう対処していけばよいかの指針を提案している

決意表明~スベテノDBエンジニアニ告グ~

(デザイナーにおけるIE死ね死ね団的なノリノリである) NULLは人間の感覚的にはわかりやすく設計段階でついついいれてしまうが、システムが複雑化するととても厄介なものになる。そこでここではより具体的な提案をまとめた章となっている。

なぜNULLがそんなに悪いのか   

  1. SQLのコーディングにあたり、人間の直感に反する3値論理を考慮しないといけない
  2. IS NULL , IS NOT NULL を指定する場合、インデックスの利用に制限が入りパフォーマンスが低下する
  3. 四則演算またはSQL関数の引数にNULLが含まれると「NULLの伝播」が起こる
  4. SQLの結果を受け取るホスト言語において、NULLの組み込み方が標準化されていない。また、DBMS間でもNULLの扱いに関する仕様が不統一
  5. 通常の列の値と異なり、NULLは行のどこかに余分なビットを持つことで実装されている。記憶領域の圧迫や検索パフォーマンス悪化の要因となる。
  6. NULLを含むカラムに作成するユニークインデックスの「ユニーク」の意味がRDBMSで異なる。例:複数のNULLを含む列にユニークインデックスを作成する際、エラーになったりならなかったり。
  7. NULLは値ではない為、ORDER BY 句によるソートの際のルールを意識する必要がある。NULLは定義含まれないが、実際は最大値か最小値として扱われ、実装によってデフォルトが異なるのでややこしい事になる。

もっとも忌むべき理由は1.
また3.も厄介 四則演算にNULL が入ると計算結果がNULLとなってしまう。
4~7は仕様違いによる厄介さ

しかしNULLを完全に排除することはできない

しかし、実務では『重要でない列にNULLが入ってくるのは目をつむる』位が実際の運用でのルールになっている。
カラムの制約でNOT NULL をしたとしても、外部結合や CUBE,ROLLUP付きのGROUP BY句を使うとNULLが入り込んでしまう。

コッドさんはNULL撲滅の最右翼、著者もそこに近い所に行きたい心情ではあるが、エンジニアの現実感覚として以下の方針を提案している

NULLは薬、用法容量を守って使う。使わざる得ない時のみに使う

次からは具体的なNULL排除の指針を提案してゆく

コードの場合ーー未コード化用コードを割り振る

true,false の様な2つの値のみ入るレコードは3つ目の値、未定義などに、NULLではなく、数字を当てはめると良い
例えば性別
1:男性 2: 女性 3:未知 9:適用不能 といった具合

例えばここに人ではなく、企業アカウントとしてレコード登録する際は 9:適用不能 を選択させる コッドの提案した『未知』と『適用不能』を値として設ける方法。

また、不明なレコードを入れなければならない場合、例えば数値として9999を入れるのではなく、そのカラムでは普段は使わない文字列 XXXX などを使うと良いだろう。 9999 という数字を持つユーザーが実際に存在する可能性があるなら数値は避けるべき。

名前の場合ーー「名無しの権兵衛」を割り振る

不明を表すデフォルトの値を入れると良い『不明』『UNKNOWN』など開発チーム内で共通了解の取られたものを入れると良い

数値の場合ーー0で代替する

NULLを0に変換してDBへ登録すると良い。筆者が実務で困った事は経験上あまりないらしい。
しかし、どうしても0とNULLを区別したい時だけNULLを許可すると良い。

日付の場合ーー最大値・最小値で代替する

日付が開始日や終了日を意味する場合は「0001-01-01」「9999-12-31」等の最大値、最小値を使うと良い。
しかし、デフォルト値がそもそもわからない誕生日など「未知」のNULLに相当する場合はNULLを許可しても良いでしょう。

指針のまとめ

  1. まずデフォルト値を入れられないか検討する。
  2. どうしようもない場合だけNULLを許可する。

というのが筆者の指針となる。


23 SQLにおける存在の階層

GROUP BY を使って集約をすると、集約キーを除いて、元のテーブルの列をそのまま参照できなくなるが、これは存在の階層を厳密に区別するSQL理論の現れ、ここからSQLの本質にせまる。

述語論理における階層、集合論における階層

P84 EXISTS述語の使い方を復習 EXISTSは高階関数である
2階 テーブルの集合
1階 テーブル(行集合)
0階 行

実はGROUP BY 句はEXISTS同様に階層がある。

なぜ集約すると、もとのテーブルの列を参照できなくなるのか?

以下の様なテーブルがあり、チームごとの平均年齢を出すクエリを考える

Teams

member team age
大木 A 28
逸見 A 19
新藤 A 23
山田 B 40
久本 B 29
橋田 C 30
...
SELECT team, AVG(age)
 FROM Tems
GROUP BY team;

これはちゃんと出力されるが、 次のはエラーになる。

-- チーム単位に集約するクエリ?
SELECT team, AVG(age), age
 FROM Tems
GROUP BY team;

理由はSELECT句に追加されたage 列を選択する事が出来ない為。 標準SQLではテーブル集約をした際、SELECT句に書ける要素は以下となる。

  1. GROUP BY句で指定した集約キー
  2. 集約関数(SUM, AVGなど)
  3. 定数

上記のエラーになったクエリの場合、 age は集約できない個人の年齢を差している。 個人の年齢は集約された際の「集団についての属性」ではない、当たり前だが、集団の統計属性なら出力できるが、個人は出力できない。と考えると良い。 過去のMySQLでは特別に可能だったが8.0以降ではやはりエラーになる様になった

GROUP BY で集約を行うと、SQLが扱う「行」という0階の存在から、「行の集合」という1階の存在に変化するため、「行」の属性は参照不能となる。

つまり、GOROUP BY で集団化されたものに、個人の〇〇を訪ねても駄目、という風に解釈すると良い。

もし、上記のクエリで名前を尋ねたい、とするなら仮に以下の様に MAXのmemberを求めるしかない

-- 正常
SELECT team, AVG(age), MAX(member)
 FROM Tems
GROUP BY team;

このクエリを応用すると「チームでの最高齢の年齢の人物」を求めるクエリも書ける。

-- チーム最高齢者も出力
SELECT team, MAX(age)
    (SELECT MAX(member)
      FROM Teams T2
      WHERE T2.team = T1.team
      AND T2.age = MAX(T1.age)
    ) AS oldest
FROM Tems T1
GROUP BY team;
team   max(age)    oldest
------   ----------   ---------
A         28              大木
B         40              山田
...

通常、WHERE句で集約関数は使えないが、このサブクエリ内では使える。MAX(T1.age) 理由は外側のT1テーブルを集約(1行目の MAX(age)かな? )したことによって、SELECT句集約関数が参照可能になる為。 その代わり今度は逆にサブクエリ内で age を裸で利用することはできない。つまり集約したルールはサブクエリと外のクエリで合わせなら利用できる。という事らしい。

単元集合も立派な集合です

GROUP BYをする際、そもそも、元のレコードでも1要素しかないものを集約した場合、どう動くか? (例となるTeamテーブルにはCチームに1メンバーのみのレコードがある)

実はこれも1単位でも1グループとして扱う。やはり階が0階から1階上がるという事、なので注意しましょう。ということ。