カテゴリー: js

P5.sketchpluginを使ってビジュアルプログラミングを学ぶ[超初級編]

こんにちは。WEB事業部デザイナーの河野です。

いつものように趣味でPinterestとTumblrの徘徊をしていると、
めちゃくちゃクールでかっこいいグラフィックを見つけました。

「これどうやってできているんだろう」と辿ってみるとそこには「processing」という言葉が。。

恥ずかしながら今までその言葉を聞いたことがある程度で実態を分かっていませんでした。
processingとはビジュアルデザインのためのプログラミング言語のことで初心者でも比較的始めやすいとのこと。

初心者でも始めやすいとはいえ、されど「プログラミング」。
もともと自分は紙媒体のグラフィックデザイナー出身で、
黒い画面とコードを見ただけで頭痛と鳥肌、冷や汗が全身の毛穴から噴き出るほどの拒絶反応がありました。
(よくWEBデザイナーになれたものだ…。シーズの採用陣、器が広い!)

しかし!
色々調べていくとp5.jsというProcessingをJavaScriptで書けるライブラリを
WEBデザインツールのSketchで再現できるプラグインがあることがわかりました。

その名も「P5.sketchplugin」というプラグインです。
www.jacopocolo.com

Sketchだったら睡眠時間よりも長い時間毎日触っているツールなので
やりやすいかもしれない!と、早速使ってみました。

使ってみたらビックリ。

前述の通りプログラミングが全くわからない自分でも
ビジュアルプログラミングを体形的に学べつつ、デザインツールとしても便利だったのです!

ということで、今回は「P5.sketchplugin」をご紹介します。

まずはインストール

1. ここから最新バージョンをダウンロード

2. zipファイルを解凍してプラグインをインストール。

3. Sketchを起動してメニューにPlugins > p5が表示されたらインストール完了です。

f:id:seeds-std:20190913173424p:plain
インストールできた状態

基本:簡単なグラフを作成する

無事インストールできたら、早速触ってみます。
Plugins > p5 > Edit and runを選択してプラグインを立ち上げます。

f:id:seeds-std:20190913173527p:plain
プラグインを立ち上げました!

最初は何も表示されていませんが、ここにコードを入力しPlay(実行)でアートボードに反映されます。

早速プリセットのデータを見てみましょう。

[Presets]のプルダウンメニューから[Pie chart]を選択して実行すると、、

f:id:seeds-std:20190913173651p:plain
円グラフができました!

コード部分の下記の数値を編集して実行すると円グラフに反映されます。

var percentages = [30,60,10];

f:id:seeds-std:20190913174108p:plain
編集してみました

他にもプリセットには棒グラフも用意されています。
管理画面のUIデザインなどで役立ちそうですね。

実践:コードを編集してモザイクパターンを作成する

ここからは応用で、パターンを作ってみたいと思います。
[Presets]の中から[Generative grid]を選択します。

f:id:seeds-std:20190913180011p:plain

これを元に、アートボードのサイズ、色、円の表示の確率などなど、
各種設定していくとモザイク模様ができます!

試しにシーズのみんなが大好きなRedBullカラーのモザイクを作ってみました。

f:id:seeds-std:20190913182648p:plain
Redbullカラーモザイク

上にテキストを乗せたりと、バナーやアイキャッチ画像制作にいろいろと応用できそうです。
f:id:seeds-std:20190913183035p:plain

今まで視界に入ると拒否反応が出ていた数字や関数たちも、
「ここを動かすための記述なのか!」と理解できれば慣れてくるものだということが分かりました。
これから仲良くなっていきたいです。

注意すべきこと

  • あくまでも表現できるのは静止画のみ(Sketchの競合、Figmaはアニメーション表現も可能らしい。。)
  • 制約が多いのでリファレンスを読んだ上で操作すると良いかも。
  • Sketchでグラフィックを編集してしまうと、コードには反映されないので注意。

まとめ

