スタイル・エッジLABO技術ブログ

士業集客支援/コンサルティングのスタイル・エッジグループ スタイル・エッジLABOのエンジニアによるブログです。

ちょっと周りで話題になったので、JavaScriptのthisについて改めて調べてみた

こんにちは、スタイル・エッジLABOのOです。今年の4月でついに3年目になりました。
最近業務中に、「JSで書いたはずのfunctionがnot definedになってとれない」と話が出まして、調査したところthisが悪さをしていたということがありました。

f:id:styleedge_tech:20200706092021j:plain
どうして。。
今となっても少しややこしいthisについて、今回書こうと思います(一人でも救われるように。。)。

JavaScriptのthis

JavaScriptを書く中で、個人的にどツボにハマる四天王として、
・this
・バブリング(イベント伝播)
・ホイスティング(宣言の巻き上げ)
・エラー文の意味のわからなさ(もはや愛嬌)
があります。
(prototypeとかもあったなあと書きながら)

今回は、この中でもとくにやっかいなthisについてです。
JavaScriptのthisはざっと4種類存在します。
・メソッド呼び出しのthis
・関数呼び出しのthis
インスタンス化時のthis
・bindするときのthis

メソッド呼び出しのthis

let obj = {
 val: 'hoge',
 fn: funcion () {
  console.log(this.val);
 }
};
obj.fn(); // hoge

このタイプのthisは、イメージ通り fn が定義されているオブジェクトを指します。

関数呼び出しのthis

let obj = {
 val: 'hoge',
 fn: funcion () {
  function fn2() {
    console.log(this.val);
  };
  fn2();
  console.log(this.val);
 }
};
obj.fn(); // undefined  hoge

そもそも関数とメソッドの違いは、定義されている場所です。
関数はグローバル空間に、メソッドはそのメソッドが書かれているオブジェクト(ローカル)に定義されます。
function hoge()と定義した時点で、それが例えオブジェクトのメソッド内であろうがグローバルに定義されます。
JavaScriptはそれ自体がObjectの塊なので、 定義されているオブジェクトをthisが指すという意味では根本的には一緒です。
グローバル空間に val というプロパティは存在しないので、例はundefinedになります。

インスタンス化時のthis

function Hoge(val) {
  this.val = val
  this.fn = function () {
   console.log(this.val);
  }
}
// インスタンス化
let foo = new Hoge('hoge');
foo.fn(); // hoge
// 関数呼び出し
Hoge('hoge'); // hoge
console.log(val); // hoge

インスタンス化した時は、thisはそのインスタンスを指しますが、もちろんそのまま呼んでしまえば関数呼び出しです。
this.val がグローバル空間に定義されるので、例の一番最後の val が hoge になっていると思います。
インスタンス化を想定したオブジェクトを定義する時は、最初の文字を大文字にしておくのが慣例のようです。

bindするときのthis

let hogeObj = {
 this.val: 'hoge',
 fn: function () {
  console.log(n);
 }
}
let fooObj = {
 this.val: 'foo';
}
hogeObj.fn(); // hoge
hogeObj.fn.call(fooObj) // foo

applyとかcallを使うときの第一引数にオブジェクトを指定することで、thisとして扱えるというものです。
便利ですが、わかってないで使うとひどい目にあいます(実体験)。

この応用に、htmlなどで使用するイベントリスナーからイベントを発火させるときのコールバックのthisがあります。

<button type="button" id="hoge">ボタン</button>
function hoge() {
 console.log(this);
}
document.getElementById('hoge').addEventListener('click', hoge);

イベントリスナーのコールバックとして呼ばれたときの関数でのthisは、そのリスナーの貼られているDOM(例でいうbutton)がthisとしてbindされます。
もし、ボタンを押した場合は、
<button type="button" id="hoge">ボタン</button>
がコンソールに表示されます。
前書きの、「JSで書いたはずのfunctionがnot definedになってとれない」という話は、これが原因でした。

以上が、JavaScriptのthisでした。

アロー関数

() => {} // こういう

