デブサミ2019関西に行ってきたのでだいぶ雑な感想を

雑な上個人的な話ばかりでレポート的な感じではないので、そういうのを求めてる人には以下などのほかの人のレポートがおすすめ。

以下、見たセッションと雑な感想。

【B-1】心理的安全性の構造

かなり期待していたセッションだがちょっと雑な感じだった。期待しすぎていたかもしれない。スライド見る感じ、あきらかに「時間が余ったらする話」以下が本題なので、前半飛ばしてそっちやってくれていたら。

【B-2】新規事業を支える文化と加速させる技術~DevOps/GCP/DDD~

新規事業を文化と技術でうまくやっていくみたいな話だったかな。ちょっと焦点がぼやけてはいた。B-1やこれ見てると、チーム開発もしてみたくなった。

【C-3】生産性を上げる新しい役割「業務ハック」とは?

なんで選んだのか覚えてない程度の期待だったが、かなりよかった。業務ハックってコンピュータ使わない(とは限らないが使うことが必須ではない)プログラミングだと思う。

【C-4】非テック企業でも出来る!テクノロジーでHRを牽引する組織作りと案件事例~機械学習・ブロックチェーンetc~

昼食ちょい後のタイミングのせいかちょっと眠かった。すまん……。採用周りの話は非常に興味深かった。採用する側ではなく採用的なことをされる側として。

【C-5】エンジニア組織づくり5年。見えてきた関西Web界隈のええとこ、あかんとこ

とにかくスピーカーの話のうまさが際立っていた。エンジニア採用の難しさ的な話は興味深い。C-4同様この辺はされる側視点だけど。

【C-6】CI/CDを使い倒して数段上のソフトウェア開発をしよう!

CircleCIの人による話だけどCircleCIの話はほぼなかった。一般的なCI/CDの話だけど、詳しくない俺にはかなりまとまっていてよかった。

セッション選んだ時点ではCI未経験だったけど、選んでからデブサミまでの間にCircleCI既存のCIをちょっとどうこうしたのと、GitHub Actionsをちょっと試していた。で、GitHub Actionsいいじゃんとなってたけど、このセッションでちょっとCircleCIもちゃんと比較しなきゃなあとなった。

なおもらった資料にCircleCIとJenkinsの比較してるところがあって、これもけっこうわかりやすいのでよかった。今後GitHub Actionsとの比較も出してくれないかなあ。

【C-7】ぶっちゃけ儲かるの? アウトプットするエンジニア大集合LT!

これがほんと楽しかった。技術同人誌的なの書きたいなあという思いはあって、じっさいちょっと手を出してたりするのもあって銭けっとの人の話が特に気になってたけど、そういう期待とは別次元の話でこの人の話力と存在感がやばかった。

最初にこの人出して大丈夫かと思ったけど大丈夫だったので後続の方たちもすごかった。

やっぱアウトプット大事だよねー、と思いつつ、基本ブログで断片的な技術情報書くだけで、そこから仕事につながったことなんてないし、ただ出すだけでは駄目だよねとも。

今の案件かなり忙しくてなかなか時間取れない(割にあちこちでかけてはいるんだが)ので、終わってからになりそうだけど、またちょっとちゃんとしたもの書いていきたい。ブログはどうしても雑に断片だけ書いて、それで理解できる人だけ理解してくれとなるんだよね。

総括

心残りとして、Lifematicsの人が募集してたモブプログラミングの勉強会への参加を迷ってたらセッションぜんぶ終わってブースも閉じてて、というのがあって。ほかのブースも見れなくて、途中トイレも行けなくてだるかったので、次行くときは1セッション犠牲にしてブースやら見ようかなと。

あとは参加証印刷いるとか、筆記用具いるとか、資料入るサイズのバッグいるとか、その辺を次行くときは忘れないようにしたい。

そういえば前回も一応感想ブログ書いてた。具体例が欲しいって前回から言ってたのか。自分がなにか人に話すようなことがあれば、その辺しっかりやるようにしよう……。

デブサミ2018関西行ってきたのでセッションの感想など - 遠い叫び

CentOS 7でCircleCI CLIでDockerがエラーを出す場合

こんなエラー。

% sudo circleci local execute --job build
Docker image digest: sha256:359227b82618c1ce0514da6b1ee0c05f60863601b8078b1907fe6917f3e5593a
====>> Spin up Environment
Build-agent version 1.0.15410-75b89bda (2019-09-13T15:43:07+0000)
Docker Engine Version: 1.13.1
Kernel Version: Linux 38934e5cbd31 3.10.0-957.27.2.el7.x86_64 #1 SMP Mon Jul 29 17:46:05 UTC 2019 x86_64 Linux
Error:
Unexpected environment preparation error: error connecting build-agent to ephemeral network: error connecting build-agent container to ephemeral network: Error response from daemon: No such container: docker-38934e5cbd3129668b05d985f6a45a08bb878e283a0acc11b5d125fdde800b43.scope

