株式会社クイックのWebサービス開発blog

HAPPYなエンジニア&デザイナーのブログです

UIデザインにおける8つの黄金律について考えてみた〜【後編】

こんにちは、最近Adobe XDがAfter Effectsとの連携ができるようになって、インタラクション作成にハマっているデザイナーAchanです。

前回はベン・シュナイダーマン氏が提唱した「UIデザインにおける8つの黄金律~前編」の話をしましたので、今日はそれの続きです。

1. エラーに簡潔に対処できるようにしよう

ウェブサイトやアプリを利用する際に、ユーザーがつまづく場合(ヒューマンエラー)があります。まず初めにデザインの段階でエラーが起きないようにすべきではないかと思います。そのためにはエラーの種類を理解することが大切です。

人間中心のデザイン原則『誰のためのデザイン?』(著者ドナルド・ノーマン氏)によると、エラーには大きく「スリップ」と「ミステーク」という二種類があると挙げられています。 f:id:aimstogeek:20181115191426j:plain

① スリップ

スリップとは実行段階の失敗です。やりたいことをユーザーが正しく認識していても、意図通りにうまく行かなかったり、誤操作をしてしまったりすることを指しています。例えば:

  • テキストリンクやボタン周りの余白が足りず、隣接したテキストリンクやボタンをタップしてしまう。
  • 入力フォームに入力しようとしても見ただけでは操作方法がわからず色々試行し、入力完了まで時間がかかってしまう。
  • スマホサイトで横スクロールしようとしたら、スワイプ操作が画面の左端すぎて前に開いていたページに戻ってしまう。

② ミステーク

ミステークとは計画段階の失敗です。ユーザーの記憶や認識の違いによりうまくいかないことを指しています。例えば:

  • リンクではない箇所をリンクだと思い、クリックしてしまう。
  • 検索機能の代表アイコン「虫眼鏡」を「目」などの見慣れていないアイコンに変えると、ユーザーがそれを検索機能だと認識できずユーザビリティが低下してしまう。
  • 汎用のショートカットキーを独自のものに設定してしまうと、ユーザーの意図通りのことができず操作性が悪くなってしまう。

以上、エラーの種類を理解すれば、まずある程度エラーを防げると言えるでしょう。 もちろん、すべてのエラーを防げるとは言えませんが、万が一エラーが発生した場合は優しく、わかりやすいメッセージでユーザーに知らせましょう。肝心なのは何が問題なのか、具体的にどうしたら解決できるのかを瞬時に理解してもらえるにデザインしましょう

2. アクションを簡単にやり直せるようにしよう

ヒューリスティックスとしては「ヤコブ・ニールセンのユーザビリティ10原則」にも同じことが挙げられています。

ユーザーコントロールと自由度(User control and freedom)

ユーザーはシステムの機能を間違って選択することがよくあるので、その不測の状態から別の対話を通らずに抜け出すための、明確に表示された"非常出口"を必要とする。"取り消し(undo)"と"やり直し(redo)"を提供せよ。

例えば先月リリースされたPhotoshop CC(v 20.0)。リリース前では「取り消し」は汎用ショートカットCommand+Zで1回前の操作にしか戻れず、それ以上遡るにはCommand+Option+Zを押すか、「ヒストリー」ツールで戻る必要がありすごく不便に感じていました。今はIllustrator と同様にCommand+Zだけで連続して取り消し操作を行う事ができるようになり、作業効率が劇的に上がりました。(「やり直し」は従来通りShift+Command+Z)

アプリやウェブデザインでは、わかりやすい場所に「取り消し」や「やり直し」があるとユーザーにやさしいです。例えば下記のメールアプリ、メールをうっかり削除した場合、ユーザーの邪魔にならないように「取り消し」を設置することで、ゴミ箱から誤って削除したメールを探す手間が省けます。

f:id:aimstogeek:20181115191631g:plain

3. ユーザーに主導権を持たせるようにしよう

ユーザーに主導権を持たせる上で必要なことは、今何を見ているのか、そして目的を達成するためには何をしなければならないのかを理解させることです。
典型的な例は検索エンジンです。ユーザーが検索エンジンを使ってウェブ上の見たい情報を自分でコントロールすることができます。

また、システムの都合で強要する操作を減らし、ユーザーが常に自分の意思にもとづいて選択、作業を進められるようにするのも大事です。例えば、8月にGmailのデザインがリニューアルされた際に、右下に小さなポップアップの更新予告に気づきましたか? f:id:aimstogeek:20181115191743j:plain

基本人間が一旦使い慣れたものがいきなりガラッと変わると作業上に混乱をもたらします。さすがGoogle大先生、その問題を意識して、ユーザーに主導権に与えるために色々工夫されたのではないかと思います。

  • 自動更新(強制)ではなく更新予告
  • 更新後の不安を解消するため詳細まで確認できる
  • 更新期間を設けている
  • 気になる方が今すぐ更新できるようにしている