同じ関数でも、アロー関数は少しthisの挙動が異なります。
アロー関数は、thisをbindしません。
つまり、

<button type="button" id="arrow">arrow</button>
<button type="button" id="normal">normal</button>
let obj = {
 hoge: function (e) {
  console.log(this);
 }
 foo: e => console.log(this);
};
document.getElementById('normal').addEventListener('click', obj.hoge);
document.getElementById('arrow').addEventListener('click', obj.foo);

というように定義したとき、hoge()とfoo()を発火させると以下のようになります。

obj.hoge(); // {hoge: ƒ, foo: ƒ}
obj.foo(); // グローバル(ブラウザだと、windowオブジェクト)

ブラウザで各ボタンを押すと、

<button type="button" id="arrow">arrow</button> // thisはグローバル(windowオブジェクト)
<button type="button" id="normal">normal</button> // thisは <button type="button" id="normal">normal</button>

になります。このように、アロー関数はどの位置で呼ばれてもグローバルをthisとします。

まとめ

今回は、JavaScriptのthisについてまとめてみました。
こういった部分をちゃんと理解するとJavaScriptはもっと面白くなりそうですね!
機会があったら他のどツボにハマる四天王についても根掘り葉掘り調べたいです。

スタイル・エッジLABOでは一緒に働く仲間を募集しております。 興味をお持ち頂けましたら是非とも下記をクリックしてください↓↓

recruit.styleedge-labo.co.jp

スタイル・エッジLABOにおけるローカル制度のご紹介

こんにちは!
スタイル・エッジLABOでマネージャをしています、オーです。
今回は、弊社LABOにおけるユニークな各種ローカル制度についてご紹介します。

f:id:styleedge_tech:20200619065555j:plain
イメージ

LABOでは、エンジニアの働きやすさの向上を通して、技術をより楽しみ、エンジニアライフを謳歌することにつなげていきたいと考えています。

その為に、いくつかLABOではローカル制度や取り組みがあります。

今回は、その3つをご紹介します。

ストレッチDAY

エンジニアはとてもとても忙しい...(ですよね)
日々スケジュールだの、進捗だの、に追われる中だと、ローカル開発環境の整備、便利ツールの自作願望、ドキュメントの更新、ずっと試したいまま出来ていないソフトウェアアップデートなどなど
ちょっとしたことで、気持ちよく効率的よく業務につながる対応を、先送りにして、なかなか時間をとることが出来ない...!といったことがあるかと思います。

その問題に対して、LABOでは毎月1日だけ「スケジュールや進捗から離れ、業務に関連する細々系のものを集中して対応」できる日として、ストレッチDAYという制度があります。

こうした日を明示的に設けることで、業務に心置きなく集中できるようで、メンバーからの評判も上々です。

まどろ眠

仕事をしているとどうしても、疲れが溜まったり、単調な内容だったり、お昼はお腹いっぱい食べた後だったりして・・・(言い訳はいくらでも)眠くなることありますよね?

そんなときに、恐ろしい顔でディスプレイを睨んでないで、思い切って眠ってしまって、すっきり切り替えて仕事に戻ってもらったほうがよい!という想いから、1日20分間だけの睡眠休憩(お昼時間とは別に)を許可する制度、まどろみ+睡眠ということで、まどろ眠という制度があります。

わりと皆使っていますね..笑

ナレッジ共有会

エンジニアたるものインプットも大事ですが、アウトプットはもっと大事!
でもアウトプットの場ってなかなか無い...というのが現実だと思います。
アウトプットすることで、組織としてのナレッジの共有にもなりますし、なによりの本人の知識定着やモチベーションUPにつながっていきます。

LABOでは、月2回を目安にLABOメンバー全員の前で任意のテーマで発表する会、すなわち「ナレッジ共有会」というものをかれこれ2年以上続けています。

あくまでも社内にはなりますが、気軽にアウトプットする場として活用してもらっています。

おわり

以上、スタイル・エッジLABOならではの3つの制度のご紹介でした。