Step failed
Task failed
Error: Unhandled prepare executor error: error connecting build-agent to ephemeral network: error connecting build-agent container to ephemeral network: Error response from daemon: No such container: docker-38934e5cbd3129668b05d985f6a45a08bb878e283a0acc11b5d125fdde800b43.scope

Dockerのバージョンが古いだけかも。CentOS 7のBaseリポジトリに入ってるのは使ってはいけない。Docker公式にあるドキュメント見て入れよう。

Get Docker Engine - Community for CentOS | Docker Documentation

Goでis-a関係を作る

Goには継承はなく、実装の再利用は構造体の埋め込みで行う。じっさいは委譲だが、見た目はオブジェクト指向言語で継承した場合のように使える。

package main

type Super struct {}
func (super Super) SuperMethod() {}

type Sub struct {Super}

func main() {
    sub := Sub{Super{}}
    sub.SuperMethod() // Subから直接Superのメソッドを実行できる
}

ただしこれだと当然is-a関係にはならないため、以下のようにSuperを要求する関数でSubは使えない。

package main

func RequiresSuper(super Super) Super {
    return super
}

type Super struct {}
func (super Super) SuperMethod() {}

type Sub struct {Super}

func main() {
    sub := Sub{Super{}}
    sub.SuperMethod()

    super := RequiresSuper(sub) // コンパイルエラーになる
    super.SuperMethod()
}

sub.Superを渡すことで済む場合もあろうが、当然それはSuper型の変数となってしまうので、今度はSubのメソッドを実行できない。

package main

func RequiresSuper(super Super) Super {
    return super
}

type Super struct {}
func (super Super) SuperMethod() {}

type Sub struct {Super}

func main() {
    sub := Sub{Super{}}
    sub.SuperMethod()

    super := RequiresSuper(sub.Super) // ここを変更
    super.SuperMethod()
    super.SubMethod() // コンパイルエラー
}

どうするか。インターフェイスを使う。SuperSuperInterfaceを満たすようにし、Superを直接でなく、SuperInterfaceを要求するようにする。

package main

func RequiresSuper(super SuperInterface) SuperInterface {
    return super
}

type SuperInterface interface { SuperMethod() }

type Super struct {}
func (super Super) SuperMethod() {}

type Sub struct {Super}
func (sub Sub) SubMethod() {}

func main() {
    sub := Sub{Super{}}
    sub.SuperMethod()
    sub.SubMethod()

    super := RequiresSuper(sub)
    super.SuperMethod()
    super.(Sub).SubMethod() // とはいえ、SuperInterfaceはSubMethod()を当然持っていないので、ここではどうしても型表明が必要になる
}

ここまで辿り着くのにかなりかかった。

PHPで例外を出力するときにわざわざgetMessage()を使う必要はない

たまに見かけるので。

こんな感じにすれば__toString()が自動的に呼ばれる。エラーメッセージとスタックトレースの両方がついたいい感じの出力になる。

<?php

function a() {
    throw new Exception("test");
}

try {
    a();
}
catch (Exception $e) {
    echo $e;
}
exception 'Exception' with message 'test' in /tmp/vw50zKH/28:4
Stack trace:
#0 /tmp/vw50zKH/28(8): a()
#1 {main}

文字列コンテキストになっているか不安な場合は、"$e"とすれば安心。

getMessage()スタックトレースがないし、getTraceAsString()は逆にメッセージがない。そもそもどちらもファイル名・行数に関する表示はない。加工してrethrowするような場合以外は、__toString()相当がおすすめ。

Nginxで権限があるはずなのにポートをバインドできない

ちょっと必要があって、Nginxを8000番で動かそうとしたらなぜかエラーが出た。1023までのポートならともかく8000だし、そもそもroot権限で動かしてるのに。

nginx: [emerg] bind() to 0.0.0.0:8000 failed (13: Permission denied)

Permission deniedと来たらseLinuxかなとaudit.logを見てみる。

type=AVC msg=audit(1564721070.008:4043): avc:  denied  { name_bind } for  pid=26994 comm="nginx" src=8000 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:soundd_port_t:s0 tclass=tcp_socket permissive=0

やっぱり。semanageというコマンドで許可できるっぽいが入ってない。yum providesして調べる。policycoreutils-pythonというパッケージに含まれてるとのこと。

