リンクバル

開発者に聞いてみた。AIで不正ユーザー発見ってどうやるの?


こんにちは!人事の原です。

先日、当社が運営するオンラインマッチングサービス「CoupLink」についてプレスリリースが発表されました。

https://prtimes.jp/main/html/rd/p/000000518.000004786.html

「CoupLink」は、2019年4月からAIを導入いたしました。AI導入により、不正ユーザーを早期発見し、迅速な処置を行う体制を構築いたしました。

エーアイを導入して不正ユーザーをソウキハッケン、、なんだかCoupLinkがレベルアップしたようだ…!ということで、プロジェクトを担当されたIさんにお話を聞いてみました!

プロジェクトの発端は?

マッチングアプリの性質上、どうしても業者等の不正ユーザーが発生してしまいます。お客様からの違反報告や運営者の目視による検出・対応は今までも行っていましたが、ユーザーにもっと安心して利用していただくために、より早い段階で対応していきたいという思いから始まりました。

そもそもなんですが、「AI」ってなんでしょうか。。

言葉はArtificial Intelligence・人工知能の略ですね。AIのはっきりした定義は無いため、世の中で言葉が独り歩きしてしまっている感じはあります。ここでは一旦「機械学習」と同義で考えてください。機械学習というのは、「過去のデータから反復的に学習を行い、パターンや特徴を見つけ出して未知のデータに対して予測を行うこと」です。学習方法にはいくつか種類がありますが、今回は「教師あり学習」という、事前にデータと特徴を紐づけておき、未知のデータがどこに分類されるかを予測する手法を使用しました。

<原メモ>
機械学習は、「今までの経験上、これはきっとこっちだ!」っていうのを人間の代わりにやってくれるものなんですね。例えば、私達人間は犬と猫の区別ができますが、それは今まで見てきた「これは犬で、これは猫」という正解のデータを持っているからです。(生まれてすぐの赤ちゃんには犬と猫の区別はできないですよね。)そのデータがあるから、初めて会った犬に対しても、たぶんこれは犬だろうと判断できるんですね。この一連の流れを機械学習はやってくれています。

機械学習のイメージはなんとなく掴めました!では、CoupLinkではどのように機能しているんですか?

今回導入した目的は不正ユーザーの早期発見・対応のためです。不正ユーザーとは、業者やマッチングした相手に嫌がらせをしている等の利用規約違反者を指します。そのため、機械学習で行っていることは、今までの「健全ユーザー」と「不正ユーザー」それぞれのデータを入れて学習させ、新しいユーザーのデータを見たときに「健全ユーザーと不正ユーザーのどちらに近いか」の判断です。

具体的にどんなデータで判断しているかというと、メッセージ数やいいね数、写真の有無など様々な項目の組み合わせです。例えば、このユーザーは1日に何百人にも同じメッセージを送っている→業者である可能性が高いかも、、のようなイメージです。もちろんこれだけではなく、様々な項目を組み合わせた上で判断しています。そして「不正ユーザーである可能性が高い」とされたユーザーをリスト化し、そこからは「本当に不正ユーザーであるか」を運営者が目視で確認して対応しています。

現段階では、機械学習の結果をそのまま適用するのではなく、人間の目で最終チェックを入れる運用にしています。完全オートメーションではないものの、不正ユーザーである可能性が高いユーザーを絞ることができるようになったので、より早く対応はできるようになったと思います。

 


わかっているようでわかっていなかったAI、機械学習について仕組みを知ることができました。知識の少ない私にも理解できるよう噛み砕いて噛み砕いて説明してくださったIさん、ありがとうございました!

より安心安全な出会いを提供できるようになったCoupLink、まだ利用したことの無い方はぜひお試しください♡

CoupLinkとは

街コン、恋活、婚活パーティーなどのリアルイベントから生まれた恋活アプリ。150万人のイベント参加者と、オンラインで出会えます。詳しくはこちら

 


なぜ残業45hを超えてはいけないのか。残業と睡眠の関係。


こんにちは。人事の吉田です。残業の上限は45hと言われますが、これは何故なのでしょう。厚生労働省がいわゆる「過労死」の認定基準として定めた事も記憶に新しいですね。今回は過労死の認定基準となった残業時間と睡眠時間の関係について紹介します。

 

「過労死」の認定基準となった残業45h

医学的な研究から、睡眠時間が5時間以下になると、脳・心臓疾患の罹患率が高くなる事が知られています。「過労死」の認定基準となったのは、この睡眠時間と残業時間の関係からなのです。厚生労働省の報告書(※)には「1日の時間外労働を2h、4h、5h程度行う者は、睡眠時間の平均がそれぞれ7.5h、6h、5hとなっていた」という調査結果があります。この残業時間に平均勤務日数21.7日を乗じて、概ね45時間、80時間、100時間を基準に定めているのです。

