ヒカ☆ラボでReact導入の話と商品検索改善の話をしてきました

12 June 2017 by Yamamoto

こんにちは。エンジニアの山本です。
5/23に開催された、【 ヒカ☆ラボ 】大規模サービスがリスクをとってまでモダンな開発環境にリプレイスした理由~ここだけの苦労話や手法を交えお話します~ というイベントに参加 & 登壇してまいりましたのでレポートします。

今回のイベントのテーマは レガシー改善 という、長年継続しているサービスでは避けては通れないものでした。

弊社のサービスである BUYMA もローンチから10年以上経ち、溜まりに溜まった技術的負債を日々返済しています。

Reactを導入した話

弊社からは2人登壇させて頂きまして、私、山本は “React導入時の苦労話とこれからについて” と題しまして、ある機能のリプレイスプロジェクトでReactを導入した話をしました。

既にデファクト・スタンダードになったと言えるReactですが、導入当時の一年前は大規模なサービスに導入したという事例もまだ少なく、如何にして非SPAなWebサービスにReact/Reduxをマッチさせるかという点でとても苦労しました。

当時の苦労話を共有することで、少しでもこれから大規模サービスにReactや他のJavaScriptフレームワークを導入しようとしている方々のお役に立てればと思います。

こちらが発表資料です。

商品検索を改善した話

木村の方は、“BUYMAの商品検索システムの改善の取り組み”というテーマでした。バイマの商品検索システムをSolrCloudへリプレースし、耐障害性を向上させた取り組みについてや、レガシーな検索ロジックを、BigQueryなどを駆使しながら数値で検索精度を計測しつつ、新しいロジックへと改善していく取り組みについてお話しました。

発表資料はこちらです。

BUYMAの商品検索システムの改善の取り組み from 慎太郎 木村

当日の様子

木村
Image uploaded from iOS (1)
山本
Image uploaded from iOS
質疑応答時
Image uploaded from iOS (2)

まとめ

一緒に登壇させて頂いたJapanTaxiさん、一休さんのお話も非常に共感できるところが多く、また今回は最近開催されたヒカ☆ラボの中でも来場者数は多かったようで、”みんなレガシー改善に苦労しているんだなぁ”としみじみ感じました。
新しい技術がどんどん生まれる中、如何にして技術的負債を返済してくかはこれからますます重要になってくると思います。
みなさんもガンガン知見を共有して共にレガシーと戦っていきましょう。

Pocket

Leave a comment | Categories: Events, JavaScript

AMP対応のススメ

30 May 2017 by Omiya

エニグモでWEBエンジニアをやっております、大宮です。
今回は、先日英語版BUYMAで行った、AMP対応についてまとめた記事をお届けしたいと思います。

そもそもAMPとは?

Acceralated Mobile Pagesの略です。
その名称が示す通り、モバイル端末で高速なWebページを表示させるためのプロジェクト、またはそのためのフレームワーク(AMP HTML)の事です。
フレームワークはGoogleとTwitterにより共同開発されています。2016年の2月にローンチされて以降、AMP対応を行っている企業は増え続けています。

Googleからは今のところは明言されていませんが、メインの開発にGoogleが入っているということで、いずれSEOの上位表示に影響してくるのではないかという予測も立てられているようです。
現に、一部の記事ページではスマホで検索するとカルーセルで検索結果の上位に表示されます。

近年は新興国でもスマホ文化が普及する一方、回線速度の遅さが問題視されることもあり、AMPはこうした時代の流れにも対応したものと思われます。
国内を見ても格安SIMや通信容量制限による低速化などにより、WEBページの体感速度の向上はますます重要な要素になってきています。
ページが速く表示されるだけユーザーの満足度は向上するというのは、想像に難しくないでしょう。

実際に見てみましょう

実際に対応された英語版BUYMAのサイトを見てみましょう。

AMP未対応のページ(ベンチマーク計測:11.5秒)
AMP対応のページ(ベンチマーク計測:3.5秒)
AMP対応のページをキャッシュしたAMP Projectページ(ベンチマーク計測:0.76秒)

ベンチマークは低速な回線で撮ったものです。
体感でも表示速度が一番下のキャッシュ速度が速い事がわかるかと思います。