普段デザイン業務しかしていないので、数値をいじるだけでビジュアルが変化するということがそもそも新鮮でした。
これがビジュアルプログラミング・・!
長らくコード大嫌いデザイナーでしたが、
これを機にprocessingを本気で勉強してみようと思います!

次回(未定)、初級編で簡単な図形を自分で作ってみたいと思います!
それではまた。

読み込みのタイミング

こんにちは、永井です。

最近はなかなか多忙な日々を送っており、業務で手一杯になってしまうので
何か+αできるように頑張っていきたいと思います。

さて今回は、業務中に困ったことがあったので、それについて書きたいと思います。

追従メニューが最後まで動きません

javascriptで画面スクロールに追従するメニューを設置したのですが、
意図しない中途半端な位置で追従が止まるという挙動になり困りました。

原因

意図しない誤動作の原因とは、ウィンドウの高さの取得などを行い、
追従のプログラムを組んだのですが、その際に値が正しく取得できていなかったためでした。
なぜ正しく取得できなかったかというと、ページ内のコンテンツに画像が複数設定されており、
その画像の高さが定義されておらず、その影響でウィンドウの高さが正しく取得できなかったようです。

解決策

結果から述べますと、”読み込みのタイミング”を変えることで解決できました。
最初はjQueryのお約束の

$(function(){
ここにプログラムを書き書き...
});

としていたところを

$(window).load(function(){
こっちにプログラムを書き書き...
});

と読み込みのタイミングを変えることで、キチンと最後まで追従するようになりました。

$(function(){})と$(window).load(function(){})の違い

正直なところよくわかっておらず、どちらもそこまで違いがないものと思い込んでおりました。
そこでGoogle先生にご相談したところ、ざっくり述べると、

$(function(){})は、HTMLの構築が完了した時点で処理を実行する。
$(window).load(function(){})は、HTMLの構築だけでなく、画像やFlashなどのデータの読み込みが完了してから処理を実行する。

だそうで、$(window).load(function(){})内ににプログラムを書くことで、コンテンツ内の画像データも含めて
ウィンドウの高さなどを取得することができるようになり、解決につながりました。

注意点

ただし、$(window).load(function(){})には注意すべき点があります。
それは、”画像やFlashなどのデータの読み込みが完了してから”なので、使用箇所、使用機能によっては
ユーザーは反応が遅く感じてしまうことがあると思われるので、
その辺りは、実際にテストを行い考慮していく必要がありそうです。

まとめ

普段は気にせず$(function(){})内に書き込んでいましたが、プログラムによっては
読み込みのタイミングを考慮する必要があるとわかりました。
また、できたから良いのではなく、機能の反応のユーザー体験(ユーザーエクスペリエンス)を
考えるということも大事なのだと思いました。

要素の選択について Vol.2

光陰矢の如しとはよく言ったもので、気づけばもう3月…そう”弥生”です。
普段の生活の中で、各月の別名を使うことは少ないと思いますが、皆さん知っておられますか?
自分はこういうの得意です!任せてください!
では、1月から…
あれ…? えーっと… あー… あ!  正月!

さて、気を取り直して、前回の記事に引き続いてjQueryでの要素の選択について書きます。
指定方法は多々ありますので、今回も自分の思うところの指定方法を抜粋して、記事にします。

フィルタを用いたセレクタ指定方法

フィルタと呼ばれる、要素の状態などを判断して指定が行なえます。

<ul class="hoge">
<li>テキスト1</li>
<li>テキスト2</li>
<li>テキスト3</li>
</ul>
<ul>
<li>テキスト4</li>
<li>テキスト5</li>
<li>テキスト6</li>
</ul>

上記のようなコードがあるとして説明していきます。

順序などによるフィルタ

:first :last

最初、最後の指定ができます。

$("ul.hoge li:first").css("color", "#f00")

上記指定で、リスト内の最初の要素(テキスト1)の文字色が赤色になります。

$("ul.hoge li:last").css("color", "#00f")

上記指定で、リスト内の最期の要素(テキスト3)の文字色が青色になります。

:first-child :last-child

“first”、”last”に似た指定方法で”:first-child”、”:last-child”というのもあります。