標準的な睡眠時間7.5hを確保
⇒1日当たりの残業を平均2h以内に

睡眠時間を5h確保(心臓病や脳疾患の予防)
⇒1日当たりの残業を平均5h以内に

※脳・心臓疾患の認定基準に関する専門検討会報告書

 

残業時間と睡眠時間の関係

1日24hの内、基本労働時間を8h、昼休み1hとすると、概算ですが次の関係が成り立ちます。

15h ≒ 残業時間 + 睡眠時間 + 余暇(夕食/風呂/身支度/趣味/自己啓発等) + 通勤時間

当然、残業時間が増えると相対的に睡眠時間や余暇が減るのです。

余談ですが、睡眠時間や余暇を確保する手段として、引越し等の手段で通勤時間を圧縮するのも有効と言えます。通勤は毎日の事ですから片道30分減るだけでも、月21h、年間250h以上の差になります。会社の近くに住むと人生が豊かになるのかもしれません。

 

時間外労働の罰則化

今回の働き方改革関連法改正で、時間外労働の上限は、原則として月45時間・年360時間と法律に定められました。特別条項付きの36協定を締結している場合でも、次の条件を守らなければ違反となります。

<原則>
・月45時間
・年360時間

<特別条項付きの36協定を締結している場合の上限>
・時間外労働が年720時間以内
・時間外労働と休日労働の合計が月100時間未満
・時間外労働が月45時間を超えることができるのは年6カ月が限度
・時間外労働と休日労働の合計について、「2カ月平均」「3カ月平均」「4カ月平均」「5カ月平均」「6カ月平均」が全て1月当たり80時間以内

<時間外労働の上限に違反した場合の罰則>
6カ月以下の懲役または30万円以下の罰金
また、悪質と判断された場合は、企業名を公表される可能性もあります。そうなれば企業の社会的信用が損なわれ、顧客や取引先や採用活動等への影響は避けられません。労働基準法を守るということは事業継続に不可欠で、経営者や人事担当者は違反を阻止しなければなりません。

当社の残業事情

当社では残業時間が月30hを超えない様に勤怠管理をしています。月平均の残業時間が10h程度ですから、インターネット業界ではかなり少ない方だと思います。それでも重要なリリースなどが近くなると、どうしても残業が増える事はあります。そうした方には翌月に特別休暇を付与する事で、健康への配慮を心掛けて頂いています。

何事も心身の健康があってこそですね。それでは。

RECRUIT – 採用情報


リンクバルベトナムへ出張しています


みなさま、シンチャオ!

リンクバルの船寄と申します。

私は今、ベトナムのハノイに所在する、リンクバルベトナムへ出張をしております。今回はリンクバルベトナムとハノイ滞在中の様子について紹介させていただきます。

リンクバルベトナム

弊社の事業成長を加速させる為に設立された、初の海外開発拠点です。冒頭で紹介させていただいた通り、ベトナムのハノイにオフィスを構えております。

現在は、machicon JAPAN の開発を主に担っています。

メンバーは若くて優秀なエンジニアが集まっており、日本語が話せるメンバーも複数名在籍しております。今の所コミュニケーションが大きな壁となっていることはありません。

残業を良いこととしているわけではありませんが、私が滞在していて驚いたのが、毎日30分ほど自らの意思で残業をしていました。とても熱心に仕事に取り組み、皆、誠実な人柄だと感じました。

ここからは写真多めでリンクバルベトナムの紹介をさせていただきます。

オフィスの様子です。業務中は皆、仕事に集中していて、静かです。

 

昼食後は昼寝をする習慣があるそうです。部屋の電気は消灯されます。

 

おやつ休憩の様子です。メンバーが慣れた手つきでフルーツをカットしてくれました。

 

誕生日を迎えたメンバー(ズイさん)のお祝いをしました。リンクバルベトナムの代表であるクオンさんは、「会社の仲間は家族のようだと」言っていました。オフィス内の雰囲気も非常に和やかに感じました。

 

ランチタイムはお弁当を持参したり、外食したり自由です。この日はみんなで出前をとりました。ベトナムでは「Now」という出前アプリがよく使われているようで、それを利用しました。写真は私が注文した焼きラーメンです。

 

滞在中の様子

ベトナム(ノイバイ空港)へはベトナム航空を利用しました。客室対応も丁寧に感じられ、機体も比較的に新しくて快適でした。機内食は「Beef or Chicken」ではなく、「Japanese or Western」でした。私はWesternを選択しました。

 

初めてハノイに来てびっくりしたのが、バイクに乗っている人がとても多いことです。道を横断するのも、慣れない日本人にとって一苦労です。ちなみに、リンクバルベトナムのメンバーも全員バイク出勤です。

 