なお、上記AMPのページはPC版で見ると崩れているように見えますが、CSSをモバイルに最適化した(PC対応のCSSを排除した)結果です。後述する実装でAMPを別URLとした場合、AMPのページがPCからみられることはありませんのでOKとしています。

なぜ速いのか?

AMP対応のHTMLは読み込みが非常に速いです。その理由を見てみましょう。

■ AMPでは、非同期のAMP専用JSしか使用出来ない。
■ CSSのサイズ制限+外部ファイルに置く事を禁止している
■ 画像のLazy Load+幅高さ指定の強制でブラウザの負荷を軽減

特に一番大きいのは最後のLazy Loadでしょう。
通常Webブラウザはページの表示時でページ内のすべての画像を読み込もうとしますが、AMPでは表示領域のみ非同期で画像をロードしてきています。
それを可能にしているのが<amp-img />タグです。ampページでは通常の<img />タグは使用できず、すべてこちらに置き換える必要があります。

また、CSSのサイズ制限があるので、リッチなコンテンツの量は増やしづらく、AMPページとしては余分なモジュールを削りおとすことになり、全体として読み込むファイルサイズが軽減されやすいということです。

さらに、これらのHTMLは、AMP-ProjectのCDNサーバーにキャッシュされ、検索結果での表示時にはキャッシュされたページを表示するようになります。
このキャッシュ時に、画像もモバイル用に圧縮をし、ファイルサイズを軽減しています。

さらに検索結果の表示時には、ユーザーが見ている検索結果の部分で、裏側でPreconnect / Prerenderingが走っています。
ユーザーが検索結果からページにアクセスしようとしてタップした時には、すでに裏側でページが読み込まれているため、ユーザー体験としては爆速に感じるということです。

AMPの三大制約

AMPを実装するにあたって、設計の段階で留意すべき制約は3つあります。

■ JSが使えない*
■ CSSは50KBまで
■ Cookieが使えない

ということ。言い換えれば

■ リッチなページは作れません。
■ ログインユーザーに応じて出しわけ…などの機能は使えません。

ということです。

JSが使えないというのは、自前のJSは一切使用不可ということで、JSでよく使用される機能について、ある程度はAMP-Projectの方で用意されています。
例えば、サイドバー、カルーセル、フォームのバリデーション等。詳細は公式のこちらのページに記載されています。

また、JSに関しては、2017年6月現在、amp-bindという機能が開発中です。
リリースされればJSで自前のスクリプトを書いた時ある程度は同じような挙動を実現できるようになります。
具体的には、イベントトリガーでclassやInnerText, attributesの値を動的に変更するということが可能になります。

が、それでも既存のJSの流用はできないため、amp-bind用に書き直す必要があります。

URL方式の設計

まずは上述のように、できることとできないことをただしく把握する必要があります。
基本的に上の項目を把握されていれば問題はありません。

次に、AMP用に新規URLを作るのか、既存ページをAMP化させるのかを決めます。
モジュールを分けるかわけないかという選択ですね。
可能であれば、メンテナンス性を考えて同一モジュール…つまり今あるページをAMP化し、新規では作らないというアプローチが望ましいです。ただ前述の通り、AMPには制限がありますので、オリジナルページを残したい場合もあるかと思います。
その辺りはページのボリュームと、JS書き直しの工数(既存機能への影響)を加味して判断する必要があります。

ちなみに新規でページを作る場合には、最初からAMPに対応したものと作成してしまえば、既存ページへの差し替えで悩むことはなくなります。

画面の設計

基本的にはオリジナルページから何を残して何を削るのかを判断する必要があります。
オリジナルページをそのままAMP化しても、CSSの容量超え+JSのリッチコンテンツで実現可能なものと不可能なものが出ると思います。
なのでAMPページの要件として絶対に必須なものを厳選して残し、CSS容量や工数に余裕があれば別の機能の対応も行うというアプローチが良いでしょう。
実際に開発してみてできること、できないことが分かるという事もあります。

なお、前述の弊社サイト(商品詳細ページ)では、商品情報+カート購入機能だけを残して、グローバルナビや検索バーといった要素は排除しています。これらの要素はAMPでも代替は可能ではありましたが、CSSの容量制限の関係で断念した要素でした。

実際にAMPページにしてみる

AMP専用の雛形がありますので、ご自身のサイトにあててみましょう。
bodyタグやheadタグやCSSは適宜調整していただければ良いかと思います。