さらに、新デザインに更新して、期間内で気にならない場合は以前のGmailに戻すこともできます。

ちなみに、ユーザーに主導権を持たせる設計方法として「オブジェクトベースUI設計」(OOUX と表記される場合もあります)が最近注目されてきています。興味がある方は調べてみてください。

4. 短期記憶の負担を減らそう

短期記憶とは、人間が瞬間的に覚えておける記憶のことで、数十秒から数分で忘れてしまう記憶です。認知心理学の教授であるネルソン・コーワン氏により人間の短期記憶の容量限界は4±1チャンクと発表され、現在は定説となっています。 f:id:aimstogeek:20181115191837j:plain

携帯番号を例にすると、「09067894321」は1つのチャンクとして11個の数字で構成されているため、それ自体を覚えるのは難しいでしょう。しかしこれを「090」-「6789」-「4321」と3つのチャンクに分けると、各チャンクは3か4個の数字になり、記憶に留まりやすくなります。

したがって、情報を整理した上で、人に覚えてもらいたい情報を伝える時には、なるべくシンプルに、3~5個以内にすることが大切でしょう。

まとめ

以上、ベン・シュナイダーマン氏が提唱した「UIデザインにおける8つの黄金律」についての考えでした。画面に表示される内容やレイアウトなどを設計する際に、皆さんの業務の一助になれば幸いです。

前編が気になる方はぜひ下記のリンクをクリック〜 aimstogeek.hatenablog.com



\\一緒に『明日のはたらくを創る』仲間を募集中です!! // 919.jp

AWSのKinesis Firehoseを使ってEC2のログをElasticsearchに飛ばして可視化した話

AWSを使うと非常に簡単にアクセスログの可視化が出来ます!感動しました!
今更感はありますが、ログを可視化してグラフ化する手順を書きたいと思います。
おはこんばんちは、SREのmatsBです。

使うAWSサービス

構成イメージ

f:id:aimstogeek:20181109154910p:plain

Amazon Elasticsearch Serviceの設定

ドメインの定義

特にこだわりとか無ければ最小構成でポチポチ設定していくだけです。
まずは、好きなドメイン名を付けます。

f:id:aimstogeek:20181109171658p:plain

クラスターの設定

構成を選んでいきます。
今回はテストとしてなので、最小構成を選んでいます。

f:id:aimstogeek:20181109171707p:plain

アクセスの設定

アクセス制御方法を選んでいきます。
VPCアクセス」でもいいのですが、Amazon Kinesisを使う時にVPCを意識しながら使わなきゃいけなくなります。
弊社の場合は「パブリックアクセス」の方が都合が良いので、そちらを選択しています。
自分の接続元IPを選んで追加します。

f:id:aimstogeek:20181109171723p:plain

確認

最後に確認をして問題なければ完了です。

f:id:aimstogeek:20181109171749p:plain

Amazon Kinesisの設定

Name and source

stream nameはEC2がFluentdを設定する時の「delivery_stream_name」で使います。

f:id:aimstogeek:20181109171800p:plain

Process records

ここはデフォルトのまま「Next」でいきました。

f:id:aimstogeek:20181109171809p:plain

Select destination

飛ばす先を「Amazon Elasticsearch Service」にして、上記で作ったElasticsearchのドメイン名を入れます。
Index名は分かりやすい文字列を入れました。

f:id:aimstogeek:20181109171821p:plain


上記画像の下の部分ですが、バックアップとして飛ばすS3を設定していきます。
今回は「Failed records only」を選択してますが「All records」を選べば、Fluentdで飛んできたログ全てが保存されます。
別の方法でログを見たい時や解析したい時に活用できます!
あと、Apacheのログフォーマットや、それを飛ばすFluentdの設定をちゃんとやらないとElasticsearchに飛んでも解析してくれません。
ちゃんと出来てるかの不安があれば、全ログを取って都度確認したほうがいいと思います。

f:id:aimstogeek:20181109171830p:plain

Configure settings

「Buffer size」は「1」、「Buffer interval」は「60」に設定しました。
最小値にしてるのはできるだけリアルタイムに近づけるためです。
逆にいうと、Kinesisを使ったログの可視化はリアルタイム性は捨てなきゃいけないです。
IAM roleの設定も必要なので、ここで設定します。

f:id:aimstogeek:20181109171840p:plain

ロールの設定

IAM roleのポリシーはもう用意されてるので、それを流用して設定します。

f:id:aimstogeek:20181109171849p:plain

Configure settings

設定するとこんな感じでIAM roleが入ります。

f:id:aimstogeek:20181109171859p:plain

Review

確認画面で問題なければ作成完了です。

f:id:aimstogeek:20181109171908p:plain


EC2の設定

EC2の前提

Apacheが動いていてログが出力されてる事が前提です。
今回はアクセスログを投げて解析しますが、用途によっては他のログを飛ばしてください。
ログの出力先は

