CYDAS Developer's Blog

サイダス技術者ブログ

サイダスの技術部にジョインしました、湯です

はじめまして。エンジニアの、湯です! 以下は社内でシェアしている私のトリセツです。

どんな問題に対するソリューションが得意か

フロントエンドとNodejs関連のこと。

そのソリューションについてどの程度エキスパートか?(経験者上位何%など)

経験者上位何%かは難しいところですが、前々職での実績値は上位 50%頃 です。

上司となる人に期待すること

  • 性格がいい。
  • 新しいことにチャレンジしていること。

同僚に対してあなたができる(できそうな)こと

私にできそうな事があれば、なんでも気軽にご相談ください。

同僚となる人に期待すること

チームで助け合う気持ちを持っていること。

ワークライフバランスについてどういう考えを持っているか

健康な生活、楽しい仕事。

リモートワークについてどういう考えを持っているか

今までリモートワークをやったことがないけど、やってみたい。

1年後どのような職業人でありたいか

  • 日本語が上手になる、同僚とよく交流できる。
  • 自分の得意技術は新入社員に教えたい。

3年後どのような職業人でありたいか

プロジェクトのリーダーになりたい。

Cloud Native Developers JP - Serverless で発表してきた

サイダス吉田真吾@yoshidashingo)です。

昨日開催された Cloud Native Developers JP(cndjp) の第11回勉強会でサーバーレスの話をしてきました。 cnd.connpass.com

前回ここに来たのはおそらく7年前のJPOUGの初期の頃のイベントで DataPump について話したときでした。非常に懐かったです。資料は以下のとおりです。

【イベントレポート】PHPerKaigi 2019 に参加してきました!

こんにちは!エンジニアのこぶかた@kobuuukata)です!

3/29〜3/31に行われたPHPerKaigi初参戦してきました!

本記事は、本編1日目のみの参加でしたので1日目のレポートになります。

PHPerKaigiとは?

PHPerKaigi(ペチパーカイギ)はPHPのカンファレンスイベントです。

phperkaigi.jp

今回、仕事でPHPを使っているということもあり、これは行くっきゃない!ってことで参加してきました!

セッション

私が聞いたセッションをいくつかまとめておきます。

PhpStorm30分集中超絶技巧:山本裕介さん

ちょうど仕事でもPhpStormを使っているのですが、普段5つくらいしかショートカットを使っていませんでした。。こんなに便利なショートカットがあるんだ!と初めて知ることばかりでとても勉強になりました。会場にいるPHPerからも、お〜!とどよめきが起こるくらいでした。
早速使いこなせるように練習しようと思います!

設計力を上げるバリエーションの見極め術:77webさん

条件ごとにif文書いたりしてませんか?というお話にギクリ。
ビジネスの変化が起こるところにはバリエーションが必要で、そのバリエーションを行うには予測することが必要!とのことでした。
「いいソースの書き方は去年のPHPerKaigiで後藤さんの資料を参考にしてね」と言われたので、探したのが2つ目の資料です。


サーバーレスPHP:角田一平さん

PHPはLambdaの言語としてまだ対応してないですが、Lambda Layerを使ってPHPを動かしたというお話でした。
Symfony(フレームワーク)よりも、bref(フレームワーク)の方が簡単に導入できたそう。どちらも初めて聞いたフレームワークなので、今度試してみようと思います!
質疑応答では、「Pythonで良くないですか?」という質問に会場がざわついてました笑

PHPerのための計算量入門:富所亮さん

計算量には時間計算量(演算回数)と空間計算量(メモリ使用量)の2つがあり、今回は時間計算量について。
計算量によってプログラムの実行時間に大きく影響するよということで、in_arrayとarray_key_exsistで実行時間を比較した結果のグラフにはびっくりでした!でも、in_arrayが何でもかんでも悪いという訳ではなく、計算量が違うので上手に使い分けることが大事だそうです!


その他のセッション資料はこちらにまとめられていますのでご覧ください!

qiita.com

PHPerチャレンジ

会場内や配布物、Twitterなどに隠された「PHPerトークン」を探して、forteeというイベントサイトにトークンを入力して得られたスコアを競う企画でした。

その中でも「徳丸 浩の挑戦状」これがすごく面白かったです!
アプリから脆弱性を見つけてトークンを探し出すというものでした。
f:id:aym413:20190401210943j:plain:w300