今回ご紹介させていただいた制度は、すでに1年以上の実績があるものですが、LABOでは一度作っておしまいではなく(ソフトウェアも)、制度も含め、日々必要に応じてどんどんバージョンUPしています。

紹介しきれませんでしたが、他にも、たとえば、ベテランも若手も新卒も一緒になって自分たちの開発ルールを作る「開発標準委員会」の定期開催、毎年12月に行われる技術アウトプットの祭典「社内Adventカレンダー」の実施などなど・・各種試みがあります。

そういった取り組みが、LABOで働くエンジニアにとって各自のやりがいや幸せにつながり、結果として、会社としてもよりよいアウトプット創出につながればと考えています。

スタイルエッジ・LABOでは一緒に働く仲間を募集しております。 興味をお持ち頂けましたら是非とも下記をクリックしてください↓↓

recruit.styleedge-labo.co.jp

Rainbow CSV と RBQL で快適CSV生活

はじめに

こんにちは!スタイル・エッジLABOのSです。 今回は最近の私の相棒であるRainbow CSVについてご紹介させていただきます。

よくVisual Studio Codeおすすめの拡張機能として取り上げられるこちらの拡張機能ですが、 恥ずかしながら私、つい最近まで「CSVを見やすく色付けしてくれるプラグイン」くらいにしか思っていませんでした。

最近CSVのようなテキストデータを取り扱う機会が多くなり、 軽くて楽に扱えるエディタ(もしくはビューワー)はないものかと探していたところ…

あれ?これもしかして…使える?

ということで、あらためてRainbow CSVの公式サイトを読んで使ってみました。

Rainbow CSV

今回ご紹介させていただくのはVisual Studio Code拡張機能ですが、 Rainbow CSVプラグインは、AtomSublime Text、Vimなどに対応したものもあります。 お使いのエディタに合わせたプラグインをご利用ください。

marketplace.visualstudio.com

なお、本稿ではサンプルデータとして、日本政府が公表している国勢調査CSVを用いています。

www.e-stat.go.jp

利点1:CSVが見やすい

カラムごとに色をつけてくれるだけでもずいぶんデータが見やすくなりますが、 同じようなデータが並んでいたりすると、「あれ?これ何の項目だっけ?」とヘッダを確認したり、カンマの数を数えたり、、、

そんな不毛な作業とはこれでさようなら!

ヘッダレコードを含むCSVであれば、マウスオーバーでヘッダテキストを表示してくれます!

f:id:styleedge_tech:20200501164800p:plain
マウスオーバーでHeaderが確認できます

でも、ヘッダレコードを含んでいないCSVもありますよね。

そんな時は仮想のヘッダを定義することができます。

コマンドパレットを開いて「Rainbow CSV: Set Virtual Header」を選択します。

f:id:styleedge_tech:20200507071402p:plain
Set virtual header

カンマ区切りで、ヘッダとして設定したい文字列を入力します。

f:id:styleedge_tech:20200507071518p:plain
ヘッダとして設定したい文字列を入力します

そうすると、先ほどと同じように、マウスオーバーでヘッダテキストを表示してくれるようになります。

f:id:styleedge_tech:20200507072401p:plain
ヘッダのないCSVもマウスオーバーでHeaderが確認できます

半角データのみのファイルであれば、align機能も便利です。

ただし、元のファイルに変更が加えられてしまうため、誤って保存しないように注意が必要です。

align機能を使うには、先ほどと同様にコマンドパレットを開いて「Rainbow CSV: Align CSV Columns」を選択します。

f:id:styleedge_tech:20200507072023p:plain
align機能を使うとカラムごとに整列して表示されます

データの文字数に応じて半角スペースでパディングされるようで、残念ながら全角を含んでいると少しずつずれてしまいますが、この程度であれば十分に見やすくなりますね。

利点2:カラムの全選択ができる

コマンドパレットを開いて「Rainbow CSV: Column edit select」を選択します。

すると、すべてのレコードに対して、いまキャレットの置かれているカラムを選択状態にしてくれます。

f:id:styleedge_tech:20200507074942p:plain
カラムがすべて選択状態になります