CustomLog /var/log/httpd/919/919-access_log combined_ltsv

としていて、ltsvを前提としています。
ログフォーマットは下記のようになっています。

LogFormat "remote_ip:%a\tx_f_protocol:%{X-Forwarded-Proto}i\tremote_host:%h\tident:%l\tuser:%u\ttime:%{%d/%b/%Y:%H:%M:%S %z}t\treq:%r\tmethod:%m\tpath:%U%q\thttp_protocol:%H\tstatus:%>s\tsize:%b\treferer:%{Referer}i\tua:\"%{User-Agent}i\"\tresponse_time:%D" combined_ltsv

Fluentdのインストール

Amazon Linuxを使ってるので、yumでインストールします。

$ yum install td-agent

fluent-pluginのインストール

kinesisに関するプラグインはいくつかあるのですが、awslabsが公開している「fluent-plugin-kinesis」を使います。

$ gem search -rd fluent-plugin | grep kinesis
fluent-plugin-in-kinesis (0.0.2)
    Homepage: https://github.com/yusukeyamatani/fluent-plugin-in-kinesis
fluent-plugin-kinesis (2.1.1)
    Homepage: https://github.com/awslabs/aws-fluent-plugin-kinesis
fluent-plugin-kinesis-aggregation (0.3.1)
    https://github.com/atlassian/fluent-plugin-kinesis-aggregation
fluent-plugin-kinesis-alt (0.0.2)
    Homepage: https://bitbucket.org/winebarrel/fluent-plugin-kinesis-alt
fluent-plugin-kinesis-firehose (0.1.1)
    https://github.com/winebarrel/fluent-plugin-kinesis-firehose
fluent-plugin-kinesis-intuit (2.1.1)
    https://github.intuit.com/cloud-logging/aws-fluent-plugin-kinesis-in

インストールをします。

$ td-agent-gem install fluent-plugin-kinesis

インストールされたことを確認します。

$ td-agent-gem list | grep kinesis
fluent-plugin-kinesis (2.1.1)

td-agentの設定

td-agentにkinesis用の設定と飛ばすログの設定を追加します。

$ vim /etc/td-agent/conf.d/919_apache.conf
<source>
  @type config_expander
  <config>
    @type tail
    #format none
    format ltsv
    time_format %d/%b/%Y:%H:%M:%S %z
    path /var/log/httpd/919/919-access_log
    pos_file /var/log/td-agent/919-access_log.pos
    tag 919-dev.apache.${hostname}
  </config>
</source>

<match 919-dev.apache.*>
  @type kinesis_firehose
  delivery_stream_name 919-logs
  region ap-northeast-1
  random_partition_key true
</match>

ちなみに、一番最初に読み込まれるconfigはこんな感じになっています。