sudo yum install policycoreutils-python

するとインストール済みと出る。なぜ。

sudo yum reinstall policycoreutils-python

で入ったっぽい。で、8000ポートをHTTP扱いに。

sudo semanage port -a -t http_port_t -p tcp 8000

すると、

ValueError: Port tcp/8000 already defined

ほかで使われているようだ。

sudo semanage port -l | grep 8000
# soundd_port_t                  tcp      8000, 9433, 16001

-mだと追加できるぽい。

sudo semanage port -m -t http_port_t -p tcp 8000

WindowsでMercurialが死んでた件

5.0.2で以下のようなエラーが出た。Python 3が別途入ってたからそのせいかと思ってPATHいじったりアンインストールしてみたりしたが駄目。

仕方ないので一応安全そうなところから4.9.1をダウンロードして入れてみたら動いたっぽい。

ちなみにChocolateyで定期的に自動アップデートしてる上、Mercurial自体も手動ではもう使っていないので気付くのがだいぶ遅れた。気をつけないと。

$ hg
Traceback (most recent call last):[2019-07-29 19:58]
  File "hg", line 43, in <module>
  File "hgdemandimport\demandimportpy2.pyc", line 150, in __getattr__
  File "hgdemandimport\demandimportpy2.pyc", line 94, in _load
  File "hgdemandimport\demandimportpy2.pyc", line 43, in _hgextimport
  File "mercurial\dispatch.pyc", line 22, in <module>
  File "hgdemandimport\demandimportpy2.pyc", line 248, in _demandimport
  File "hgdemandimport\demandimportpy2.pyc", line 43, in _hgextimport
  File "mercurial\i18n.pyc", line 28, in <module>
  File "hgdemandimport\demandimportpy2.pyc", line 150, in __getattr__
  File "hgdemandimport\demandimportpy2.pyc", line 94, in _load
  File "hgdemandimport\demandimportpy2.pyc", line 43, in _hgextimport
  File "mercurial\encoding.pyc", line 24, in <module>
  File "mercurial\policy.pyc", line 101, in importmod
  File "mercurial\policy.pyc", line 63, in _importfrom
  File "hgdemandimport\demandimportpy2.pyc", line 164, in __doc__
  File "hgdemandimport\demandimportpy2.pyc", line 94, in _load
  File "hgdemandimport\demandimportpy2.pyc", line 43, in _hgextimport
  File "mercurial\cext\parsers.pyc", line 12, in <module>
  File "mercurial\cext\parsers.pyc", line 10, in __load
ImportError: DLL load failed: %1 は有効な Win32 アプリケーションではありません。

しかしググってももうMercurialの情報がろくに出てこなくてね、つらい……。

Laravelでドキュメントルートに静的ファイルを混在させる方法

作ったシステムに後から静的ページを追加したい、みたいな要望にどう対応すればいいだろうか。「有料です」で済ませたいところだが、なかなかそうも行かない場合も多い。

古のCGI/PHP環境でやってきたクライアントにとっては、既存のファイルと無関係なところにファイル/ディレクトリを追加することができないのはなぜ、となってしまうのもまあ仕方ないのかもしれない。

そういうときどうするか。

LaravelのデフォルトのApache/Nginxの設定では、ファイルが存在する場合はそちらを読み込むようになっているので、単純にpublicディレクトリにファイルを置けばそちらを優先してくれるが、publicディレクトリは普通Git管理下にあるので、勝手にいじられたくない。1

解決法は、publicディレクトリをドキュメントルートのサブディレクトリなどに置いて触らないよう伝えた上で、ほかは勝手にしてください、とすることだろうか。

ということで、ドキュメントルートにpublic/.htaccessベースの.htaccessを置いて、URL上ではルートで動かしながら、じっさいのファイルはドキュメントルートのサブディレクトリに置くようにしてみる。

以下ではサブディレクトリ名はpublicとする。

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # ここから追加 {
    RewriteCond %{REQUEST_URI} ^/$
    RewriteRule ^ public/index.php [L]

    RewriteCond %{REQUEST_FILENAME} !-f # これがあれば、ドキュメントルート直下の同名ファイルを優先できるがなくてもいい。
    RewriteCond %{DOCUMENT_ROOT}/public%{REQUEST_URI} -f
    RewriteRule (.*) public/$1
    # } ここまで追加

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ public/index.php [L] # ここも変更
</IfModule>

なおこれだけでは、https://example.com/public/への直アクセスが防げない。いい方法が思い付かなかった。思い付いた人いたら教えてください。


  1. デプロイ方法にもよる。リンクでなく一方向のコピーであれば、上書きさえしなければ問題ない。