これで、サイトはAMPとして扱われます。

なおAMP用に新規でURLを作る場合には、オリジナルページのHTMLのheadタグ内に下記を記述しましょう。
<link href=”AMPページのURL(フルパス)” rel=”amphtml”>
これでGoogleにもAMPページが認識されます。

ただし、エラーが出る(多分)

Chromeの開発者モードを開きURLの末尾に#development=1とつけましょう。雛形をそのまま使っていない限り、このように大量のエラーとなるはずです。

スクリーンショット 2017-05-30 10.14.26
弊社サイトの対応途中で怒られていた内容としては、主に下記のような内容です。

■ img -> amp-imgに変換+幅・高さ指定してください
■ scriptタグの使用してる所を全部削除してください
■ a href=”javascript:void(0);”など
■ cssをインラインで読み込みしてください
■ cssのファイルサイズを削減してください

このエラーを解消しないと、GoogleからAMPページとして認識されませんので、すべて対応しなければいけません。
根気よく対応していけば、いずれは下記のように「AMP validation successful.」となりますので、頑張って対応しましょう。
スクリーンショット 2017-05-30 13.53.28
WEBアプリケーションの場合はVIEWにIF文があることも多々あるので、当然ながらその条件分岐は全パターンみておく必要があります。

晴れてエラーがでなくなれば、本番環境にデプロイして、完了となります。
この時本番環境でしか動いてない監視用のJSなどがあると、またエラーになってしまいますので、注意深く観察しましょう。

終わりに

AMPはそれなりに工数もかかる上に、完成する画面としては真新しいものではありません。
むしろ既存の画面より機能が削ぎ落とされたものなので、パッとみた完成品は物足りなさを感じるかもしれません。

なかなか成果のわかりにくい改修ではありますが、実際にAMP対応によって数字の伸びた事例も挙がってきています。
何より低速回線のユーザーにも、快適な挙動のページをお届けするという意味で重要な要因となりますので、ぜひとも導入を検討していただければと思います。

本記事がその際の一助となれば幸いです。

Pocket

Leave a comment | Categories: Uncategorized

ReproUserMeetup#1にて登壇してきました!

16 June 2016 by Enigmo Engineer

みなさんはじめまして!
BUYMAでiOSアプリのエンジニアを担当している、松本と申します!

先日6月2日に行われたRepro User Meetup #1に登壇してまいりましたので、その様子をお伝えします!!

Reproとは?

Reproとはアプリに特化した、アナリティクスツールです。従来のツールと大きく違う点は、ユーザーの行動を動画で確認をできる点とリテンション分析・ファネル分析といった機能によってユーザーの重要な行動を細かくトラッキングできる点です。詳しくは、ReproさんのHPをご覧ください

当日の様子

IMG_4506
当日はReproを活用されている10社様が登壇され、様々なReproの活用法や成功事例が発表されていました。各社様の発表内容はコチラから

BUYMAでのRepro活用

IMG_5837
新規ユーザーにまず継続的にアプリを使用していただくことは、どのアプリにおいても非常に重要な事と言えると思います。

Reproのリテンション分析では、特定のアクションを行ったユーザーのリテンションを測定するといったことも可能であり、今回のRepro User Meetupでは新規ユーザーに対して最も効果的なイベントをどう判断するかという事について発表を行わさせていただきました。

詳しい内容はこちらのスライドをご覧ください!

BUYMAにおけるRepro運用 from Takashi Matsumoto

IMG_5472
Repro株式会社取締役CMOの中濱 康広様(中央)と弊社松本(左)と松永(右)

Pocket

Leave a comment | Categories: Events

BUYMAの商品検索を支えるSolrCloud

02 September 2015 by Kimura

お久しぶりです。アプリケーションエンジニアの木村です。

BUYMAでは、この記事を書いている時点で世界中から出品された約155万件の商品が検索可能となっていて、商品検索機能は世界中から自分の欲しい物を探すことを実現する、まさに「世界を買える」を実現するための重要な機能の1つとなっています。今日はそんなBUYMAの検索機能の裏側を支える基盤部分についてご紹介いたします。

BUYMAでは検索機能実現のためにはSolrを導入していて、さらにSolrCloudを構成しています。

SolrCloudとは