※現在はアクセスできません

最初は何をしたらいいのか全くわからなかったのですが、一緒に参加していた同僚と協力して最終的には4つ見つけることができました!
脆弱性について全然詳しくなかったので、今回のPHPerチャレンジで楽しみながら脆弱性についても勉強することができてとてもよかったです!

解答はこちらのブログで解説してくれています。
www.ryotosaito.com

トークンは全部で5つだったようで、あと一歩でした!悔しい!!
セッションの空き時間もこのチャレンジに挑戦していたので、有意義に過ごすことができたのでとてもよかったです!

初めて参加してみて

  • メインのセッション以外にも参加者が楽しめる内容が豊富だった!
  • 質疑応答では司会者の方が登壇者の方に「質問に回答する前に質問内容を復唱してください」との案内があり、とても参加者に配慮されていると感じた
  • 開発初心者だったので、知らないツールやフレームワーク、開発する際の考え方などを知れるいい機会だった
  • ノベルティが豪華!(バッグ、Tシャツ、ノート型のホワイトボードなどなど)
  • もう少し充電スペースがあったらよかったなぁ
  • スマホの充電もなくなりかけたので、モバイルバッテリーは必須

【Go言語】 構造体、スライス、マップ、ポインターの組み合わせで割とつまずく

こんにちは。もうすぐ終了するGoogle+に未だに投稿するよく訓練されたGoogle信者の長谷川です。

今回はGo言語の話。Go言語は最近では珍しいポインターがある言語です。
ポインターというとC言語初心者がつまずく鬼門とされて忌み嫌われてる感がありますが、メモリの使用量を抑えて高速化するにはやっぱりポインターがあると有効です。
そうはいってもちょくちょくポインター関連でやらかします。特にスライス、マップ、構造体が絡むとよく失敗するんでここで書き留めておきます。

配列は実体、スライスはポインター

Goでは配列とスライスがありますが扱いが異なります。
配列は値がコピーされますが、スライスはポインターとして扱われます。

package main
import "fmt"

func main(){
    ar := [3]string{}
    sl := make([]string, 3)
    mp := make(map[int]string, 3)

    setFunc(ar, sl, mp)
    fmt.Println(ar) // [  ]
    fmt.Println(sl) // [star  ]
    fmt.Println(mp) // map[0:sun]
}

func setFunc(ar [3]string, sl []string, mp map[int]string) {
    ar[0] = "moon"
    sl[0] = "star"
    mp[0] = "sun"
}

ついでにmapも比較してます。
スライス、マップは変更内容が反映されてますが、配列は変更内容が失われます。

スライスはポインターだけではない

しかし、スライスはポインターとしてアドレスを持っていますが長さとキャパシティーの要素も持っており、これらは変更が反映されません。

// 省略
func main() {
    sl := make([]string, 3)
    sl[0] = "uno"
    fmt.Println(len(sl), cap(sl), sl) // 3 3 [uno  ]

    setFunc(sl)
    fmt.Println(len(sl), cap(sl), sl) // 3 3 [uno due tre]
}

func setFunc(sl []string) {
    sl[1] = "due"
    sl = append(sl, "quatro") // appendは反映されない
    sl[2] = "tre"

    fmt.Println(len(sl), cap(sl), sl) // 4 6 [uno due tre quatro]
}

関数内でappendしてスライスを拡張してますがその内容は失われています。

for文で取得した要素はコピー

あと構造体のスライス操作しようとしてやってしまうんですが、for文で取得した値はコピーなんで反映しません。 ポインター関係ないですね。

// 省略
type Person struct {
    name string
    age  int
}

func main() {
    persons := make([]Person, 3)
    setFunc(persons)
    fmt.Println(persons) // [{ 0} { 0} { 0}]
}

func setFunc(persons []Person) {
    for _, p := range persons {
        p.name = "fool"
        p.age = 1
    }
  // そもそもスライスには反映しない
    fmt.Println(persons) // [{ 0} { 0} { 0}]
}

インデックス指定して操作すればいいんですけどね。

for i := range persons {
  persons[i].name = "fool"
  persons[i].age = 1
}

mapではキー指定で操作できない

しかし、これもmapだとできません。