$("li:first-child").css("color", "#f00")

上記指定で、”各リスト内”の最初の要素(テキスト1とテキスト4)の文字色が赤色になります。

$("li:last-child").css("color", "#00f")

上記指定で、”各リスト内”の最期の要素(テキスト3とテキスト6)の文字色が青色になります。

:even :odd

偶数、奇数を指定できます。

$("li:even").css("color", "#00f")

上記指定で、リスト内の偶数番目の要素(テキスト2)の文字色が青色になります。

$("li:odd").css("color", "#f00")

上記指定で、リスト内の奇数番目の要素(テキスト1とテキスト3)の文字色が赤色になります。

:eq(n)

n番目を指定できます。
注意点として、nは0から始まる番号です。

$("li:eq(2)").css("color", "#f00")

上記指定で、リスト内の3番目の要素(テキスト3)の文字色が赤色になります。

:lt(n)

n番目より前を指定できます。

$("li:lt(3)").css("color", "#f00")

上記指定で、リスト内の3番目より前の要素(テキスト1とテキスト2)の文字色が赤色になります。

:gt(n)

n番目より後を指定できます。

$("li:gt(1)").css("color", "#00f")

上記指定で、リスト内の1番目より後の要素(テキスト2とテキスト3)の文字色が青色になります。

:nth-child(n)

n番目を指定できます。
なお n には番号だけでなく、数式などでも指定可能です。
また、:nth-childでは1から始まる番号になります。

$("li:nth-child(2n+1)").css("color", "#f00")

上記指定で、リスト内の1、3、5…番目の要素(テキスト1とテキスト3)の文字色が赤色になります。

状態などによるフィルタ

:animated

アニメーションしている要素の指定ができます。

$("div:animated").css("background", "#f00")

上記指定で、アニメーションしている要素の背景色が赤色になります。

:visible :hidden

表示、非表示を判断し、要素の指定ができます。

$("div:visible").css("background", "#f00")

上記指定で、表示されている要素の背景色が赤色になります。

$("div:hidden").show()

上記指定で、非表示の要素が表示されます。
※inputのtype=”hidden”の要素も対象です。

:enabled :disabled

利用可能、不可能を判断し、要素の指定ができます。

$("input:enabled").val("YES");

上記指定で、利用可能な要素の値を”YES”に変更します。

$("input:disabled").val("NO");

上記指定で、利用不可能な要素の値を”NO”に変更します。

まとめ

前回と同じくですが、セレクタの指定方法は多々あり、フィルタを用いたセレクタ指定方法を網羅しているわけではありません。
他に、”:checked”、”:selected”などフォーム周りで使えそうな選択状態の要素を指定する方法などもあるようです。
jQueryの本家サイトや日本語翻訳サイトもありますので、さらに詳しくお知りになりたい場合は、そちらをご覧下さい。

後述

記事とは関係ありませんが、冒頭の月の別名については…

  • 1月 – 睦月
  • 2月 – 如月
  • 3月 – 弥生
  • 4月 – 卯月
  • 5月 – 皐月
  • 6月 – 水無月
  • 7月 – 文月
  • 8月 – 葉月
  • 9月 – 長月
  • 10月 – 神無月
  • 11月 – 霜月
  • 12月 – 師走

でした。
恥ずかしくないようちゃんと覚えておこうと思います。

HubotでSlackのボットを作成する

Hubotとは

Hubotは、Github社が開発したBot作成フレームワークです。
今回は、Hubotを使用してSlackボットを作成する方法をご紹介します。

Slack https://slack.com/
Hubot https://github.com/github/hubot

HubotはNode.jsのモジュールですので、Node.jsのインストールから始めます。

Node.jsのインストール

複数のNode.jsを管理するnvmコマンド経由で、Node.jsをインストールします。

nvmコマンドのインストール。

git clone git://github.com/creationix/nvm.git ~/.nvm

nvmのコマンドを使えるように、.bashrcにスクリプトを追記します。

if [[ -s ~/.nvm/nvm.sh ]]; then
source ~/.nvm/nvm.sh
fi