SolrCloudは、高信頼性、耐障害性、拡張性を運用コストを抑えつつ実現するSolrのクラスタリングの仕組みです。紙面の都合上あまりSolrCloudについて詳しく説明できませんが、下記リンクが参考になるのではないでしょうか。

https://cwiki.apache.org/confluence/display/solr/SolrCloud
http://www.slideshare.net/kenhirose547/10solr-solr-cloud

あまりWeb上に詳説された記事がないので、下の書籍も参考にしつつ構築にとりかかりました。

・『Solr in Action』Trey Grainger・Timothy Potter (2014) Manning Publishing.
・『改訂新板 Apache Solr 入門』大谷純・他(2013) 技術評論社.
・『Scaling Apache Solr』Hrishikesh Vijay Karambelkar (2014) Packt Publishing.
・『ZooKeeperによる分散システム管理』Flavio Junqueira・Benjamin Reed [著]、中田 秀基 [訳] (2014) オライリー・ジャパン

さらに、上の2つ目の本も監修されているロンウィットさんのトレーニングも受講しました。最後の本はSolrCloudに組み込まれるZookeeperの本です。

BUYMAでのSolrCloudの構成

BUYMAのでのSolrCloudの構成を表したものが下の図になります。

SolrCloud

更新のしくみですが、Solrを更新するバッチが常に動いていて、DBから更新がかかった商品情報を取得し、leaderのSolrノードへ更新リクエストを送ります。するとSolrCloudの仕組みとして、leaderノードが他のreplicaノードへ更新を伝えて全ノードが更新されます。

検索はRailsのWebサーバーから直接SolrCloud内のSolrノードへリクエストします。特にロードバランサー用のサーバー等は挟まず、SolrノードのIPをランダムに選び、そのIPへリクエストを飛ばすように、Railsアプリ側でロードバランシングしています。

耐障害性への取り組み

RailsのWebサーバーから直接SolrノードのIPへ検索リクエストが飛びますが、各SolrノードのIPアドレスはそれらを監視しているZookeeperから取得しています。したがって、いずれかのSolrノードで障害が起こった場合でもそれをZookeeperが感知し、リクエスト可能なIPの一覧からダウンノードのIPを外してくれ、ダウン中やリカバリ中のノードへは常にリクエストが振られない仕組みになっています。

更新時も更新バッチがZookeeperからleaderであるSolrノードのIPを取得し、それに対して更新リクエストを飛ばしています。もしleaderノードで障害が発生し、フェールオーバーして別のノードがleaderとなった場合でも、Zookeeperがそれを感知して更新バッチ側へleaderの変更が伝わる仕組みです。

実は、Zookeeperと連携してそこらへんの面倒な処理をやってくれるSolrJというSolrCloudにも対応したJava用のSolrクライアントがあるので、JVMのWebアプリではそれを使ったり、そうでない場合はSolrJを使ったAPIサーバーを検索クライアントとSolrとの間に挟む構成が通常なんだそうです。ただ、そのためのサーバーの運用保守もコストなので、RubyからZookeeperと連携するSolrCloud用のRubyクライアントを自分たちで作りました。gemとして公開していますので、ご自由にお使いいただいてフィードバック等をお待ちしております。

https://github.com/enigmo/rsolr-cloud

BUYMAの検索基盤クロニクル

BUYMAがシステム面で今の形に近いものに生まれ変わったのは2008年ごろ(らしいの)ですが、その当時公開されていたSolr 1.3系の時代から検索機能にはSolrが導入されていました。その後2011年に3.x系へとバージョンアップがなされ、2015年6月まで稼働していましたが、商品数の増加とマスキャンペーンにより大量のアクセスが予想されたため、マシンリプレースと合わせて2015年リリースされた5.x系へとバージョンアップしました。さらに、運用し易さを求めて、構成をSolrCloudとしました。

SolrCloud導入以前は、マスタースレーブ構成でもなく、Solrノードを並列にならべてそれぞれのIPアドレスを更新・検索クライアントとなる全サーバーに固定値で持たせていました。更新バッチは全Solrノードへ同じ更新リクエストを何度も送る必要があり、1ノードでも更新に失敗すれば検索結果がノードによってズレてしまいました。Solrノードでの障害発生時やメンテナンス時にもそれぞれのサーバーのSolrノードのIPを書き換えてやる必要がありました。商品数やアクセス数の増大に伴って、この先ノード数を増やす場合にこの構成では限界を感じていました。また、仮にマスタースレーブ構成にしたとしても、マスターが単一故障点になってしまったり、障害対応の時の手間は変わらないというのが難点で、マスタースレーブ構成への変更にも二の足を踏んでいました。