$ vim /etc/td-agent/td-agent.conf
@include conf.d/*.conf

<match fluent.**>
  @type file
  path /var/log/td-agent/fluent.log
</match>

config に誤りが無いかを確認してtd-agentを再起動します。

$ td-agent --dry-run -c /etc/td-agent/td-agent.conf
2018-11-09 16:40:15 +0900 [info]: parsing config file is succeeded path="/etc/td-agent/td-agent.conf"
2018-11-09 16:40:15 +0900 [info]: starting fluentd-1.2.0 as dry run mode ruby="2.1.10"

$ /etc/init.d/td-agent restart
td-agentng td-agent:                                       [  OK  ]

kibana

これで設定は完了になります!
あとはAWSのElasticsearchにKibanaが用意されてるので、Kibanaで見たい条件などを入れれば可視化出来ます。
ちょっと見せられる部分が少ないのですが、イメージとしてこんな感じに入ってくると思ってもらえれば!

f:id:aimstogeek:20181109164739p:plain


そして今のままのアクセスログだとtime_formatがElasticsearchに無いので追加する必要があります。
具体的には下記のElasticsearchのデフォルトで用意されてるフォーマットに合わせるかこちらでフォーマットを作って時間を認識してもらう必要があります。
format | Elasticsearch Reference [6.4] | Elastic

最後に

リアルタイム性は無いですが、運用するコストがほとんどないのでとても楽にログの可視化が出来ます。
ただ、可視化することがゴールではなく、可視化して分析して次に繋げるが最終的な目的になります。
これからのエンジニアは分析能力も問われてくるってことですね!





\\一緒に『明日のはたらくを創る』仲間を募集中です!! //
919.jp

RPAツールを使って簡単にロボット作れるのか試してみた

こんにちは。入社1年が経ちました。パパ歴は4ヶ月、「こってぃ」でございます。

ここ数年、やたらと「RPA」ってワード見かけますよね。
でも見かけるだけで、実際に何が出来るのかよく分からんって人、結構いらっしゃるんじゃないかと思います。

私も全然知りませんでしたが、業務効率化を図れるなら、何かしら使えるかもしれんなと思い、とりあえず社内で一番RPAに詳しいおじさんになろうと試みました。

いろいろ調べてみると、メジャーどころのツールの中に、評価や研修目的であれば無料で使えるものがあるとの事なので使ってみました!

そう、UiPathのCommunityEditionです!!

www.uipath.com

今回は、RPAの1つである、「UiPath」を使ったら、自己学習のど素人が、どれだけ簡単にロボットが作成できるのかを検証してみようと思います。

読んで欲しい人

  • UiPathをほとんど使ったことがない人
  • 試しにUiPathのCommunityEditionを入れたものの使い方よく分からん人
  • 上司からRPA入れろやって圧かけられたけど、何が出来るんか全然分からん人
  • UiPathを使ってロボット作ってみたいけど、手始めに何を作ってみればいいか分からん人

今回設定してみるロボット

RPAのデモを見たことがある人なら一度は見せられたであろうあの作業。
そう、「Webサイトから情報を取得して、Excelに保存する」というプロセスを、UiPathを使って実装してみようと思います。

交通費精算処理と並ぶ2大RPAデモあるあるですよね←(知らんがな)

今回は価格.comのサイトより、macの売れ筋ランキングの商品名、URL、価格の一覧を取得してみますね。

細かい設定の話は今回しないので、そこはご了承ください。
ただ、設定の画面は少しお見せ出来るので、何か参考になれば嬉しいです。

事前準備

  • UiPAthのCommunityEditionのインストール
  • GoogleChromeExcelなどを利用するためのパッケージのインストール


サイトから情報を取得するために使用した機能 

  • ブラウザーを開く(Open browser)
    操作するURLをブラウザで開きます。

  • データスクレイピング(Data Scraping)
    マウスで指定したデータを取得します。

    データをExcelに出力するために使用した機能

  • Excel アプリケーションスコープ(Excel Application Scope )
    どのExcelを使うのかを指定します。
    ファイルが存在しない場合は作成することも可能です。

  • 範囲に書き込む(Write Range)
    保存したデータをExcelに書き込みます。

全力で作成してみた

どんだけ簡単にロボット作れるんじゃいって事で、
上記の機能を組み合わせて設定作業をしてみます。

  1. どのサイトを開くか設定する
    f:id:aimstogeek:20181101171736p:plain

  2. 取得するデータを選択する
    f:id:aimstogeek:20181101171957p:plain

  3. 取得したデータを確認する
    f:id:aimstogeek:20181101171824p:plain

  4. どのExcelに出力するか設定する
    f:id:aimstogeek:20181101171711p:plain

  5. 書き込み場所を設定する
    f:id:aimstogeek:20181101172123p:plain


    頑張って作った結果、2分程でデータ取得のロボットが作成されました!!
    本当は動画準備してたんですけどね。画像の羅列だと伝わらないこの簡単さ。。


ロボットを動かしてみる

いや、ほんとに出来てるの?って思いませんでしたか?
安心してください!完成しています!!

全力で作成したロボットの活躍をご覧ください。

f:id:aimstogeek:20181101183706g:plain


少し見にくいですが、最初は空のフォルダだったのが、
気づけばExcelが作成されているのにお気づきいただけるでしょうか。

そのExcelの中には、Webサイトから取得した情報が格納されているじゃないですか!
f:id:aimstogeek:20181101190910p:plain


ロボットに任せてしまえばかなりのスピードで処理出来てしまうんですね^^

所感

確かに僕みたいにプログラミングほとんどやってないような人間でも、
直感で簡単なロボットなら作成できるなぁと思います。

ただ、実運用に乗せるには、どうやってエラー対処するかとか、
前後のプロセスどう変えていくかとか、
結構クリアすべきハードルは高いのではないかなという印象です!

実際の業務は今回作成したロボットが行っているような、
単純作業ばかりではないですもんね・・

世の中でバズワードのように言われているRPAですが、
何が出来て、何が出来ないのかを正しく理解し、どこに活用するかを考えれば、
生産性向上に寄与出来るのではないでしょうか。

バズワードに惑わされることなく、自分がどんな価値を提供出来るのかを
きちんと把握した上で、今後仕事に取り組む必要がありますね。

子どもとお風呂入るために早く帰らなきゃ。業務効率化、生産性向上、興味あります。
(ほんとは飲みに行きたい)
じゃぁね。



\\一緒に『明日のはたらくを創る』仲間を募集中です!! // 919.jp

ゲシュタルトの法則をおもいだしてみる

こんにちは、いのっちです。

今日は人間がものを見るとき、塊としてまとめて知覚してるよという話。
そう、ゲシュタルトの法則をご紹介します。

ゲシュタルトの法則とは

人がものを見て知覚するとき、無意識の内にまとめてみる特性があり それが起こる際の法則をゲシュタルトの法則といいます。

ゲシュタルトの法則は下記の7つがあります。

ゲシュタルトの法則
1.近接 (Ploximity)
2.類同(Similarity)
3.連続(Continuity)
4.閉合(Closure)
5.共通運命(Common Fate
6.面積(Area)
7.対称性(Symmetry)

さて、どんなものか見ていきましょう。

近接 (Ploximity)

距離が近いものをグループとして認識します。

↓の画像を御覧ください。どのように見えますか?

f:id:aimstogeek:20181026112457p:plain:w300

きっと、このようなグループであると感じたのではないかと思います。

f:id:aimstogeek:20181026113214p:plain:w300

類同(Similarity)


類同は色、形、向きなどが同じものをグループとして認識します。

f:id:aimstogeek:20181026124704p:plain:h300

上の画像も↓のように感じますよね
f:id:aimstogeek:20181026125204p:plain:h300

連続(Continuity)


連続は線を見た時、変化や切れ目がない1本の線としてみることです。

f:id:aimstogeek:20181026132903p:plain:w300
この画像はどう見えますか?

f:id:aimstogeek:20181026133133p:plain
きっと、①のような2本の線に見えたのではないでしょうか。
②や③のような線が集まっているようには感じられなかったと思います。

閉合(Closure)


閉合は閉じた形をみたときに1つのグループとしてみることです。

f:id:aimstogeek:20181026135910p:plain:w300
それでは見てみましょう!

f:id:aimstogeek:20181026135723p:plain
これも①のような3つの楕円が重なっていたように見えますよね。
②のような欠けた楕円と模様の入った楕円であるとは思わなかったのでは無いでしょうか。

共通運命(Common Fate


移動の方向や点滅などの周期が同じであるものをグループとしてみることです。

f:id:aimstogeek:20181026150011p:plain:w300

上2つのマルが左、下2つのマルが右に動いている場合、↓のようにグループ化して見てしまいます。

f:id:aimstogeek:20181026151634p:plain:w300

面積(Area)


図形の中に図形がある場合、中の図形をメインの図形として認識します。

f:id:aimstogeek:20181026154859p:plain:w300

対称性(Symmetry)


左右対称のものには、何らかの意味を見出してしまいがち

f:id:aimstogeek:20181026162350p:plain
生成したランダムドットの画像(左)を加工して、左右対称化した画像(右)を作りました。どこか気になる点はあるでしょうか。

f:id:aimstogeek:20181026163051p:plain
円で囲んだ部分、何か顔に見えてきません?
顔があると、なんだか意味のある画像に思えてきます。

最後に

実は「ゲシュタルト」って言いたかっただけなんです。
なんか、中二っぽくてかっこいいですよね。
ゲシュタルト

ゲシュタルトの法則は日常のデザインの中でよく使われています。
皆さんの身の回りのものを法則に照らし合わせ、「あっ、あれは○○の法則だな」とニンマリしてみると、楽しくデザインについて素養がつくと思います。ぜひお試しを。


\\ 『明日のはたらくを創る』仲間を募集中!! // 919.jp

あなたのスプシがもっとスマートに。ARRAYFORMULA編

こんにちは、ねこです。
ここ半年くらいスプレッドシート(※以下スプシ)で設計書を作っては投げ、データをまとめては投げておりまして、 日々その便利さに感動しもうエクセルには戻れない体になってしまいました。

さてスプシに慣れてくるとあちこちで便利だ便利だと言われているのを見かける伝説の関数、ARRAYFORMULAさん…*1
私もつい最近やっと使い方がわかったので、sanameko先生のINSERT文作成スプシを改良する形で紹介したいと思います!

aimstogeek.hatenablog.com

ARRAYFORMULAさんとは

公式ページには

配列数式から返された値を複数行または複数列に表示したり、非配列関数で配列を使用したりすることができます。
ARRAYFORMULA - ドキュメント エディタ ヘルプ

とありますが正直なんのこっちゃって話なので次に行きましょう。
数式を各行で使いたいときってオートフィルで複製しますよね。
ARRAYFORMULAさんは適用させたい範囲を指定してあげればそれをやってくれる関数です。
しかもこの方だけ入力するためのショートカットキー付きです。*2

・数式の編集中に Ctrl+Shift+Enter を押すと、数式の先頭に ARRAYFORMULA( を追加できます。
ARRAYFORMULA - ドキュメント エディタ ヘルプ

""格""を感じる……

ARRAYFORMULAさんの使い方

ARRAYFORMULAさんの使い方はいろんな人がもう記事にしてるんですが
わかりやすいのは下記の手順だと思います。

  1. いつもどおり一行用の数式を書く
  2. Ctrl+Shift+Enterする(ARRAYFORMULAさんの追加)
  3. 数式内のセル範囲を適用したいとこまで広げる

sanameko先生の式で言うと、作業用のF4セルにいれるこちらの数式

=SUBSTITUTE(VLOOKUP(A$2,$M:$N,2,false),"@@@",A4)

VLOOKUPとSUBSTITUTEの適用したい範囲は下記図になりますね。 f:id:aimstogeek:20181019155806p:plain

というわけでそのとおりに広げてあげるだけ!

A$2 → A$2:E$2
A4 → A4:E6

=ARRAYFORMULA(SUBSTITUTE(VLOOKUP(A$2:E$2,$M:$N,2,false),"@@@",A4:E6))

f:id:aimstogeek:20181019163239g:plain
きゃーかんたん!

これで100行とか1000行とかオートフィルのためにスクロールしなくても良いのです。

応用編

このままINSERT文生成セルも適用しちゃいましょう。
と言いたいところですがここでつまずきポイントがあります。
JOINさん*3です。

何がアレかっていうとこの関数の指定方法、単一セルじゃないんですよね。
既に行または列指定なのです。
当然ですがARRAYFORMULAさんをつけても複数行指定すると単一行にしなさいと怒られます。

f:id:aimstogeek:20181019161120p:plain
ごめんなさい…

こういうときはとりあえずTRUEになるIF文を挟みます。

=IF(A4<>"", "INSERT INTO "&$A$1&" ("&JOIN(",",$A$3:$E$3)&") VALUES ("&JOIN(",",$F4:$J4)&");"), "")

id列が空じゃなかったら、INSERT文を作成」ってしておきました。
これをARRAYFORMULAさんで包んでIF文の範囲を拡大します。

A4 → A4:A

=ARRAYFORMULA( IF(A4:A<>"", "INSERT INTO "&$A$1&" ("&JOIN(",",$A$3:$E$3)&") VALUES ("&JOIN(",",$F4:$J4)&");"), "") )

範囲をA4以下の全行(A4:A)にしたことで、行を追加したときも数式の変更なくINSERT文が生成されます。

f:id:aimstogeek:20181019164844g:plain
これで数式コピーは卒業しよう

まとめ

公式ページを見ても使い方がいまいちわからないARRAYFORMULAさん、
使うコツは「一度いつもどおり数式を作ってからARRAYFORMULA、範囲を拡大」です。
ぜひ覚えて使ってみてくださいね😉✨✨


\\ 『明日のはたらくを創る』仲間を募集中!! // 919.jp

*1:敬意を表して本記事ではさん付けします。

*2:ARRAYFORMULAって打つのめんどいですしね。

*3:すごくお世話になっているのでさん付けしています。

Amazon CloudSearchを簡易の検索用DBとして気軽に使う【事例・プログラミング不要】

プランナー兼ディレクターのyumeです。

複数のツール・システムを運用するケースって非常に多いと思うのですが、 だいたいの場合、しばらく経つと

「ツールAでシステムBの情報を検索した結果を取ってきてゴニョゴニョしたい!」

ってなりますよね。

そういうときに、すぐAやBの改修ができるエンジニアに依頼できる状態ならよいのですが、 他の案件にかかりきりで、地味な改修を誰にも依頼できない…ってこともよくありませんか?

そんなときに、Amazon CloudSearchという手段も検討してみてはいかがでしょうか。

こんな要件にオススメ

  • 検索対象のデータを出力したファイルを生成できる
    • XMLまたはJSONだと自動化も可能!
  • APIで条件検索した結果を取得できるようにしたい
  • ただしAPIの自前開発をする余力がない
  • (既にAWSを使っていて、新たにアカウント発行とかクレカ登録とかする必要がない)
  • (検索対象が膨大なサイズでない)

CloudSearchって?

Amazonが提供している、検索ソリューションを簡単に構築できるサービスです。
日本語のあいまい検索やサジェストの提示ができるので、弊社では以前からサイト内検索に利用しています。

Amazon CloudSearch (クラウド内の検索サービス)| AWS

え!?CloudSearchって文書検索じゃないの!?

CloudSearchと言えば、「日本語解析して単語ベースで検索」「自動入力候補の表示」などの目玉機能があり、なんとなく

「フリーテキストで検索するシーンで使うんだろうな〜」
「複雑な検索するのに向いてるサービスなんだろうな〜」

と思いがち※ですが、属性を利用した単純な検索でも充分利用する価値があります。
※筆者の主観です

例えば、以下のような元データがあったとしましょう。

ID テキスト 日付 投稿者 お店の緯度経度
1 ここのカオマンガイ屋は骨入スープが最高。 2018-10-10 A 35.655898,139.705498
2 とにかく餃子がうまい! 2018-07-10 B 35.666781,139.750832
3 2度食べてハマる麻婆豆腐。 2018-04-10 C 35.667239,139.752888
4 個人的にこの近辺で一番魚がうまい。 2018-01-10 C 35.669347,139.738818

(どの店も私のオススメなので、都内の方は緯度経度から検索してぜひ行ってみてください♡)

この場合、CloudSearchでは以下のことがすべて開発なしでできるので便利です。

  • 食べ物の名前で検索する(あいまい検索もOK)
  • テキストの一致度や日付で並び替えをする
  • 投稿者が完全一致した場合のみに絞り込み
  • 緯度経度の範囲を指定して絞り込み

上2つのイメージが強いですが、単純な絞り込み検索や、空間検索もできるので汎用性は高いです。

「自宅から半径◯キロ以内で!」に近いこともできそうですね。

Amazon CloudSearch での地理的位置による検索および結果のランク付け - Amazon CloudSearch

ざっくり手順

詳しくはAmazonのヘルプを参照してください〜ここでは流れのイメージだけ(๑•̀ㅂ•́)

1. Amazon CloudSearchで検索ドメインを作成する

  • AWSのコンソール上でポチポチ設定する
  • 必要に応じてアクセス制限を設定

Amazon CloudSearch ドメインの作成 - Amazon CloudSearch f:id:aimstogeek:20181010100125p:plain

2. 必要なフィールドと型を洗い出す

下記のようなフィールドが必要になるかと思います。

  • 検索条件になるフィールド
  • 検索結果に必要なフィールド

それぞれのデータが何型か(日付型なのかテキスト型なのか)を検討します。

3. 作成したドメイン上で、フィールドを設定する

  • コンソール上でポチポチ設定する
  • 型によってデータの表記法が決まっている(特に日付型)ので、データ作るより先にこちらを決めるのがオススメ

Amazon CloudSearch ドメインのインデックスフィールドの設定 - Amazon CloudSearch

4. 上記に合わせた検索用データを用意する

  • XMLJSONだと、コンソールからもAPI経由でもアップロードできて良い
  • 難しければCSVで作成し、コンソールから手動でアップする運用も可

Amazon CloudSearch 用にデータを準備 - Amazon CloudSearch

5. 検索用データをアップロードする

ここまで対応すると、API経由で対象データを検索できるようになります!

絞り込み検索のイメージ

コンソール上の「Run a Test Search」で、検索結果をプレビューすることができます。

全件検索するには、"Search:"に「*:*」を入れ、"Options"の"Query Parser"を「Lucene」に変更します。
Searchには通常、検索したいテキストを入力しますが、全件の場合(テキスト検索をしない場合)は「*:*」と指定するようです。 f:id:aimstogeek:20181010112431p:plain

Search欄についてですが、ここで指定したテキストは、単純に検索可能なフィールド全体が検索対象となります。

時に、完全に一致していないレコードもヒットして返ってきますし、検索対象となるフィールドを指定することもできません。

一方で、「このフィールドがこの値に完全一致したとき」という条件で検索したい場面もあると思います。

というか、「えっ…単純にRDBMS的に検索条件セットするので充分なんだけど…」ということのほうが多いと思います。
この場合は絞り込み検索です。

絞り込み検索を行うには、"Filter Query"に条件を指定していくことになります。

投稿者がCのレコードのみを検索するには、以下のようにします。 f:id:aimstogeek:20181010112600p:plain

「この検索結果をAPI経由で取得するにはどうすればいいんだ?」となった場合は、
同じページ内の「JSON」リンクをクリックすると以下の画面が表示できます。 f:id:aimstogeek:20181010113008p:plain 赤矢印の箇所が該当の検索リクエストになっているので、コピペして連携させたいシステム側からcurl等で叩いてあげればOKです。

料金

料金はインスタンスのサイズと起動時間でほぼ決まります。
詳細は以下のページが非常にわかりやすいです。(ちょっと古いですが)

Amazon CloudSearchの見積方法について | ナレコムAWSレシピ

安く済ませるには、使わないときはインスタンスを停止させればいいじゃん!と思いましたが、
どうやら削除か起動かしかないようです。

予めデータ量などが分かっている場合は、以下のツールで試算するといいと思います。

Amazon Web Services Simple Monthly Calculator

まとめ

以上のように、プログラミングをすることなく検索用DBを持てる点と、即座にAPIが利用できる点が、CloudSearchの便利なところです。
また、リクエストやアップデートに応じたスケーリングも勝手にやってくれるので、その点は楽です。

ですが、データの二重管理になってしまう、コスト試算がしづらい等、長年運用するケースに不向きな面もありますので、
状況に合わせて選択肢の1つになるかもなというくらいでのご紹介でした。

こういう状況でむしろこうしたほうがいい、このツールもオススメ、というものがあればぜひ教えてくださいm( )m


\\ 『明日のはたらくを創る』仲間を募集中!! // 919.jp

Laravel5.6とVue.jsでクリーンアーキテクチャを目指す

先日の台風により楽しみにしていたライブが中止になりブルーなぱふゅーむです。

最近新規サイトの構築でアーキテクチャについて、プロジェクトメンバーで議論する機会がありました。 そのプロジェクトは新しい試みとしてスクラム開発を行なってるのですが、今回はスクラム開発の話ではなく新規サイトのアーキテクチャについて話したいと思います!

スクラムについてはスクラムマスターのフルーツパーラーが記事を書いていますので興味がある方は是非!

スクラム開発はじめます - 株式会社クイックのWebサービス開発blog

技術要件

使用する技術セットについては以下になります。今回の話にはあまり関係がないところですので、詳細は割愛させていただきます。

全体構成

f:id:aimstogeek:20181004160749p:plain

アーキテクチャは大まかに分けてこのような構成になっています。

  • Controllerクラス・・・viewを返すControllerとデータのやりとりをするApiController
  • Serviceクラス・・・ユースケースを纏めたクラス
  • Repositoryクラス・・・DBとやりとりをするクラス
  • Modelクラス・・・Entity

Controllerクラス

Controllerは以下2種類のコントローラに分けています。

  • 単純にviewを返すController(ViewController)
  • 実際にデータの受け渡しを行うApiController

アプリケーションがRequestを受け取るとまずController(ViewController)はリクエストパラメータをviewに返します。この段階では特にデータの取得・削除などは行いません。単純にリクエストパラメータとともにviewを返すようなイメージです。

viewはいくつかのvueコンポーネントから構成されています。各vueコンポーネントはControllerから必要なパラメータを取得し、表示に必要な情報を取得するため再度非同期で各ApiControllerにRequestを送ります。

基本的にはcomponentとApiControllerは1対1の関係を考えています。ケースによっては多対1(複数コンポーネントから呼ばれるApiController)にはなりえるかもしれませんが、1対多はできる限り避けたいと考えています。理由としては1対多の関係になると、トランザクションをApiControllerではれなくなるためです。

下記はApiControllerの一例です。

<?php

namespace App\Http\Controllers\Api;

class UserController extends \App\Http\Controllers\ApiController
{
    /**
     *
     *
     * @param  int          $id
     * @return \Illuminate\Http\JsonResponse
     */
    public function detail(int $id): \Illuminate\Http\JsonResponse
    {
        $service = new \App\Services\UserService();

        return $this->renderJson([
            'user' => $service->fetchUser($id),
        ]);
    }