以上で、nvmコマンドが使えるようになります。

次にNode.jsをインストールします。
今回の例では、バージョン0.11.13をインストールします。

npm install 0.11.13
npm use v0.11.13

以上で、Node.js関連のコマンドが使えるようになります。

nvmの他の機能が気になる方は、
nvm単体で実行するとヘルプが表示されるので、そちらをご参照ください。

Hubotのインストール

npmコマンドでHubotをインストールします。
また、必要なモジュールもインストールします。

npm install -g hubot hubot-slack yo generator-hubot coffee-script

上記のコマンドでインストールしたモジュールの情報は以下のとおりになっています。

モジュール名 説明
hubot Hubot本体。hubotコマンドが使用できるようになる。
hubot-slack HubotのSlack用アダプタ。HubotをSlackに対応させるために使用する。
yo ひな形生成ツール。
generator-hubot yoでHubotプロジェクトのひな形を生成するために使用する。
coffee-script CoffeeScript。HubotのスクリプトはCoffeeScriptで記述する。

HubotでHello World

「Hello」と呼びかけたら「World」と返すボットを作成します。

まずはHubotのひな形作成します。

$ mkdir hellobot
$ cd hellobot
$ yo hubot
_____________________________
/                             \
//\              |      Extracting input for    |
////\    _____    |   self-replication process   |
//////\  /_____\   \                             /
======= |[^_/\_]|   /----------------------------
|   | _|___@@__|__
+===+/  ///     \_\
| |_\ /// HUBOT/\\
|___/\//      /  \\
\      /   +---+
\____/    |   |
| //|    +===+
\//      |xx|
? Owner: Uchiyama
? Bot name: hellobot
? Description: (A simple helpful robot for your Company)
? Bot adapter: (campfire) slack
? Bot adapter: slack

ひな形ができたら、scriptsディレクトリ下にスクリプトを作成します。
今回はscripts/helloworld.coffeeとしました。

# scripts/helloworld.coffee
module.exports = (robot) ->
robot.respond /HELLO$/i, (msg) ->
msg.send "world"

ざっくり説明すると、
robot.respond /HELLO$/i」で、正規表現で反応する文字列をマッチさせ、
msg.send “world”」で、レスポンスを返しています。

チャットからのメッセージを受信したり返信したりする処理は、Hubot側で行ってくれています。

Hubotのコンソールを立ち上げて、このスクリプトの動作確認をしてみます。
以下のコマンドを実行します。

$ bin/hubot

Heroku関連の環境変数の設定に関するエラーが出てきますが、
現状は問題ないのでエンターを押して、コマンドプロンプトを復活させます。

以下のようにHubotにメッセージを送信すると、メッセージが返ってきます。

Hubot> Hubot hello
Hubot> world!
Hubot>

このように、実際にSlack上で実行する前に、コンソールで動作確認することができます。

Slackと連携するBotを作成

SlackのIntegrationページでHubotと連携するための設定を行います。

「Hubot URL」は、Hubot設置予定のURLを設定します。

あとで参照するので、「HUBOT_SLACK_TOKEN」などの環境変数は覚えておきます。

今回のSlackボットは、Slack上で挨拶された場合に挨拶を返す仕様にします。
コードは以下のようになります。

# scripts/slack-hello.coffee
module.exports = (robot) ->
robot.hear /@hubot Hello/i, (msg) ->
username = msg.message.user.name
msg.send "Hello, " + username

robot.hear /@hubot Hello/i, (msg) ->」で、反応するメッセージを検出し、
username = msg.message.user.name」で、ユーザー名を取得し、
msg.send “Hello, ” + username」で、レスポンスしています。

このスクリプトをコンソール上で動作確認してみます。

$ bin/hubot
Hubot> hubot @hubot hello
Hubot> Hello, Shell
Hubot>

ということで、挨拶を返してくれました。

Slackと連携するBotを実行

本番でSlackと連携する場合は、実行時のオプション指定などが必要になってきます。
結論から言いますと、コマンドは以下のようになります。