SolrCloudはそういった煩雑さから開放してくれ、まさに自分たちにとっては渡りに船でした。結果、スキーマ変更や設定ファイルのチューニング、ノードの障害発生時の対応やメンテナンスが圧倒的にやりやすくなりました。マシンリプレースの効果もありますが、パフォーマンスも、導入前より向上しました。

今後

Solrのバージョンが3.xから5.xとなり、機能面でも新たに使えるものが増えたので、BUYMAの検索の機能面としても向上していければと思います。

Pocket

Leave a comment | Categories: Uncategorized

【ECサイトにおけるデザイン】キャンペーンページのデザインを考える

25 June 2015 by shinohara

はじめましてデザイナーの篠原です。
ECサイトのデザイナーならではのトピックをお伝え出来ればと思います。

はじめに私の担当は主に運営しているサービス「BUYMA」に関してのデザインになります。
「BUYMA」でのデザイン業務は大きくわけて、

1.トレンドと連動したキャンペーンページやバナーの作成
2.機能改善・新規開発に伴うページやUIの作成

になります。

細かく分類すると他にもありますが、大きく分けるとこんな感じだと思います。

今回は「トレンドと連動したキャンペーンページの作成」時に気をつけている事を、順序立てて書いていければと思います。

ざっとページ作成の流れはこんな感じ

STEP1「構成」

STEP2「ヒアリング」

STEP3「デザインイメージを探す、集める」

STEP4「デザインを考える (頭の中で)」

STEP5「プロトタイピング→デザイン(グラフィックソフトを使ったデザイン)」

STEP6「コーディング」

STEP7「ブラッシュアップ(もうひと頑張り)」

STEP8「公開」

STEPを通して、それぞれどんな事を考えているのかを書いてみようと思います。

STEP1「構成」

STEP1

BUYMAでは日頃からトレンドをウォッチしているMD担当のスタッフがいるので、
企画概要やデザインへ盛り込む要素などは、そのスタッフがあらかじめ決めることが多いです。

企画の規模によっては最初からデザイナーも入り共に構成を考えたりもします。
キャンペーンページでは特に売れ筋や定番人気の商品をBUYMAとしてどう見せていくかを意識して考えていきます。

STEP2「ヒアリング」

STEP2
前STEPとほぼ同時の事は多いのですが、あらかじめ構成をもらっている場合にはこの段階で、

「テーマ」「ターゲット」「トレンド」「企画を考えた時に感じた事」「データからのユーザー分析」「スケジュール」

あたりをしっかりヒアリングします。
内容を整理しデザイン面で懸念があればしっかり認識合わせをしておきます。

STEP3「デザインイメージを探す、集める」

STEP3
ヒアリングで得たものから、同じテーマのデザインをネットで集めたり、
過去の経験から似たようなイメージを引っ張りだしたりします。

色が似ているとかフォントが似ているとか、なんでもヒットしたものを探して、
イメージを広げていきます。

印刷して実際にデスク上にバラバラと広げたり、
ホワイトボードとかにぺたぺた貼っていくとかも良いと思います。

企画を聞いてから色々と探してもいいのですが、
やはり普段から準備しておく事でスピードアップできます。

私の場合はとにかく「パッと見」でたくさんのものを見ておくことを大切にしています。
断片で覚えている方がよりクリエイティブな感覚をもたらすからと考えています。

ちなみにこの「パッと見」の際は、こちらのサイトとかよく見ます。
designspiration.netとかpinterestですね。

BUYMAというサービスは海外との繋がりを楽しむ、または感じてもらうサービスなので、
海外のデザインからインスピレーションを得ることも多いです。
特にファッション性の高い見せ方、トレンドなどは常にチェックしています。

ついでに、ファションだけでなくカルチャー、経済、ゴシップネタまで、ユーザーの取り巻く環境を幅広く把握しておく様に、雑多に情報収集するのも良いデザインに繋がったりすると思います。

STEP4「デザインを考える」

STEP4
前STEPで集めたものに対して、「自分だったらこうする」という軸で考えていきます。
自分の審美眼をあてにしながら、色々と感じるままに考えていきます。