Userを取得する処理は後述するServiceクラスに任せます。

Serviceクラス

Serviceクラスはユースケースをまとめたものです。例としてUserServiceクラスをあげます。Userに関わる振る舞い(ユースケース)としては以下のようなものが考えられます。

  • ユーザ情報を取得
  • ユーザ情報を登録
  • ユーザ情報を編集

上記のような振る舞いをまとめたものがUserServiceクラスになります。 Serviceクラスで重要なことはビジネスロジックのみを記述し、データ取得などModelとのやりとりはRepositoryクラスに任せることです。(取得したデータをApiControllerに渡すために加工が必要な場合はServiceクラスで行います。)

設計の段階でServiceクラスとRepositoryクラスを分けるかどうかメンバー間で議論をしたのですが、Serviceクラスでビジネスロジックとデータ取得等DBとのやりとりを一緒に書くと、冗長な記述が多くなり、Fatロジックになりがちとの結論により分離することになりました。

一例としてユーザ情報を編集する処理がUserServiceクラス以外で必要になったとしましょう。その場合Serviceクラスをビジネスロジックの記述のみに抑えることにより、実際にDBにアクセスしてユーザ情報を編集するという処理を共通化することができます。

Repository層にDBとのやりとりを任せることで、各Serviceクラスから使いまわすことができるようになります。