HUBOT_SLACK_TOKEN=xxxxxxxxxxxxxxx \
HUBOT_SLACK_TEAM=xxxx \
HUBOT_SLACK_BOTNAME=hubot \
bin/hubot --adapter slack

HUBOT_SLACK_TOKEN」「HUBOT_SLACK_TEAM」「HUBOT_SLACK_BOTNAME」といった環境変数を設定しています。
これらはSlackのIntegration画面にありましたね。

また、–adapterオプションでアダプタ(slack)を指定しています。

これで、Hubotが立ち上がったと思います。
この状態で、Slack上に「@hubot hello」と打ち込めば返信が返ってくるはずです。

まとめ

Hubotでボットを作成する方法をご紹介しました。
scriptsディレクトリ下にスクリプトを追加していけば、
ボットの機能を増やしていけます。
慣れてくると気軽に開発できるので、ボットづくりが捗ります。
色々連携させて効率化していきましょう。

要素の選択について

近頃は朝夕の気温がめっきり下がり、外に出るのが億劫になってきています。
そんな時は自宅にこもり、先日発売されたモンスターハンター4Gなんかをやりたくなりますね…まだ持っていませんが…
社内でモンハン部が発足すれば、迷わず購入するのですが…|ω・`)チラ

閑話休題、業務でjQueryを用いて諸々の機能を実装するのですが、その際に少々悩むjQueryでの要素の選択について、自身の備忘録を兼ねて書きます。

DOM要素の選択

まず、jQueryでは容易にDOM要素の選択が行なえます。

$("body")

上記のコードだけでbody要素を選択することができます。

基本的なセレクタ(セレクター)指定方法

セレクタの指定方法には、タグを指定する以外にも様々なパターンがあります。
以下に基本的なセレクタ指定方法を記述します。

要素(タグ)セレクタ

$("div")

div要素が選択ができます。

idセレクタ


指定したidを持つ要素が選択できます。

classセレクタ

$(".hogehoge")

指定したclassを持つ要素が選択できます。

グループセレクタ

$("body, div, p")

指定した要素が選択ができます。

$("body, #hoge, .hogehoge")

また、上記コードのように、異なるセレクタでの指定も可能です。

ユニバーサルセレクタ

$("*")

全ての要素が選択ができます。
ワイルドカードでの指定です。

属性セレクタ

<a href="" target="_blank">リンク</a&gt

このようにtarget属性を持ったaタグがあるとして、

$("a[target='_blank']")

上記コードで、target=’_blank’の属性と値を持つaタグが選択できます。
また、属性セレクタには色々と指定方法があり、それについても記述します。

[属性名]

$("input[name]")

特定の属性を持つ要素を選択できます。

[属性名=値]

$("input[name="hoge"]")

属性の値が一致した要素を選択できます。

[属性名=!値]

$("input[name!='hoge']")

属性の値が完全一致しない要素を選択できます。

[属性名 *= 値]

$("input[name*='hoge']")

属性の値が部分一致した要素を選択できます。

<input name="hoge" type="text" >
<input name="hoge123" type="text" >
<input name="hoge hoga hogi" type="text" >

上記コードでは、全て対象です。

[属性名 ~= 値]

$("input[name~='hoge']")

区切られた単語ベースで一致した要素を選択できます。

<input name="hoge" type="text" >
<input name="hoge123" type="text" >
<input name="hoge hoga hogi" type="text" >

上記コードでは、1行目と3行目が対象です。

[属性名 ^= 値]

$("input[name^='hoge']")

値と前方一致した属性を持つ要素を絞り込みます。

<input name="hoge123" type="text" >
<input name="123hoge" type="text" >

上記コードでは、1行目が対象です。

[属性名 $= 値]

$("input[name$='hoge']")

値と後方一致した属性を持つ要素を絞り込みます。

<input name="hoge123" type="text" >
<input name="123hoge" type="text" >

上記コードでは、2行目が対象です。

階層構造でのセレクタ指定方法

基本的な指定方法では、ピンポイントでその要素の選択でしたが、階層構造でのセレクタ指定もできるので、子孫要素の選択などが可能です。
以下に基本的な子孫、兄弟要素を選択するセレクタの指定方法を記述します。

子孫セレクタ

$("body div")

body要素の中にある、div要素を選択できます。

$("body div.hoge")

上記のように、特定のclassを持ったdiv要素の選択などもできます。

セレクタ

$("body > div")

body要素の直下の、div要素を選択できます。

隣接セレクタ

$("h1 + div")```
h1要素の”すぐ”後に続く(隣接する)、div要素を選択できます。
<h3>兄弟セレクタ</h3>