しかし(本当に)残念ながら10000行以上のデータではこの機能は使えません。

Multicursor column edit works only for files smaller than 10000 lines.

利点3:RBQLが使える

RBQLというSQLに似たクエリを用いて、CSV内のレコード検索や集計、編集操作を行うことができます。

この機能のおかげでデータの抽出やログの解析がめちゃくちゃスムーズになりました。

RBQL Consoleは、Visual Studio Code左下の[Query]をクリックするか、コマンドパレットを開いて「Rainbow CSV: RBQL」を選択することで起動します。

f:id:styleedge_tech:20200507082132p:plain
RBQL Console
RBQLについて、詳しくお知りになりたい方はこちらをご覧ください。

rbql.org

RBQLの例

select * where a1 == '01' (fromはなく、比較には=ではなく==を使います)

where

RBQLでは、利用する言語としてJavaScriptPythonを指定できます。 どちらの言語を利用するかによって、クエリの書き方が変わるので注意が必要です。 (最初はこれでずいぶん悩みました)

例えば、次のクエリはPythonではエラーなく実行されますが、JavaScriptではエラーになります。

where a1 == '01' and a2 == '0〜4歳'

これはクエリが選択した言語(JavaScriptまたはPython)として解釈されるためです。

この解釈については前述のRBQLのページの「How RBQL works: Explanation」をご覧ください。

よって、JavaScriptでandやorを使いたい場合には、&&や||のように書く必要があります。

select * where a1 == '01' && a2 == '0〜4歳'

以下、特に断らない限りクエリはJavaScriptで記述します。

like

likeは関数として実装されています。

30代を抽出

select * where like(a['年齢5歳階級'], '3%')