// 省略
func main() {
    persons := map[int]Person{
        1: Person{},
        2: Person{},
        3: Person{},
    }
    setFunc(persons)
    fmt.Println(persons)
}

func setFunc(persons map[int]Person) {
    for key := range persons {
        // ここがエラーになる
        persons[key].name = "fool" // cannot assign to struct field persons[key].name in map
        persons[key].age = 1 // cannot assign to struct field persons[key].age in map
    }
}

他の言語の連想配列みたいにkeyで指定してメンバーにアクセスしようとするとエラーになってコンパイルが通りません。
下のように一旦コピーした構造体にセットしてmapに戻すという方法もありますが、

for key, p := range persons {
  p.name = "fool"
  p.age = 1
  persons[key] = p
}

操作するならそもそもポインターのmapのほうが間違えないし処理的にも負荷が少なくなります。

func main() {
    persons := map[int]*Person{
        1: &Person{},
        2: &Person{},
        3: &Person{},
    }
    setFunc(persons)
    fmt.Println(persons[1]) // &{fool 1}
    fmt.Println(persons[2]) // &{fool 2}
    fmt.Println(persons[3]) // &{fool 3}
}

func setFunc(persons map[int]*Person) {
    for k, p := range persons {
        p.name = "fool"
        p.age = k
    }
}

それならスライスのほうもポインターのスライスにしたほうがいいんじゃないかという気がします。
大きい構造体ならいちいちコピーしないで操作できたほうがいいですよね。

それではよいGoライフを!

【AWS SAA合格への道】RDS

AWS ソリューションアーキテクト - アソシエイト合格に必要な知識をまとめていきたいと思います!
今回は「RDS」になります。

RDS(Relational Database Service )

フルマネージドなデータベースサービス

  • OSへログインして操作することはできない
  • IPアドレスを固定することはできない(DNS名による接続)

マルチAZ

ハードウェア障害などが発生した場合自動的にフェイルオーバーし、耐久性の向上や可用性の向上を実現できる。

f:id:aym413:20190313231558p:plain
マルチAZ配置のイメージ

  • マスターとスレーブ間は同期レプリケーション が行われている(マスターはスレーブにデータ更新が反映されるのを待つ)
  • 2台分の料金がかかるので、費用が高くなる
  • フェイルオーバー時、エンドポイントの切り替えは不要
  • スレーブ側のDBインスタンスにはアクセス不可
  • バックアップの取得はスレーブ側から行われるので読み書き操作は停止しない
フェイルオーバーが発生タイミングは以下の3つ
  • インスタンスやハードウェア障害
  • パッチ適用などのメンテナンス時間
  • 手動リブート時に強制フェールオーバーするよう設定していた場合

リードレプリカ

読み込み専用のデータベース

f:id:aym413:20190313233112p:plain
リードレプリカの作成イメージ

  • マスターとリードレプリカ間は非同期レプリケーションが行われている(マスターはスレーブにデータ更新が反映されるのを待たない)
  • 参照が多いアプリケーションの場合に使用することでパフォーマンスが向上する

バックアップ

RDSの標準機能により、自動で1日1回フルバックアップ+トランザクションログを取得できる

  • 自動バックアップにより、ポイントインタイムリカバリが利用できる
  • 任意のタイミングでバックアップを取得することも可能
  • マルチAZに比べ、安価にデータ復旧が可能

ポイントインタイムリカバリ

自動バックアップにより任意の時点までRDSを復元することができる

  • マネジメントコンソールの「最新の復元時間」として表示されている時刻まで復元可能

その他のDBサービス

DynamoDB

NoSQLのデータベースサービス

利用用途

  • メタデータの保存
  • JSON ドキュメントの保存
  • セッション情報

Redshift

データウェアハウスサービス

利用用途

  • 大量のデータの集計と分析

ElastiCache

インメモリキャッシュサービス

利用用途

  • セッション情報
  • キャッシュ

【AWS SAA合格への道】VPC

AWS ソリューションアーキテクト - アソシエイト合格に必要な知識をまとめていきたいと思います!
今回は「VPC」になります。

VPC(Virtual Private Cloud)

AWS上に仮想ネットワークを構築できるサービス

f:id:aym413:20190305172237p:plain
VPC作成イメージ

  • 単一リージョン内に作成する(リージョンをまたいで作成することはできない)
  • 他のVPCとは論理的に切り離されている
  • VPCのサイズ(CIDRブロック)は変更不可