$(“h1 ~ div”)

h1要素の後に続く(弟要素)、div要素を選択できます。
”兄弟セレクタ”と書きましたが、基準となる要素より後の要素のみが対象のようです。<br /><br />
以上が私が思う、ごく基本的なセレクタの指定方法のまとめです。
<h2><span style="color: #2196f3">まとめ</span></h2>
セレクタの指定方法は多くあり、今回の内容で全て網羅しているわけではありません。
私の知らないセレクタの指定方法もまだあるかと思います。
また、セレクタではなくjQuery関数で、先祖子孫、親子、兄弟要素の選択の方法や、フィルタと呼ばれるセレクタの指定方法もあります。
それらについては次回以降に書こうかと考えております。
<h2><span style="color: #2196f3">後述</span></h2>
今回も至極当然な記事になってしまった…が、備忘録も兼ねているということでよしとします。
頻繁に利用するので、作業の度に調べることの無いようにしよう。

".on()"での"hover"の記述でつまずいたので

初秋の候、皆様お変わりなくお過ごしでしょうか。
私は年齢のためか、右足太ももに激痛を感じている今日この頃です…

さて、話は変わりまして、業務でjavascriptでプログラムを作成していた時のことなのですが、動的に生成される要素に”hover”で動作を設定したかったので、単純に”.on()”で処理をしようと考えたのです。

“.on()”で”hover”を機能させるには

“.on()”に”hover”を引数として書いても機能しない

$(".hoge").on("hover", function(){...});

まず単純に考えて上記の様に記述したのですが、見事に動作しませんでした…
動作すると思い込んでいたため、見当違いな部分を修正したりして、つまずき時間を費やしてしまいました。

“.hover()”は”.mouseenter()”と”.mouseleave()”

とりあえず、私のちっぽけな頭脳では全く解答が導き出せなかったので、Google先生に相談しました。
すると、「”.hover()”は”.mouseenter()”と”.mouseleave()”をまとめたものである」とのことでした。
なるほど、つまりそもそも引数に”hover”を渡すということが間違いだったようです。

“.mouseenter().mouseleave()”を”.on()”で記述

ということで、Google先生の相談の結果、書き直すと

$(".hoge").on({
"mouseenter": function(){...},
"mouseleave": function(){...}
});

上記コードになります。
これで”.on()”での”hover”の記述するということはできました。

しかし、もう一声

先ほどのコードでは、動的に生成される要素には適用されません。
ですので、動的生成要素に対応する場合はコチラ

$(document).on({
"mouseenter": function(){...},
"mouseleave": function(){...}
}, ".hoge");

“document”の部分は親要素が決まっていれば、その親要素の指定で大丈夫なようです。
上記コードで私の思っていた動作が無事実現できました。

後述

私がまだまだ未熟というか圧倒的に知識、技術が乏しいので、ごく当然なことだったのかもしれませんが、記事にしました。
調べたことは(なるべく)忘れないよう身に付けて、成長していこうと思います。

全く話は変わるのですが、”つまずく”って「爪(つま)突(づ)く」の意のようですが、”つまづく”ではなく”つまずく”と書くのがどうも一般的なようですね…知らなかった…

参考サイト

tacamy.hatenablog

isucon3 予選で敗退しました(うさぎ工房)

isuconは初回からずっと出ているのでこれで3回目。

いつもは同僚の@shokiri @memememomo (Uchiko) 、僕、の3人で出場するのですが
お互いの予定の折り合いがつかず、僕は出場できない可能性が出てきました。
でも僕はどうしても出場したい・・・!