自分の関わるサービスにしっかりとしたブランディングがある場合は、「サービスに似合うのは何か」と考えていきます
BUYMAだとこちらの方が多いです。
この場合はサービスの審美眼をあてにしながら、という具合でしょうか。

STEP5「プロトタイピング→デザイン(グラフィックソフトを使ったデザイン)」

STEP5
イメージがある程度まとまったら手を動かしていきます。

徹頭徹尾まとめてからだとうまくいかない事が多いので、ある程度がいいと思います。
アイディアの鮮度を大切に。頭がフレッシュな朝に回して手を動かすのでも良いと思います。

ちなみに手を動かすという事は文字通り手書きじゃなくても良いと思いますが、
イメージを素早く出すのは手書きが良い場合が多いなと感じます。

大事なのはイメージをどんどん頭から出す事だと思っています、
頭からイメージを出していく事で新たなアイディアが入るスペースが出来るので、
短時間で様々なパターンを出す事が出来ると思います。
そもそもイメージが浮かばない場合はSTEP3に戻ってやり直します。

その後、
デザインが軽くまとまったらプレビューの場を設けます。

注意したいのはこのプレビュー時にデザインが出来上がりすぎている事です。
意見の入る余地がないものを仕上げてからだと、
デザインへのこだわりが強くなっていて引けなくなっちゃったりしますし、
その思いが伝わって良い意見ももらえなかったりします。。。
なので、批判を恐れずにプレビューする事を心がけると良いと感じます。

方向性を定めてデザイン的に問題ないものが出来たら、
そのデザインに合わせたバナー作成もこのタイミングで行っていきます。

STEP6「コーディング」

STEP6
ここは分業の場合も多いと思いますが、
僕らはデザイナーがコーディングまで担当する様にしています。

Webデザイナーは、各デバイス、ブラウザの特徴を把握し、
特性や利点を活かし、欠点を補うデザインが求められる職業だと考えています。

それはデバイス問わず成立するデザインを考えるということでもあると思います。
なので良いデザインをするためにコーディングの知識は必要と考え、極力担当をする様にしています。

またBUYMAではエンジニアと一緒になってページを作る機会も非常に多いので、
HTMLだけでなくPHPやRubyについてもデザイナー側に知識がないと厳しい
という経緯もあり普段からソースに触れる様にしているのもあります。

STEP7「ブラッシュアップ(もうひと頑張り)」

STEP7
実際にはこのタイミングなのか、もしくは途中のタイミングでもあり得ますが、ページ公開に向けてブラッシュアップをしていきます。

ここで良く考えるのは(というより言い聞かす様にしているのは)、
ここまで試行錯誤しながら作ったものであろうが、今の完成度は80%だと思う事です。
UI作成の場合はこの時点では改悪しないものが出来た、と思う様にしています。

誤解を恐れずに書くと、
ブランディングを考慮し、トンマナを守った上で出来たものはまだ完成度が80%程度なのだと思います。
ここからどこまでやるかは周りの反応だったり、それこそ個人の感覚が大きいと思いますが、
人を感動させるもの、気持ちを動かすもの、UIにおいての改善と呼べるレベルのものは、
ここからのブラッシュアップによって達成出来るものと考えています。

STEP8 「公開」

STEP8
BUYMAでは各担当者から公開依頼を一度システム管理者へ回します、
そこでサイトにクリティカルな問題がないかを確認した上で公開されます。
公開されたらもう一度自分が考えたデザインになっているかサイト上で確認を行い完了となります。

ページ公開後は、
良い反応があるかどうかをGAなどでチェックしたり、
実際にインタビューしたりなど、効果を追っていく流れになりますが、
こちらは担当Dirから共有してもらう事が多いので、デザイン作成としてはここで一旦完了となります。

という事で、だいぶ文字ばかりになってしまいましたが、
以上がデザインが出来るまでの基本的な流れです。

この様な基本となる流れを「素早く」「精度高く」こなす事で余裕が生まれ、
よりクリエイティブなキャンペーンページのデザインが出来る様になると思います。

最後になりますが、たまに休憩を取る事も大切なので、時折コーヒータイムでも挟みましょうね。
ではでは、良いデザイナーライフを。

Coffee

Pocket

Leave a comment | Categories: Design

← Older posts