<?php

namespace App\Services;

class UserService
{
    /**
     *
     *
     * @param  int          $id
     * @return \App\Models\User|null
     */
    public function fetchUser(int $id): ?\App\Models\User
    {
        $repo = new \App\Repositories\UserRepository();

        return $repo->find($id);
    }

Repositoryクラス

LaravelのEloquentモデルはEntityとしての役割と、DBのデータ操作をする2つの責務を持っていますが、その責務を分離したかったためRepositoryクラスを実装することになりました。Repositoryクラスはデータの取得・編集・削除など DBとのやりとりを行うクラスになります。ModelクラスはあくまでEntityとしての振る舞いを持つクラスにとどめます。

<?php

namespace App\Repositories;

class UserRepository
{
    /**
     *
     *
     * @param  int          $id
     * @return \App\Models\User|null
     */
    public function find(int $id): ?\App\Models\User
    {
        return \App\Models\User::find($id);
    }

Modelクラス

Modelクラスは単純にEntityとしての振る舞いのみになっています。DBとのやりとりは前述したRepositoryクラスに任せます。Modelはテーブルと1対1の関係になります。

今後に向けて

プロジェクトメンバーでこういったアーキテクチャの話ができたのは非常に有意義で楽しかったです!これがベストなアーキテクチャかどうかはまだ分かりませんが、個人的にはスケールしやすい、いい設計ができたのではないかと思っています。現在ようやく設計フェーズが終了し実装に入ってきたところです。今後もプロジェクトメンバーで議論しながらよりよい柔軟なアーキテクチャを目指していきたいですね!では!ʅ(◔౪◔ ) ʃ


\\ 『明日のはたらくを創る』仲間を募集中!! // 919.jp