そこで、いつもの社内メンバーは「進撃の超大型パティスリー兄弟」
僕は一人ソロ活動で社外の友人(@gom_oh)や元社員(ttoz)を誘って「うさぎ工房」として予選登録しました。

僕自身がOps側である所や、メンバーのプログラマPerlPSGI/Plackは初めて触る二人だったので
集まって過去ISUCONで自家製ISUCONしたり、クエリ最適化について勉強したりといった準備をしました。

結果はスコア的には5300でfinish。見事敗退となりました。

ちなみに弊社の本チームである「進撃の超大型パティスリー兄弟」チーム側は
なんと総合4位で予選通過!さすがです!
若干悔しさもあるけど、弊社から本戦にいく人がいて、本当に嬉しかったです。おめでとうございます!
そちら側の詳細はきっと彼らが記事にしてくれるはず。本戦でもばっちり頑張ってください!

こちらの記事は点数の低い僕らがやった事なので、
アンチパターンとして楽しんでいただければ。

最終構成

最終的には varnish perl mysql とちょっとだけmemcached の構成でした。

phpMyAdminを立ち上げる

まず、MySQL関連の操作でphpMyAdminしか使えない僕はphp5.5をソースコンパイル
ビルドインサーバーとして立ち上げました。これ便利ですね

/usr/local/lib/php -S 0.0.0.0:3000

my.cnfを設定

APIキー登録して初回ベンチが確認する。たしか800くらいでした。
初回ベンチですぐにDBボトルネックとわかったので、my.cnfを以下に変更。
(ええ、もちろん find / -name my.cnf しました。)

key_buffer = 512M
max_allowed_packet = 10M
table_open_cache = 10240
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 1M
thread_cache_size = 128
query_cache_type= ON
query_cache_size= 16M
thread_concurrency = 8
innodb_flush_log_at_trx_commit = 0
innodb_file_per_table
innodb_additional_mem_pool_size=40M
innodb_log_buffer_size=32M
innodb_log_file_size=256M
innodb_buffer_pool_size=8000M
max_connections = 2048
max_connect_errors = 10000
tmp_table_size=1342177280
max_heap_table_size = 1342177280

インデックスを張りました

最終的にはcreated_atとか使ってなかったので無駄だった。

ALTER TABLE `memos` ADD INDEX ( `created_at` ) ;
ALTER TABLE `memos` ADD INDEX ( `user` ) ;

ここらへんで1500くらいだったかな。

フロントエンドはVarnish

フロントエンドはVarnishを使用。
編集や削除はされないようだったので、なんとかリクエストヘッダの値から「ログインしているか否か」を判別して全体キャッシュできないか考えてましたが、リクエストヘッダで判断できる材料がなく、また、Plackとか全然わからないのでヘッダーの修正とかはできませんでした。

結局フロントエンド側での大規模なキャッシュは僕の力では厳しそうだったので
静的ファイルだけvarnishでキャッシュ。設定の主要部分だけだけど以下のような感じ。

backend web1 {
.host = "127.0.0.1";
.port = "5000";
}
sub vcl_recv {
set req.backend = web1;
if (req.url ~ "\.(jpg|png|gif|css|js|ico)$") {
return (lookup);
}
return (pass);
}
sub vcl_fetch {
set beresp.ttl = 86000s;
return (deliver);
}

スキーマとかSQLの改修

ここらへんで2500くらいだったかな。
この時でもDBボトルネックはまだまだ明らかでしたので
ここでメンバーの@gom_ohがDBに以下の改修を行いました。

内容は公開IDの一覧だけのテーブルを作ってtopページやrecentページのDB負荷を削減する、といった感じの修正となります。