ネットワーク

サブネット

VPCをさらに分割したネットワーク空間

f:id:aym413:20190306204318p:plain
サブネット作成イメージ

  • 単一AZ内に作成する(AZをまたいで作成することはできない)
  • サブネット内で利用できるIPアドレスは最初4つ最後1つのアドレス(合計5つ)はAWS側で予約されているため、使用不可
  • サブネットのサイズ(CIDRブロック)は変更不可
  • サブネットは1つのルートテーブルに紐付ける必要がある(複数のルートテーブルに紐付けることはできない)

パブリックサブネットとプライベートサブネットの違い

サブネットを作成する際の設定として、
「パブリックサブネットを作成する」や「プライベートサブネットを作成する」といったものはありません!
パブリックサブネットなのか、プライベートサブネットなのかを判断するのはサブネットに紐付くルートテーブルによって変化します。
詳細は「ルートテーブル」にて説明します。

インターネットゲートウェイ

VPC内のEC2とインターネット間の通信を可能にする

f:id:aym413:20190306205024p:plain
インターネットゲートウェイ作成イメージ

  • インターネットゲートウェイはVPCに紐付ける必要がある
  • ルートテーブルにインターネットゲートウェイのルートを追加する必要がある

ルートテーブル

ネットワークトラフィックの経路を判断する際に使用される

  • VPCを作成するとルートテーブルが1つ作成される(メインルートテーブル)
  • メインルートテーブルはサブネットを特定のルートテーブルに明示的に関連付けなかった場合に、暗示的に関連付けられる
  • ルートテーブルは追加で作成することができる(カスタムルートテーブル)
  • 同一VPC内の通信はデフォルトで許可されている

f:id:aym413:20190307232242p:plain
パブリックサブネットとプライベートサブネットの違い

この図が示す「10.0.0.0/16:local」はVPC作成時に指定したVPCのネットワーク範囲を表しています。 つまり、VPC内で行われる通信はこの「10.0.0.0/16:local」を使用することになります。

「0.0.0.0/0 : インターネットゲートウェイ」はデフォルトルートと呼ばれ、全ての経路を示します。

  • 0.0.0.0/0 : インターネットゲートウェイを持つルートテーブルが紐づいたサブネット
     →パブリックサブネット
  • 0.0.0.0/0 : インターネットゲートウェイを持たないルートテーブルが紐づいたサブネット
     →プライベートサブネット

VPC内のEC2とインターネット間の通信ができるための条件

  • インターネットゲートウェイがVPCと紐付けられていること
  • ルートテーブルにインターネットゲートウェイへのルートが含まれていること
  • VPC に関連付けられているセキュリティグループが、インターネット間とのトラフィックを許可していること
  • VPC 内のEC2は、パブリック IP アドレス または Elastic IP アドレスのいずれかを持っていること

NATゲートウェイ

プライベートサブネットに配置されたEC2からインターネットへ通信(アウトバウンド)は許可したいが インターネットからの通信(インバウンド)は許可したくない場合に利用

f:id:aym413:20190307232333p:plain
NATゲートウェイ作成イメージ

  • NATゲートウェイはパプリックサブネットに配置
  • プライベートサブネットに紐付くルートテーブルにNATゲートウェイを追加

セキュリティ

ネットワークACL

サブネットに紐付くファイアウォール

  • デフォルトで全ての通信は許可されている
  • 戻りの通信も明示的に許可する必要がある(ステートレス)
  • 記載された番号の小さい順にルールが適用される

セキュリティグループとの違い

f:id:aym413:20190307231531p:plain
ネットワークACLとセキュリティグループの違い

セキュリティグループの特徴についてはこちらの記事でも説明しています。 tech.cydas.com

VPC Flow Logs

VPC内のIPトラフィックの監視が行える

PHP5系 から 7系に上がって出来なくなること

こんにちは。技術部の金尾です。
PHPといえば良くも悪くもゆるい書き方を許してくれる大らかな言語ですが、7系以降では お行儀のわるい書き方には(以前よりは)厳しくなりました。
廃止されたものやルールが変わった部分もあるのでまとめておきます。

split関数の廃止

split関数が廃止されました。以降はpreg_splitexplodeを使う必要があります。