ハノイにはとても多くのカフェがあります。カフェが複数件、連続して存在する光景をよく見ます。

 

ベトナムコーヒーを初めて飲みました。非常に濃厚です。私はコーヒーが好きなので、オフィス出勤前に毎日一杯飲んでから出勤しています。

 

リンクバルベトナムのメンバーと食事とカラオケに行きました。なかなか対面で会えない分、こういった場でのコミュニケーションが非常に大事だと思いました。とても楽しかったです。

 

ベトナムで有名な朝食です。(ソイとバインミー)

 

フォーの写真です。あっさりしていて美味しかったです。ベトナムでは暑い日でも日常的に食べられるそうです。

 

ビテットです。通常のステーキより若干甘めに感じました。とても柔らい食感でした。

 

街で一際目立つ存在、ロッテタワー。リンクバルベトナムから徒歩10分ほどで行くことができます。もし道に迷ったらここのタワーが目印です。

 

特に用事があるわけではないのですが、日本国大使館もオフィスの近くにあります。日の丸を見ると、なぜか落ち着きます。

 

最後に

今回はリンクバルベトナムと出張中の様子をご紹介させていただきました。今後とも、日本とベトナムのエンジニアで協力し、良いプロダクトを世の中に送り出したいと思っています。

リンクバルではエンジニアの採用募集を行っております。外国籍のエンジニアも在籍しております。ご興味がある方はこちらをご覧ください。

https://hrmos.co/pages/linkbal


DeepLens + Rekognition + Raspberry Pi で会議室を自動解錠する


2018年6月、弊社にて「OpenSesameプロジェクト」が立ち上がりました。
目的はその名の通り、「開けゴマ」です。
DeepLensを使用して会議室のドアを自動で解錠します。

今回は自動解錠システムの実装として
・Rekognition API での顔認証
・Raspbery Pi のGPIO制御
をメインにお話します。

DeepLensの基本事項や設定方法については過去記事で紹介しておりますのでそちらをご覧ください。

過去記事
AWS DeepLensを購入しました〜セットアップ編〜
AWS DeepLensを購入しました〜映像をみる、SSH接続編〜
AWS DeepLensを購入しました〜サンプルプロジェクトデプロイ編〜
AWS DeepLensを購入しました〜コミュニティプロジェクトデプロイ編〜

続きを読む


リンクバルの従業員持株会制度ってどんな制度?


こんにちは!人事の原です。

みなさん、従業員持株会という制度をご存知ですか?簡単にご説明すると、従業員が自社株を取得する際に、会社が補助することで従業員の資産形成を助成する制度です。上場企業の約90%の会社が導入しており、導入している会社に所属する従業員の約40%が加入しています。当社の制度はどんなものなのかも含め、以下でもう少し詳しくお伝えしていきます!

従業員持株会とは

冒頭でお話したとおり、入会すると自社株式を取得する際に会社から補助が受けられます。通常、株式を買うにはまとまった資金が必要ですが、従業員の特権として月々わずかな資金で自社株式を購入することができます。月々給与や賞与から定額が天引きされて株式購入するので、資産形成にも役立ちます。

リンクバル従業員持株会について

<入会資格>
 リンクバルの正社員(試用期間中は除く)
<奨励金>
拠出金の12%(1口1,000円につき120円)

奨励金は会社が付与。拠出金に加算して株式購入資金にあてます。
<申込可能時期>
決算発表翌日から2週間の間

<口数上限>
・月例 最小:1口1,000円、最大:給与の10%

・賞与 最小:0口、最大:月例の3倍

 

奨励金12%ってすごいですよね。毎月1,000円分購入するとしたら、120円分上乗せで会社がお金を出してくれるんです。(ありがたい..!!!)

ちなみに、上場会社の奨励金支給平均額は82.27円(/1,000円につき)なので、かなり高い方だと思います。

よくある質問

拠出金を一時的に休むことは可能ですか?

可能です。病気や災害等、やむを得ない事情がある場合、一時的に休むことができ、再開することも可能です。ただし、一度退会すると再入会はできません。

残高紹介の通知は?

年二回(3・9月末現在の各会員の持分を原則翌月中に)残高明細をお届けします。
オンラインでも確認したい方は事務局(人事G)までお問い合わせください。

口数の変更はできますか?

できます。入会時同様のフローで申請してください。

退職したらどうなりますか?

会員資格を失います。

退会したら保有している株はどうなりますか?

端株(100株に満たない分):ご自身の銀行口座に振り込まれます
単元株(1単元=100株)  :会社が指定する証券口座に移行(お持ちでない方は口座発行が必要です。)