CREATE TABLE `public_id` (
`memo_id` int(11) NOT NULL,
PRIMARY KEY (`memo_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;'

public_idというmemosテーブルでパブリックに公開しているだけのmemo_id一覧を入れるテーブルを作成しました。
それから、ベンチ実行後のスクリプトで現在公開中である記事のIDをインサート

INSERT INTO public_id (memo_id) SELECT id FROM memos WHERE is_private = 0 ORDER BY id DESC;

上記は初期スクリプトで実行。

#公開ページの総数
SELECT count(*) FROM memos WHERE is_private=0SELECT count(memo_id) FROM public_id
#TOPページ
SELECT * FROM memos WHERE is_private=0 ORDER BY created_at DESC, id DESC LIMIT 100SELECT m.id, u.username, m.created_at, m.content
FROM memos m
JOIN (
SELECT p.memo_id
FROM public_id p
ORDER BY p.memo_id DESC
LIMIT 100
) t
ON m.id = t.memo_id
JOIN users u
ON u.id = m.user;
#recentページ
SELECT * FROM memos WHERE is_private=0 ORDER BY created_at DESC, id DESC LIMIT 100 OFFSET %d", $page * 100

SELECT m.id, u.username, m.created_at, m.content
        FROM memos m
        JOIN (
          SELECT p.memo_id
          FROM public_id p
          ORDER BY p.memo_id DESC
          LIMIT 100 OFFSET %d
        ) t
        ON m.id = t.memo_id
        JOIN users u
        ON u.id = m.user',
        $page * 100);

これでスコアが5000くらいになりました。

Markdownの結果をmemcacheでキャッシュ

その他はMarkdownの処理が重かったので、ここだけmemcacheでキャッシュとか、ちまちまして5300くらいに。
まんまとポート11211につないでましたが。

あとどこかのタイミングでStarmanからStarletに変更しましたがスコア的に動きはなし。
最終的にはまだまだDBがボトルネックなまま5300でフィニッシュとなりました。

感想

初日に「1位の人とか人間なの?」と思ってたのですが、
2日目の弊社メンバーが1位に輝いてて、出先からの発表見てのけぞった。
どんな事をしたのか聞くのが楽しみです。

競技中も楽しかったのですが、普段なかなか会えない友達や元同僚と集まって
お菓子ほおばりながら共通の目的をもって取り組んだ時間が勉強になったし楽しかった。
特に普段は他の二人にまかせていた所を本腰を入れて取り組まないといけない状態だったので、
今まで以上にソースを見たりDB構造を見たり、という部分に入っていけたのがよかったです。

反省点としては、

[READMEをしっかり読んで意識を共有しておけばよかった]
workloadがAMI提出時のコマンド入力で気づきました。「ただボトルネック調査の為に負荷を大きくできる」くらいの認識しか持ってなくて(んなわけないのに)、、、試せる事はちゃんと試すべきでした。結果、一度もWorkloadを変更してなかった!!

[とりあえずperlだろみたいな雰囲気になってた。]
やりたい事をちゃんとやれる言語でやる道も検討したらよかったと。PHPで着実なボトルネック修正で予選抜けたところもあってそう思いました。「こうしたら早くなりそう!」→「Perl、、というかPlackって奴でどうやんの。」→「わからん」、のコンボが多かった。

ISUCONは参加者は楽しいけど、運営の方々は本当に大変そうで少し申し訳ない気持ちに。
運営の皆様本当にありがとうございました。

そして「進撃の超大型パティスリー兄弟」、本戦がんばれー!

おまけ

終了後に本番ベンチが解放されていたのでWorkload 5くらいでまわした結果

Result:   SUCCESS
RawScore: 8285.3
Fails:    0
Score:    8285.3
[OK] 結果を管理サーバに送信しました

ちょっとあがった。

JQuery Mobile 関連 セレクトボックスやラジオボタンを js から操作する時の注意点

jQueryMobile でセレクトボックスの要素を選択状態にしたり、ラジオボタンにチェックをつけたりといった操作を JavaScript から行っても、画面表示に変化がないという事象になったので調べました。

値のなどの操作を行った後に、描画の更新が必要でした。

下記のようなコード対応できます。

セレクトボックスの描画を更新する。

$("#myselect").selectmenu('refresh');

© SEEDS Co.,Ltd.