<?php
// 呼び出しても undefined
var_dump( split(',', '1,2,3,4') );
//=> Fatal error: Uncaught Error: Call to undefined function split() in ...

// explode などに置き換えましょう。
var_dump( explode(',', '1,2,3, 4' ) );
//=> array(4) {
  [0]=>
  string(1) "1"
  [1]=>
  string(1) "2"
  [2]=>
  string(1) "3"
  [3]=>
  string(2) " 4"
}

E_STRICT 通知の深刻度の変更

PHP7以降から E_STRICT 通知が廃止されました。それに伴い今まで E_STRICT だったものは E_NOTICE E_WARNING E_DEPRECATED のいずれかに変更になります。E_ALL & ~E_STRICT でひとまず非表示にしておく、ということができなくなったのでその場合対応が必要です。
いくつかある変更対象のエラーのなかで、比較的うっかりやりがちな Signature mismatch during inheritanceOnly variables should be passed by reference について取り上げます。

Signature mismatch during inheritance

オーバーライドしたメソッドのシグネチャが継承元と異なる場合、E_WARNING エラーが発生します。

<?php
class Hoge {
    public function method(){
        return 'hoge';
    }
}

class ChildHoge extends Hoge {
    // 親の method とは異なる引数を指定してオーバーライド
    public function method($foo){
        return 'hoge' . $foo;
    }
}
//=> Warning:  Declaration of ChildHoge::method($foo) should be compatible with Hoge::method() in ...

Only variables should be passed by reference

引数に参照渡しを要求している関数にメソッドの戻り値を直接渡すと E_WARNING エラーが発生します。 array_poparray_shiftなどを使用する際には注意が必要です。

<?php
// 関数の戻り値を直接渡しては×
var_dump(array_pop( explode(',', '1,2,3,4') ) );
//=> Notice:  Only variables should be passed by reference in ...

// 一度変数に格納すればok
$hoge = explode(',', '1,2,3,4');
var_dump(array_pop($hoge));
//=> string(1) "4"

変数やプロパティ、メソッドへの間接的なアクセスの扱いの変更

$$foo['bar']$foo->$bar['baz'] といった、
変数やプロパティ、メソッドへの間接的なアクセスを厳密に左から右の順で評価するようになりました.

PHP5 PHP7
$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz']
$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']
$foo->$bar'baz' $foo->{$bar['baz']}() ($foo->$bar)'baz'
Foo::$bar'baz' Foo::{$bar['baz']}() (Foo::$bar)'baz'

このため可変変数や可変メソッドを使用するときには5.x系とは異なる挙動をすることがあります。

<?php
class Foo {
    public function bar(){
        echo "bar";
    }
    public function baz(){
        echo "baz";
    }
}
$arr = ['bar' => 'bar', 'baz' => 'baz'];

// PHP5.x系では $arr['bar'] が先に評価されていたが、
// PHP7.x系では (new Hoge)->$arr が先に評価されるためとエラーになる。
(new Foo)->$arr['bar']();
//=> Notice:  Array to string conversion in ...
//=> Notice: Undefined property: Foo::$Array in ...

// 波括弧を使用して $arr['bar'] を先に評価するよう指定すればok
(new Foo)->{$arr['bar']}();
//=> "bar"

無効な文字列による算術演算の通知

PHP7.1以降、数値形式ではない文字列を使って算術演算を行おうとしたときに E_WARNING あるいは E_NOTICE エラーが発生するようになりました。キャストしてくれることをいいことにうっかり空文字を0として扱ってしまうとバンバン Warning エラーが出ます。

  • E_NOTICE になるケース 数字で始まり、数値以外で終わる文字列のときに発生
    Notice: A non well formed numeric value encountered in ...

  • E_WARNING になるケース 数値が含まれない文字列のときに発生
    Warning: A non-numeric value encountered in ...

<?php
var_dump("0" + 1);
//=> int(1)

var_dump("01" + 1);
//=> int(2)

var_dump("" + 1);
//=> Warning:  A non-numeric value encountered in ...

var_dump("1m" + 1);
//=> Notice:  A non well formed numeric value encountered in ...

var_dump("m1" + 1);
//=> Warning:  A non-numeric value encountered in ...

var_dump("1m" + ""); 
//=> Notice:  A non well formed numeric value encountered in ... 
//=> Warning:  A non-numeric value encountered in ...