インサイダー取引には要注意!

インサイダー取引とは

重要事実(公表前の売上や業務提携等)を知る会社関係者等(家族や知人も対象)が、当該事実を知りながら上場会社の株を売買することです。
※違反した場合、罰則有り。5年以下の懲役もしくは500万円以下の罰金等。
※退職者も退職後1年間は「会社関係者等」に該当します。

申込可能時期を決算発表後2週間に絞っているのは、インサイダー取引を防止するためです。

おわりに

制度を上手く利用して賢く資産形成していきたいですね!

これを読んで持株会に加入したくなったリンクバル社員の方は、「リンク集」から従業員持株会申請フォームをご確認ください☆


(参考:2017年度従業員持株会状況調査結果の概要について/株式会社東京証券取引所)

 


早見表:5日の有休を取得すべき1年間 (働き方改革関連法案)


年次有給休暇の取得義務化

働き方改革法案の成立により、労働基準法が改正され、10日以上有給休暇の権利がある従業員について、最低でも年5日以上は有給休暇を消化させることが義務付けられました。企業は有給休暇の日を指定してでも、有給休暇を5日以上消化させる必要があります。

義務に違反して、対象となる従業員に有給休暇の指定をしなかった場合は、1人当たり30万円以下の罰金が課されます。

自分の入社月:5日間の有休を取得すべき1年間

  • 20xx年10月入社:2019年04月~2020年03月
  • 20xx年11月入社:2019年05月~2020年04月
  • 20xx年12月入社:2019年06月~2020年05月
  • 20xx年01月入社:2019年07月~2020年06月
  • 20xx年02月入社:2019年08月~2020年07月
  • 20xx年03月入社:2019年09月~2020年08月
  • 20xx年04月入社:2019年10月~2020年09月
  • 20xx年05月入社:2019年11月~2020年10月
  • 20xx年06月入社:2019年12月~2020年11月
  • 20xx年07月入社:2020年01月~2020年12月
  • 20xx年08月入社:2020年02月~2021年01月
  • 20xx年09月入社:2020年03月~2021年02月

もうこれだけ覚えておけば大丈夫です。ただし、企業によっては従業員の入社日に関係なく基準日(有休付与日)を統一している事もあります。よく分からなければ人事へ問合せてみましょう。

計画的に取得できなかった場合

もし期限ギリギリになって5日取得できていない場合、当社では人事が休暇日を指定して有休を取得して頂く方針です。担当するプロジェクトの状況によってはチームに迷惑をかけてしまうので、そうならないためにも計画的な有給休暇の取得を心掛けましょう。

参考

もしよければ、リンクバルの採用ページもご覧になってください。


【新入社員インタビュー】個性豊かな19新卒


こんにちは!リンクバル人事の原です。

4月1日、新卒3名が入社しました。多くの会社から、当社を選んでくれたことを非常に嬉しく思います。今回はそんな3名に座談会形式でインタビューをしてきました☻

 

プロフィール

・ガルシアさん

エンジニア / ミステリアスボーイ

 

 

 

 

・長坂さん

総合職 / 最高スマイルman

 

 

 

 

・中嶋さん

エンジニア / アナウンサー感の強いエンジニア

 

 

 

 


社会人になって2週間、社会人生活はどうですか?

ガルシア:特に今までと変わらないですね。インターンにも来ていてたので。

長坂:僕は、ビジネス基礎力の低さを痛感しています。もっと学生時代に勉強しておけばよかったです。ホウレンソウや結論から先に話すようによく指摘をいただきます。ビジネス基礎力やサービスの仕組みについて、もっともっと勉強していきたいです。

中嶋:社会人って楽しいなと思っています。変わったことは朝が早くなったくらいです。

今やっている業務を簡単に教えてください。

ガルシア:エンジニアとして、オンラインデーティングアプリ「CoupLink」の主に改修を行っています。

長坂:僕は今、「CoupLink」をお客様にとってより良いものにするためにどうするか施策を考えています。例えば、ボタンを押し間違えないようにするにはどうしたらよいか等です。

中嶋:「machiconJAPAN」のバグ改修や表示の変更を行っています。

入社前後で会社のイメージは変わりましたか?

ガルシア:残業が全然ないことに驚きました。ITの会社って夜遅くまで残って仕事して、、というイメージだったのですが、みなさん本当に早く帰りますよね。

長坂:一つ驚いたことは、「CoupLink」を作っている人の少なさですね。エンジニアは除いてですが、仕様等を考えたり作っていく人は僕を入れて3名です。できる範囲がとても広いなとも感じているので、どんどん成長していきたいと思っています。

初任給の使いみちは?

ガルシア:学費の引き落としがあるので、、、

中嶋:引っ越し費用の引き落としがあって、、、