関数の利用(JavaScript/Python

関数を使ってデータを操作することも可能です。

select * where a['都道府県名'].indexOf('府') > -1

select

カラムは、a1, a2, ...のようにインデックスで指定したり、 a['都道府県コード'],a['都道府県名'],...というように、項目名(ヘッダテキスト)によって指定することができます。 項目名による指定では、"a["と入力するだけで候補が出てくるため、リストから選択することができます。

そのほかに、NRという行番号を表すカラムがあって、これを利用すると元のファイルから該当行を探す手間が省けるので便利です。

group by

select a['都道府県名'], a['西暦(年)'], sum(a['人口(総数)']) group by a['都道府県名'], a['西暦(年)'] where NR > 1

1行目はヘッダ文字列のためsumできないので除外しています。

order by

select * order by parseInt(a['人口(総数)'])

文字列として解釈されてしまうのを防ぐために、parseInt関数を用いています。

join

別のファイルとjoinすることもできます。 joinするファイルのカラムは、b1, b2, ... で指定します。

select * inner join ファイルパス on a1 == b1

update

update a['元号'] = 'T' where a['元号'] == '大正'

ちなみに、selectの結果やupdateの結果は別ファイルとして別タブに表示されるため、誤って元データを編集してしまうということもありません。 その結果に対してさらにRBQL Consoleを立ち上げてクエリを実行することも可能です。

また、copy backという機能が用意されており、これを使えば、編集結果を元データに書き戻すことも可能です。(Visual Studio Code左下のcopy backボタン)

おわりに

いかがでしたでしょうか?

RBQLを使えば、他のアプリで開くと重くなってしまうようなデータも比較的サクサク扱うことができますし、 CSVCSVのまま取り扱うことができるのも良いですよね。 普段から起動してあるお気に入りのエディタ上で実行できるのも魅力です。

これでデータを扱う作業が捗ること間違いなしですね!

スタイルエッジ・LABOでは一緒に働く仲間を募集しております。 興味をお持ち頂けましたら是非とも下記をクリックしてください↓↓

recruit.styleedge-labo.co.jp

UptimeRobotを使ってお手軽ネットワーク監視生活

はじめに

はじめまして! スタイル・エッジLABOのTAKと申します

突然ですが皆さん、個人でWebサービスを公開してて気付いたらサービス落ちてた…なんて経験、あると思います

個人で立ち上げたサービスとはいえ、たまに利用してくれる人もいるし落としたまま気付かないの申し訳ないな…でもサービス監視ツール導入したり、それを通知する準備するの大変そうだし…
って中々やれていない人、いるんじゃないでしょうか?
そう!数か月前の私のように!

そんな方へ私からオススメするのが、ネットワーク監視ツール「UptimeRobot」です!

続きを読む

ブラウザ操作を「脚本家」に任せてみよう

はじめに

お初にお目にかかります。スタイル・エッジLABOの┣(読み: てぃー or てー)と申します。
今年からこちらにお世話になり、やっとのことDockerやLaravel等に慣れてきて、ただいまこうなっております↓

f:id:styleedge_tech:20200311075644j:plain
寝落ちカバ by フリー素材ぱくたそ(www.pakutaso.com)


ですが今回はそれらではなく、つい最近知ったブラウザテストツール「Playwright」について書き留めます。

Playwright #とは

前述のとおり、マイクロソフトが開発した「ブラウザ操作を自動化するためのNodeライブラリ」です。
ブラウザテストツールをご存じの方であれば「Puppeteerに近いもの」……という表現の方がわかりやすいかもしれません。
(そもそも「元Puppeteerの開発チームが開発した」とのことです)

Playwrightの利点

というわけで使用方法も内部的な構造もPuppeteerがベースになっているように見受けられますが、
Playwrightは下記のように「クロスブラウザ対応が容易」と感じました。
Webkitのパッケージ依存解決が大変すぎて心が折れました・・・

  • 標準でクロスブラウザ対応している
  • ブラウザを切り替えやすい
    • Puppeteer・・・モジュールごと切り替える

      const puppeteer = require('puppeteer');
      const pptrFirefox = require('puppeteer-firefox');
      
      (async () => {
        for (const pptr in [puppeteer, pptrFirefox]) {
          const browser = await pptr.launch();
          // 省略
        }
      })();
      


    • Playwright・・・パラメータ指定で切り替える

      const playwright = require('playwright');
      
      (async () => {
        for (const browserType of ['chromium', 'firefox']) {
          const browser = await playwright[browserType].launch();
          // 省略
        }
      })();
      


概要は以上です。
以下、学習用に実際にやってみた内容となります。

実際にやってみた

お題

今日のニュースをGoogle検索し、1ページ目の内容をCSVにまとめる

前提
  1. Docker for Windows(Docker Desktop 2.1.0.5) を使用する想定です。
    他の環境では未検証のためご了承ください。
  2. ゲストOSは┣がDebian系のディストリビュージョンに不得手なため、CentOSとさせて頂きます。
  3. 主な流れはコメントとして記載致しますが、各メソッドの挙動等につきましては特に触れません。
事前準備

  • docker-compose.yml

    version: "3.3"
    
    services:
        playwright-sample:
            container_name: playwright-sample
            build: .
            tty: true
            volumes:
                - .:/src
    


  • Dockerfile

    # 最新版のブラウザが動作しなくなるので常に最新イメージとする
    FROM centos:latest
    LABEL  maintainer "├"
    
    # 各種パッケージ インストール本体
    RUN curl -sL https://rpm.nodesource.com/setup_12.x | bash \
        && dnf install -y \
            # Node.js、日本語対応に必要なパッケージ
            nodejs-12.14.1-1nodesource.x86_64 glibc-locale-source \
            glibc-langpack-en glibc-langpack-ja wget unzip fontconfig \
            # ブラウザの動作に必要なパッケージ
            libX11 libXcomposite libXcursor libXdamage libXext \
            libXi libXtst cups-libs libXScrnSaver libXrandr \
            alsa-lib pango atk at-spi2-atk gtk3 \
            firefox \
        && rm -rf /var/cache/dnf/* \
        && dnf clean all
    
    # playwright インストール
    RUN npm i --no-save playwright
    
    # 日本語対応・・・キャプチャを取得する場合は必須
    # (最新版のCentOSはdnf installできない模様、今回はキャプチャを取得しないためコメントアウト)
    # RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
    # ENV LANG="ja_JP.UTF-8" \
    #     LANGUAGE="ja_JP:ja" \
    #     LC_ALL="ja_JP.UTF-8"
    # RUN wget https://ipafont.ipa.go.jp/IPAfont/IPAfont00303.zip \
    #     && unzip IPAfont00303.zip \
    #     && mv IPAfont00303 ipafont \
    #     && rm -f ipafont/*.txt \
    #     && cp -r ipafont/ /usr/share/fonts/  \
    #     && fc-cache -f \
    #     && rm -rf ipafont IPAfont00303.zip
    
    # 作業ディレクトリ
    WORKDIR /src


スクリプト本体

  • example.js

    // ブラウザの種類とオプション
    const browsers = {
        chromium: {
            args: [
                // root権限で実行するために付与
                '--no-sandbox',
                '--disable-setuid-sandbox',
            ]
        },
        // firefox: {},     // firefoxで実行する場合はこちら
    };
    
    // 待ち合わせの設定(ドキュメント読み込みまで待つ)
    const waitOption = { waitUntil: 'domcontentloaded' };
    
    // ヘッダ行
    const header = '"タイトル","内容","URL"\r\n';
    
    // 検索ワード
    const word = '今日のニュース';
    
    // playwright 実行
    const playwright = require('playwright');
    const fs = require('fs');
    (async () => {
        for (const browserType in browsers) {
            // 1. ブラウザ起動
            const browser = await playwright[browserType].launch(browsers[browserType]);
            const context = await browser.newContext();
    
            // 2. googleへ遷移
            const page = await context.newPage();
            await page.goto('https://www.google.com/', waitOption);
    
            // 3. 検索
            await page.type('[title="検索"]', word);
            await Promise.all([
                page.keyboard.press('Enter'),
                page.waitForNavigation(waitOption),
            ]);
    
            // 4. ニュースタブを開く
            await Promise.all([
                page.click('[href*="tbm=nws"]'),
                page.waitForNavigation(waitOption),
            ]);
            await page.waitFor(1000);       // ページが描画されるまで適当に待つ
    
            // 5. 検索結果を取得
            const result = await page.$$eval('.ts > div', els => {
                return els.map((el) => {
                    const label = el.querySelector('a');
                    const content = el.querySelector('.st');
                    return `"${label.innerText}","${content.innerText}","${label.href}"`
                }).join('\r\n');
            });
    
            // 6. 検索結果をファイル出力
            fs.writeFileSync(`${word}.csv`, `${header}${result}`);
    
            // 7. 後始末
            await browser.close();
        }
    })();
    


実行手順
  1. 上記3ファイルを用意したフォルダ内でdocker-compose buildを実行してコンテナを作成
    • 「Successfully built」と表示されれば完了です。
  2. docker-compose up -dでコンテナを起動
    • -dをつけなければ起動ログが出るのでデバッグに役立ちます。
  3. docker exec -it playwright-sample bashでコンテナ内に入る
  4. node exampleスクリプトを実行
実行結果(出力ファイル一部分)

f:id:styleedge_tech:20200311075435p:plain

総括
  • サンプルではスクリーンショットもブラウザの切り替えも行っておりませんが、
    これらを併用すればデザインの確認にも一役買ってくれると思います。
  • 関連するものとして、弊社TMがSeleniumに関する記事を上げております。
    こちらも是非ともご覧ください。(リンク)

最後に

ご感想やご指摘等ございましたら後学のためにコメント頂けますと幸いです。


スタイルエッジ・LABOでは一緒に働く仲間を募集しております。
興味をお持ち頂けましたら是非とも下記をクリックしてください↓↓
recruit.styleedge-labo.co.jp

デザインパターンについて勉強してみた!

はじめに

こんにちは。スタイル・エッジLABOのOです。

今回は最近業務でよく関わるデザインパターンについて、自分の勉強もかねてご紹介したいと思います。

1.DTOについて

はじめにDTOについてご紹介します。DTOとは「Data Transfer Object」の略で、デザインパターンの一種です。
デザインパターンとは主にJavaなどのオブジェクト指向言語で使われる設計パターンの事ですね。

DTOはどういうデザインパターンかというと、データの入れ物としてのクラスを作成し、そのクラスにデータを入れて渡す、というパターンです。そのクラスには変数と変数の型を定義します。

実際に使う場合のイメージ図を見てもらうと、わかりやすいかと思います。

f:id:styleedge_tech:20200219131440j:plain
DTOイメージ図


データを受け渡す際に通るトンネルがDTO、というイメージです。

このDTOには何のメリットがあるのでしょうか?下記2点などがあるかと思います。

1.変数と変数の型が定義されたクラスを用意することで、可読性が向上する
2.DTOで型を指定することで、データの整合性を保つ

実際のサンプルコードとしては以下のようになります。

<?php

/**
 * Class TestViewDto
 * データベースから受け取ったデータをControllerからViewへ受け渡す時に使うDto
 */

class TestViewDto
{
    /**
     * @var int ID
     */
    private int $id;

    /**
     * @var string 名前
     */
    private string $name;

    /**
     * @var string 住所
     */
    private string $address;

    /**
     * @var int 電話番号
     */
    private int $tel;

    /**
     * @var string|null 備考
     */
    private ?string $comment = null;

    /**
     * @return int
     */
    public function getId(): int
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId(int $id): void
    {
        $this->id = $id;
    }

    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName(string $name): void
    {
        $this->name = $name;
    }

    /**
     * @return string
     */
    public function getAddress(): string
    {
        return $this->address;
    }

    /**
     * @param string $address
     */
    public function setAddress(string $address): void
    {
        $this->address = $address;
    }

    /**
     * @return int
     */
    public function getTel(): int
    {
        return $this->tel;
    }

    /**
     * @param int $tel
     */
    public function setTel(int $tel): void
    {
        $this->tel = $tel;
    }

    /**
     * @return string|null
     */
    public function getComment(): ?string
    {
        return $this->comment;
    }

    /**
     * @param string|null $comment
     */
    public function setComment(?string $comment): void
    {
        $this->comment = $comment;
    }

}
?>

本当にシンプルな内容ですね。DTOにはプロパティとgetter/setterしか書きません。
このようなデザインパターンは他にもいくつも存在しています。もう一つ紹介しましょう。

2.Template Methodパターン

今回もう一つ紹介するのはTemplate Methodパターンです。まず、こちらはどういった場合に使用するのかを説明いたします。

下の図のようなクラスがあるとします。

f:id:styleedge_tech:20200219131502j:plain
学生クラス図

学生A、学生B、学生Cの各クラスは以下の順にメソッドを呼んでいきます。

1.朝起きて学校へ行くメソッド
2.学校で授業を受けるメソッド
3.放課後を過ごすメソッド

当然学生により、各々の行動は違います。
例えば学生Aさんは自転車で学校に通いますが、学生Bさんは徒歩、学生Cさんは電車です。
しかし、3人の学生さんは1~3のメソッドを順番に呼んでいく流れは共通です。

このような共通の流れをまとめたい場合にTemplate Methodパターンを使用します。

Template Methodパターンの場合、親クラスで基本的な処理の流れを実装します。
処理の流れで呼ばれる1~3のメソッドを抽象化として宣言します。
親クラスで宣言した抽象メソッドの具体的な処理は学生Aさん、学生Bさん、学生Cさんで実装していきます。

では実際のコードを見ていきましょう。親クラスは以下の通りです。

<?php


namespace App\Http\Controllers;


abstract class StudentController extends Controller
{
    //朝起きて学校へいく
    abstract public function goToSchool();

    //学校で授業を受ける
    abstract public function Study();

    //放課後を過ごす
    abstract public function SpendAfterSchool();

}


続いて子クラス(学生Aさん)です。

<?php


namespace App\Http\Controllers;


class StudentAController extends StudentController
{
    //朝起きて学校へいく
    public function goToSchool()
    {
        return '電車で通学';
    }

    //学校で授業を受ける
    public function Study()
    {
        return '数学・日本史・英語・物理・国語';
    }

    //放課後を過ごす
    public function SpendAfterSchool()
    {
        return '部活動:野球';
    }

    public function index()
    {
        echo $this->goToSchool()."<br />";
        echo $this->Study()."<br />";
        echo $this->SpendAfterSchool();
    }
}

子クラスは親クラスを継承して使います。結果は以下のようになります。

f:id:styleedge_tech:20200219123732j:plain
結果

Template Methodパターンはフレームワークでもよく使われています。
DTOやTemplate Methodのようなデザインパターンを使うメリットはなんでしょうか。
よく言われているのが

1.開発者の共通言語となる
2.コードが読みやすくなる、拡張性が高くなる、メンテナンス性が向上する
3.再利用しやすい

あたりです。多くの人が開発に参加する、人の出入りがある大きいプロジェクトに向いていると思います。

逆にデメリットとしては
1.デザインパターンを知らない場合、共通言語とならない
2.学習コストがかかる。知っているとしても、使ったことがない場合は実際の開発時に時間がかかる

簡単なシステムを作る場合はそこまでデザインパターンにこだわる必要はないかと思います。

デザインパターンは他にもありますので、今後自分でも勉強していきたいです。

最後に

スタイル・エッジLABOでは、一緒に働く仲間を募集しています。 もし興味を持っていただけましたら、ぜひ採用サイトものぞいてみてください!

recruit.styleedge-labo.co.jp

PhpStromに乗り換えてみる

f:id:styleedge_tech:20200110121228j:plain
Photo by Zany Jadraque on Unsplash

はじめに

こんにちは。スタイル・エッジLABOのNです。

さて早速ですが、弊社では希望者にはPhpStormのライセンスを会社負担で支給していただけます。

私はスタイル・エッジLABOへはつい最近転職してきたばかりなのですが、以前いた会社ではそういった制度はなかったものですから、PhpStormを利用しようと思うとで個人利用で初年度は1万円少々かかります。2年後以降も安くはなっていくもののランニングでコストがかかるとなると庶民にはなかなか手が出づらいものでした。

ですが会社のお金で使えるならこれ幸いと私も遅ればせながらPhpStormデビューを果たしてみましたので使ってみたプラグインを5つ紹介させていただこうと思います。

1. IdeaVim

PhpStormのエディタ操作をVimキーバインドにしてくれます。 もともとVimで開発を行っておりましたのでこれがないと始まらぬ、ということで入れました。 Vimの機能を完全再現、とまではさすがにいきませんのである程度割り切りは必要なのですが、十分に使えるのではないでしょうか。

2. Scratch

プロジェクトに依存しないファイルにメモ書きができます。 Vimを使ってるときはちょっとしたメモを新規タブで開いてさっと書いたりしてたのですが、PhpStormではどうするか、、、と思っていたところ見つけました。 便利です。

3. Auto-Align

イコールの位置を調整してくれます。

f:id:styleedge_tech:20200110111821g:plain

4. Emmet

HTMLコードの補完をしてくれます。 >で子ノード、+で兄弟ノード等を表現することで記述の簡略化もすることができます。 いろんなのエディタのプラグインとして提供されてたりしますがPhpStormではデフォルトで利用することができるようです。

f:id:styleedge_tech:20200110111909g:plain

5. Tab Shifter

分割したウィンドウ間の移動や、ウィンドウサイズの変更ができます。 マウスを使わずにこれらの操作をしたかったので導入しました。

f:id:styleedge_tech:20200110120623g:plain

最後に

PhpStormはプラグインの導入もボタンひとつで簡単にできます。 他にもデバッグ機能等、便利な機能を搭載しているようなので、ぜひ活用して自分好みの開発環境に育てていきたいですね。

スタイル・エッジLABOでは、一緒に働く仲間を募集しています。 もし興味を持っていただけましたら、ぜひ採用サイトものぞいてみてください!

株式会社スタイル・エッジLABO採用サイト