長坂:ナンを食べにいきたいです!

原:、、、ナン?

ナンが大好きらしいです。ナンが美味しいお店を知っている方、ぜひ連れて行ってあげてください。

GWはどう過ごす?

ガルシア:空を見上げて何もしないで過ごしたい。

長坂&中嶋:ひまですね。

(原:みんな時間セレブですね。)

ガルシア:あ、でも19卒で何か作りたいなと思っています。詳細はこれから詰めていきますが、GWの間何日か集まって何か作る予定です。

1年後どうなっていたいですか?

ガルシア:CoupLink100万ダウンロード達成したいですね。

一同:オオ!

中嶋:入社前には「1年後、今の自分を鼻で笑えるくらい成長したい」と思っていました。でも、実際入社してみて、この目標は普通に過ごしていたら達成できそうなので、GW中に目標立て直します。

長坂:先輩を抜きたいです。早く成長したい。


なんだかとても頼もしい。今後が楽しみですね!

ちなみにアイキャッチ画像の耳打ちポーズはガルシアさんが発案してくれました。微笑ましい…

採用情報はこちら

 


【妻への連絡を9割以上Bot化】プライベートSlackのススメ


こんにちは。人事の吉田です。

今回は勇気を出して、私の日常をさらけ出してみます。

技術的には大した内容ではありませんが、私が技術大好き人間なのだと認知して頂けたら嬉しいです。

帰宅を巡る攻防

妻への連絡をBot化しようと考えたのは、毎日毎日帰宅を巡って下記の様なクソリプを繰り返す事にお互いがウンザリしていたからです。しかし、こうしたやり取りには一定の規則性がある事、そしてこれは簡単な仕組みで解決できると気がついたのです。
妻「今日は何時に帰るのか」
俺「・・・(面白い事を思いついたので、ちょっとだけ試してみたいな。)」
妻「晩ご飯は要るのか」
┣俺「要る」  ─妻「何時に帰るのか(無限ループ)」
┗俺「要らない」─妻「ヴぃあぇbvこうおはh(怒)」
妻「そろそろ帰ると言ってから3時間経過してるけど何をしているのか」
俺「・・・(帰り間際に誘われてホイホイ食事に行ってしまった)」

Botの仕組み

必要なものは、スマホ、googleアカウント(無料)、Slack(無料)、IFTTT(無料)くらい。Botの仕組みも至ってシンプルなものです。
  • IFTTT スマホの位置情報をトリガーにしてスプレッドシートを更新(帰宅時に利用する*駅*番出口の半径3m以内に侵入すると、指定したスプレッドシートにタイムスタンプ。ただしAM(出勤時)は起動しない&20時までに起動しなければ「今日はご飯いらない」をSlackに投稿し業務終了。
  • IMPORTXML関数 スタンプされた時刻から乗換案内を検索し、自宅最寄駅(+10mで自宅)への到着時間を算出しスプレッドシート上で更新
  • GAS セル上で算出した帰宅時刻にそれらしいテキストを付け加えてSlackに投稿
余談ですが、Bot完成後に妻へSlackの導入を提案したところ、即断即決で拒否されました。上記のBotはSlack→LINEに転送する形で運用しています。

問題は解決できたのか

結果として帰宅時間を巡る攻防は激減したと言えます。計測しておらずデータで示す事はできないですが、冒頭の様なやり取りは実感値として9割以上駆逐できました。機械的なメッセージに一切反応しなくなったとも解釈できますが、アイコンを子供の画像にした事で、緊張は和らいだ気がします。現場からは以上です。

号外

プライベートにSlackを導入すると、目的別にチャンネルを設定できるので、リマインドの共有相手を一括変更したり、複数SNSの投稿やフィードをまとめて流し読みしたりするのに便利です。一部紹介。
• Remind #trash “明日は燃えるゴミの日です” at 9PM every Sunday and Thursday.
• Remind #trash “そろそろ清掃車が来ます” at 9:45AM every Saturday.
• Remind #shops “明日は火曜市(https://www.aeonnetshop.com/shop/c/マイ店舗)” at 8PM every Monday.
• Remind #shops “今日はピザが半額(https://pizzahut.jp/ip/shop_detail/マイ店舗)” at 9AM on the 8th of every month.
• Remind #shops “今日はニワトリの日(https://www.kfc.co.jp/sp/menu/)” at 9AM on the 28th of every month.
• Remind #shops “31の日です” at 9AM on the 31st of every month.
• Remind #finance “https://karauri.net/kikan/” at 6PM every weekday.

Host a Website on GitHub with Jekyll – Part 2


Hi! I’m Dennis and I’ve been working at Linkbal as a software engineer since October 2017. In Part 1, we took a quick look at Jekyll and how to create and deploy a website to GitHub Pages. In this second and final part, let’s explore some of the customization features Jekyll provides us.

Layouts

In the previous example, you may have noticed the layout definition below in the front matter:

layout: post

While the markdown file provides the content of a page, the structure and appearance are defined in the layout file. We can create our own layout files, but because we are using an existing theme, we can customize the theme’s layout files instead.

First, let’s copy the layout files from the theme’s folder to our project (the specific folder to copy from will probably be different for you as it depends on the version of the packages installed).

cp -r vendor/bundle/ruby/2.3.0/gems/minima-2.5.0/_layouts .

If we take a look at the _layouts folder, we can see the 4 files below:

  • default.html
  • home.html
  • page.html
  • post.html

If we open the default.html file, we can see contents like the below:

<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">

  {%- include head.html -%}

  <body>

    {%- include header.html -%}

    <main class="page-content" aria-label="Content">
      <div class="wrapper">
        {{ content }}
      </div>
    </main>

    {%- include footer.html -%}

  </body>

</html>

It is an ordinary HTML file, but we can see a couple of the features provided by Jekyll and the Liquid template language it uses.

“Include” tags, like the below, allow us to include content from another file stored in the _includes folder:

{%- include header.html -%}

While the line below specifies where the content of a markdown file that uses the layout file will be injected:

{{ content }}

If we take a look at the contents of page.html:

---
layout: default
---
<article class="post">

  <header class="post-header">
    <h1 class="post-title">{{ page.title | escape }}</h1>
  </header>

  <div class="post-content">
    {{ content }}
  </div>

</article>

We can see that a layout itself can use another layout and that this layout can be used to display an article with a title in the top.

Now, we can also open the about.md file that ships with Jekyll. We can see in the front matter that this file uses the page layout.

---
layout: page
title: About
permalink: /about/
---

Also, the front matter defines a title and this title is injected in the line below in the page layout:

<h1 class="post-title">{{ page.title | escape }}</h1>

Now that we have an idea of how layouts work, let’s customize our website a little bit.

Includes

In the default.html layout file, we can see the line below:

{%- include header.html -%}

Because the default.html layout includes the header and all other layouts uses the default layout, it is obvious that all pages in our website includes the content in header.html.

Let’s take a look at the contents of the header.html file. Because it is also part of the minima theme, we need to copy this file as well:

mkdir _includes
cp vendor/bundle/ruby/2.3.0/gems/minima-2.5.0/_includes/header.html _includes

This include file is responsible for displaying the website header and shows many variables that Jekyll make available for us, as well as filters provided by the Liquid template language.

{%- assign default_paths = site.pages | map: "path" -%}

The line above, for example, shows the site.pages variable. It is an array of Jekyll’s Page variables (you can check the list of attributes a Page variable contains in Page Variables). Any .html or .md file in the root folder or a new subfolder that contains a front matter will be part of the site.pages variable. Then, we execute Liquid’s map filter on the site.pages to get an array of the paths of those pages.

{%- assign page_paths = site.header_pages | default: default_paths -%}

The next line creates a variable called page_paths. It is assigned the value in site.header_pages, but can also be assigned the value in default_paths in the case the former does not exist, what is possible with the use of Liquid’s default filter. We are going to come back to site.header_pages later.

{%- for path in page_paths -%}
  {%- assign my_page = site.pages | where: "path", path | first -%}
  {%- if my_page.title -%}
  <a class="page-link" href="{{ my_page.url | relative_url }}">{{ my_page.title | escape }}</a>
  {%- endif -%}
{%- endfor -%}

This last snippet iterates over the page_paths variable created before and creates a link in the header for each page that has a title (defined in the front matter).

To test what was just shown, let’s create a new page notes.md in the project’s root folder. Now, let’s add the content below to the new file:

---
layout: page
title: Notes
permalink: /notes/
---

If we refresh our website, we are going to see a new “Notes” link in the header. Add another page called contact.md to the root folder with the content below:

---
layout: page
title: Contact
permalink: /contact/
---

A new link is created as well. The problem is that the links are created in the alphabetical order, but we may want a different order to put the “Contact” page last, for example. In that case, we can use the site.header_pages mentioned before. This currently does not exist, but we can easily create this variable by adding the following lines to the _config.yml file:

header_pages:
  - about.md
  - notes.md
  - contact.md

You will notice the change will not be reflected immediately and will require the server to be restarted. After that, the header will look as expected.

The Resulting Header

The Resulting Header

Collections

Now, we are going to explore Collections that are a great way to group related content. Let’s use this feature to implement the “Notes” section in our website.

First, add the following content to _config.yml:

collections:
  - notes

Then, let’s create a _notes folder and add 2 files in it. The /_notes/note1.md:

---
menu_title: Note 1 Menu Item
title: Note 1 Title
---

Note 1 content

> A nice blockquote

A **formatted** line of *text*.

And the /_notes/note2.md:

---
menu_title: Note 2 Menu Item
title: Note 2 Title
---

Note 2 content

> A nice blockquote

A **formatted** line of *text*.

Now, let’s create a custom layout listing all our notes. It will be the /_layouts/note.html file and will contain the following content:

---
layout: default
---
<style>
.note {
  margin: 2rem 0;
  padding: 1rem 2rem;
}

.yellow {
  background-color: #fdf475;
}

.blue {
  background-color: #cbf0f8;
}

.note-date {
  font-size: 0.8rem;
  font-style: italic;
  color: gray;
}
</style>
<div class="notes-container">

  <header class="notes-header">
    <h1 class="notes-title">{{ page.title | escape }}</h1>
  </header>

  {%- for note in site.notes -%}
  <article class="note {{ note.background }}">

    <header class="note-header">
      <h2 class="note-title">{{ note.title | escape }}</h2>
      <p class="note-date">{{ note.date }}</p>
    </header>

    <div class="note-content">
      {{ note.content }}
    </div>

  </article>
  {%- endfor -%}
</div>

I added the styles directly in the layout, to keep things simple, as that is not the main focus of the article. As Jekyll has built-in support for Sass, please refer to the Docs to know how to manage your stylesheets.

You can see we were able to access our notes through the site.notes variable and even use a custom variable background we added to the front matter.

Restart the server and we can now access those notes in the /notes/ path.

The Notes Page

The Notes Page

The files we created in the _notes folder does not generate corresponding files in Jekyll’s build process. If you need, you can change this behavior as shown in Add content. This would generate files such as /_notes/note1.html in the build output. In our example, we could, for example, display only part of the content of the notes in the list and link each note to a page where the user can see their whole content.

Data Files

In this final section, we are going to take a quick look at Data Files. It allows us to create files with custom data to be used in our templates. Those can be YAML, JSON, or CSV files. Let’s do an example to illustrate its use.

First, create a file named /_data/contacts.yml:

- type: Email
  value: me@denakitan.com

- type: Phone
  value: (00) 0000-0000

- type: Website
  value: http://github.com/denakitan

This is enough to make our data accessible in our templates in the site.data.contacts variable. So, we can now edit our /contact.md file with the following content:

---
layout: page
title: Contact
permalink: /contact/
---

<table>
  {%- for contact in site.data.contacts %}
  <tr>
    <td>{{ contact.type }}</td>
    <td>{{ contact.value }}</td>
  </tr>
  {%- endfor %}
</table>

This will generate the below output:

The Contact Page

The Contact Page

As we could see, we can use Data Files to remove repetition in our pages by separating data and configuration. A practical use is illustrate in Navigation where it is used to create custom navigation for a website.

Conclusion

In these article, we could learn and practice basic Jekyll concepts such as Layouts, Collections and Data Files. There are plenty of content was not covered in the articles, so I highly recommend reading the documentation, as it is very well written and easy to understand.


元PHPエンジニアがPHPとRubyを比較してみた


はじめに

はじめまして。去年の6月に入社したチャン・ゾアン・タンと申します。

私はリンクバルに入る前にPHPエンジニアでした。RubyもRailsも未経験でした。入社してからRubyやRailsを勉強し始めました。以下の方法で勉強しました。

まず、Rubyを学ぶ

もともとPHPエンジニアだったので、Rubyを学んた時に、PHPと比較しながら学びました。

両方の言語はオブジェクト指向プログラミング言語(実は、Rubyはpureオブジェクト指向プログラミング、PHPはオブジェクト指向サポート言語と言われている)であるので、同様なものがあるかと思いました。この学び方でPHP知識に参照出来ると思います。

同様

まず、PHPとRubyは以下の通り同様なところがあると思います。

PHPとRubyとも型の指定せず変数を宣言できます

  • php
$hoge = 'linkbal';
echo $hoge;

$arr = [1,2,3];
print_r($arr);
  • ruby
hoge = 'linkbal'
puts hoge

arr = [1,2,3]
puts arr

オブジェクト指向プログラミング言語なので、両方PHPとRubyはpublic, protected, privateというアクセス修飾子を付けてクラスを宣言できる

配列

一次元配列は大体同じ、両方とも動的な配列がサポートされています。シンタックスも同様です。
Rubyで二次元配列がhashになります。

文字列補間

両方は文字列補間という文字列内に変数を埋め込むことができます。シンタックスも同様です。

  • php
$a = 'hogehoge';
echo "hello {$a}";
  • ruby
a = 'hogehoge'
puts "hello #{a}"

パッケージ管理ツール

両方とも盛んな言語なので、コミュニティーが広いし、ライブラリーも豊富なので、パッケージ管理ツールが必要です。

PHPではComposerを使っています。
RubyではGemです

いくつか同じ関数

  • eval: ローコードスクリプトを実行する関数
  • spintf: 文字列をフォーマットするための関数

違い

シンタックス

  • 基本のシンタックス

PHPはC言語と同様、セミコロンでコードステートメントを終了にします。semicolon terminatedと言います。
クラス関数ループなどというブロックは{}が包まれます
RubyはPythonと同様、改行でコードステートメントを終了にします。newline terminatedと言います。
クラス関数ループなどというブロックは{}が要らない

def method(a, b)
  if a &amp;amp;gt; b
    puts 'hoge hoge'
  end
end

以下の通り{}を使用するケースもあります。

eachメソッドのshorthand

[1,2,3].each { |elm| puts(elm) }

コードブロック

def hoge
puts 'welcome to'
yield
end
hoge { puts 'Linkbal engineer blog' }

・Rubyでは全部オブジェクトで、シンタックスはわかりやすいし、すっきりだと思います。

文字列の長さを取得する

PHP

echo strlen("welcome to linkbal engineer's blog");

Ruby

puts "welcome to linkbal engineer blog".length

・Rubyのシンタックスはかなりは柔軟です。
関数を呼び出す時、括弧があるかないかどちらもいけます。
Rubyの関数は最後の変数または表現がreturnの値になります。

def hoge
1 + 1 # return 2
end

If-else文は自然言語に近いので、結構わかりやすいです。

# これは
# if a == b
# hoge = 10
# end
# と相当です
hoge = 10 if a == b

Rubyでは逆の条件の場合、unlessが使える

#「if a != 10 hoge = 'test'」と相当です
hoge = 'test' unless a == 10

こういうかき方もよく使われています。

def hogehoge
'test' if a == 10
end

Truthy/Falsy

Rubyではfalse, nilのみfalseを返します。0、空文字列、空配列がtrueです。
PHPではfalsenullfalseであることはもとより、0、空文字列、空配列もfalseです。

Rubyはabstractクラスとinterfaceともありません。

文字列の連結

PHPではdot(.)を使います。
Rubyでは+を使います。

変数種

PHPでは変数が1種類しかありません。

Rubyでは4種類があります。

$variable # グローバル変数
@@variable # クラス変数
@variable # インスタンス変数
variable # ロカール変数

コード規約

開発するには言語を学ぶことだけではなくて、コード規則を学ぶべきです。

PHPのコード規約は「PHP Standard Recommendation(PSR)」が一番盛んなものだと思います。

RubyではRubocopという静的解析ツールが結構有名で、うち会社のプロジェクトも使っているので、Rubycopのコード規約に参考しました。

Railsを学ぶ

プログラミング言語を学んだあと、Railsフレームワークを学びます。

PHPを開発した時、Laravelフレームワークを使っていました。
LaravelはRailsのようにモダンな「MVC」Webフレームワークであります。それに、Laravelの作者はLaravelを作ったときに、Railsに参考したということを言われています。そのため、LaravelとRailsは構造や機能の中に同様なものがあるかと思いました。

Model

Laravelでは「Eloquent」と言います。
Railsでは「ActiveRecord」と言います。

両方ともパワーフルORM(Object Relational Mapping)で、Model連携も便利です。

View

LaravelではBladeというテンプレートエンジンがあります。これで簡単にレイアウトを作れ、再利用もできます。

RailsではERBがあります。LaravelのBladeと同様です。

Controller

他の「MVC」フレームワークと同じで、RailsとLaravelはリクエストがルーターで処理したあと、コントローラーにいって、ロジックを処理されます。

その他

Rails Laravel
コマンドライン rails console php artisan
マイグレーション サポート(実行, ロールバック, リセット、初期データ生成) サポート (実行, ロールバック, リセット、初期データ生成)
ストレージ Active Storage File Storage
Websocket Action Cable Broadcasting
多言語 i18n Localization
ユニットテスト rspec PHPUnit

終わり

最初、Railsに触った時に、こういう方法でRubyやRailsを勉強しました。
そして、私の部署ではPull Requestは必ず二人以上のApproveがないとマージできないようになっているので、ソースレビューでチームメイトのコメントからもいろいろ勉強できました。だんだんRailsの開発に慣れました。

現在、うちの会社ではエンジニアを募集しています。ご応募お待ちしております!

参考

https://guides.rubyonrails.org/index.html
https://docs.ruby-lang.org
https://laravel.com/docs
https://github.com/rubocop-hq/ruby-style-guide