備忘録

なんとなく暇なときにでも....

楽天の商品検索APIで詰まってしまった話

楽天の商品検索APIを使って、指定したキーワードを用いて楽天市場に出回っている商品を検索するツールを受託で開発しました。
その際に、ある問題で1時間ほどハマってしまいましたので、共有できればと思います。

まず楽天の商品検索APIについてですが、導入や使い方については割愛させていただきます。
(実際に使用したAPIはこちらです。↓)
webservice.rakuten.co.jp
一旦は開発しまして、クライアントさんに納品したのですが、あるキーワードを入力するとバグが出るとのこと。
そのワードとは........

「半角1文字」


再度上記のAPIの仕様書を読んでみますと、

各検索キーワードは半角2文字 もしくは 全角1文字 以上で指定する必要があります。

との記述が...
完全に見落としてました。

じゃあいったい半角英数字を入力したい場合はどうすればよいのか...
「そもそも、半角1文字で検索するシチュエーションなんてほとんどないわけだし、気にしなくていいのでは?」とも思いましたが、
どうやら半角1文字だけでなく、「i can fly」のようにスペースを空けて半角1文字を使用した場合でも、駄目だという。

f:id:tomAn:20161008182900j:plain

( i , can , fly の3つワードのアンド検索になっているのでしょう。 )

どうしたものかと考えていましたが、ふと実際に楽天で同様の条件で検索したらどうなるのだろうと思いまして、「i can fly」で検索してみたところ、「i+can+fly」のように検索を行っているようです。

f:id:tomAn:20161008183120p:plain

なので、これを踏襲することとし、
目標としては、単語の羅列の中から1文字の単語が来たら、その後ろのスペースを"+"に変換することにしました。

手順としては、

1. 単語の羅列の中に含まれる全角スペースを半角スペースに変換(preg_replace)

2. 半角スペースをデリミタにして、各単語を配列の格納(preg_split)

3. 各単語の文字数をカウントし、もし1文字だったら、後ろに"+"を付ける。(念のため、ひらがな1文字の場合も1文字とカウントするためmb_strlenを使用しました。)

4. 配列の最後までチェックが終わったら、配列の要素(単語)同士を結合して、元の文字列に戻す。

こんな感じでなんとか「i+can fly」というキーワードに変換することができました。


本日はここまで。

参考サイト

web-dou.com

unskilled.site

[ PHP ] 正規表現サンプル12選 ( preg_match / preg_match_all) – 行け!偏差値40プログラマー

ysklog.net

mb_strlen:文字列の文字数をカウントする

追記

よくよく考えてたら、スペースをpreg_replaceで全て"+"にすればよかっただけの話でしたな。

CakePHP3をインストールする際にハマった...

約1年ぶりにCakePHP3をインストールしました。
一年前はVagrantを使用した仮想環境上(たしかCentOS 7)にCakeを導入したのですが、
その時は、参考サイトに言われるがままにPHPの導入からやっていたのですが、
今回はdocker上に導入するにあたって、ローカルのマシンにCakePHP3をインストールしました。

公式サイトにしたがって
composerを使ったCakePHP3を導入しました。

$ curl -s https://getcomposer.org/installer | php

$ composer create-project --prefer-dist cakephp/app [プロジェクト名]

プロジェクト名は適宜自分で。

ここでまさかのエラーが...

Your requirements could not be resolved to an installable set of packages.

Problem 1
 - cakephp/cakephp 3.0.x-dev reqyures ext-intl * -> the requested PHP extention intl is missing from your system.
 - ...
 - ..
 - .

調べてみるとintlがないとのこと。
さっそくphp.initを調べてみる。

$ php -i | grep intl

なにも表示されない....

まず必要なpeclをインストールします。

$ sudo php install-pear-nozlib.phar
   .
   . 
   . 
Wrote PEAR system config file at: /private/etc/pear.conf
You may want to add: /usr/lib/php/pear to your php.ini include_path

これでpeclを使う準備できました。

インストールしたpeclを使って、intlをインストールします。

$ sudo pecl update-channels

$ sudo pecl install intl


インストール成功したら、php.iniにextension=intl.soを追加しろとのこと。

$ php -m | grep intl
intl

表示されました。
ようやくこれでインストールできるようになりました。

$ composer create-project --prefer-dist cakephp/app [プロジェクト名]



無駄に時間取られました。


本日はここまで

初のAPI実装を行っての反省点

会社で初めて規模が比較的大きめのAPI実装を行いました。

大規模なAPI実装自体は、個人でアプリ開発を行った際は、すべて1人で行ったのですが、
そのときは、アプリ側からのリクエストに対して、正しいレスポンスをすることだけしか考えてませんでした。
それに加えて、その際は、自分の隣にアプリエンジニアがいて、意思疎通を取りながらできていたので、認識のズレが少なくて済んでました。

今回ははじめてアプリエンジニアと新機能企画者とAPIエンジニアのように役割が分担されたケース(1番よくありそうなケースですが...)で、 私にとっては初仕事でした。


今回の実装で大きな反省点は2つです。

  • レスポンスの型を意識する

  • アプリ側で実装された完成型もイメージする

レスポンスの型を意識する

まず1つ目は、アプリ側へのレスポンスするときの型についてです。
私は、個人でも会社でもPHPをメインにAPIの実装を行っています。
ここで問題となるのが、"型"についてです。
正直に言いますと、動的型付き言語であるPHPが9割5分を占めている私のエンジニア人生において、型というものを意識する機会は皆無でした。
$a = 1$b = "1"も私にとっては大きく違いがあるものというイメージがありませんでしたが、開発現場ではそうもいかないようです。
アプリ側からのリクエストに対しても、API側で型のチェックを行っています。これは、誤った型でリクエストが渡ってきた場合に一見動いているように見えるという状況を防ぐためでもあります。
たとえば、

$get = $_GET;

$use_id = $get['user_id'];

とした場合。
$user_idは、API側ではinteger型を期待してるのに、もしかしたら、string型でリクエストが来てるかもしれないですよね。

もしものためにバリデーションしておきますが...

$get = $_GET;

$use_id = intval($get['user_id']);

アプリ→APIのようなリクエストの際に、ある特定の型を期待しているのと同様に、
API→アプリのレスポンスの際にも、アプリ側は、(バリデーションをかけているとはいえ)ある特定の型を期待していることでしょう。

ということで、レスポンスの内容が、正しいからといって、そこで終わりではなく、アプリエンジニアとのきちんと型についても意識を共有しておくことが大事だという反省点でした。

もう1つが、レスポンスの際の内容がなかった場合(たとえば、ユーザーのフォロワーを返すようなAPIに対して、user_id = 1のフォロワーが1人もいなかった場合)
この場合レスポンスをどうするべきかということ。

$get = $_GET;

$use_id = intval($get['user_id']);

$follower_data_array = $this->get_follwer($user_id)

return $follower_data;

この例で言うならば、フォロワーがいる場合、フォロワーを返すAPIは、複数の各フォロワー情報を含んだ配列を返すはずです。

$follower_data = array(
    array( 
        user_id  = 2,
        name     = 'AAA',
    ),
    array( 
        user_id  = 5,
        name     = 'BBB',
    ),
    ........
);

しかし、最初に述べたように、user_id = 1のフォロワーが誰もいなかった場合、どのようなレスポンスを返すべきなのでしょうか。
考えられるパターンとしましては、

  1. $follower_data=NULL; で返す

  2. $follower_data=array();(空配列) で返す

  3. 1と2のどちらも許容する

のようなパターンが考えられるかと思われます。
ここでもアプリ側が期待しているものに絞るべきです。
でないとアプリ側の実装の際に、不必要なバリデーションが増えてしまい、冗長ですよね。
1か2が妥当だと思います。(NULLを許容しない2がいいらしい。)

アプリ側で実装された完成型もイメージする

2つ目は、完成型をイメージするということですが、たとえば、あるリクエストに対して、所定のテーブルから、指定のIDの画像のURLを取ってきて返す。といったAPIがあるとします。
しかし、まだ指定された画像が準備おらず、そのレコードの画像URLののカラムがNULLになっています。

このようなケースですが、私は特に意識しておらず、画像のURLもいつか準備されてるだろうから、とりあえずはNULLを返しておけばいいかと思っていました。
しかし、アプリエンジニアからすると、NULLが返ってくるので、実際の画像が表示できず困ってしまうようです。
もう少し、アプリでの実装過程もイメージして、仮の画像を準備するなどして、対処するべきでした。


以上2点が今回の反省点です。
新人エンジニアの人はそこらへんも注意して、API実装を行ってみてはどうでしょうか。


本日はここまで。


参考

qiita.com



Twitterもフォローしてください

twitter.com

"リーダブルコード -より良いコードを書くためのシンプルで実践的なテクニック-"を読み終えました。

かの有名な書籍”リーダブルコード”を読み終えました。


やっぱり有名なだけあって非常に為になる本でした。そしてなによりその読みやすさ。
読書が苦手な私でも毎日二章ずつくらい読みすすめることができて、結局1週間ほどで完読しました。

日々の業務でも、読んだことを実践してます。
4章の"美しさ"なんて即実践に移せましたね。

私は関数や変数への名前付けが苦手なので、2章や3章はとても興味深い内容でした。

  • 2章 名前に情報を詰め込む

    • 名前に情報を詰め込む
    • 類語辞典でもっとカラフルな名前を探す
    単語 代替案
    send deliver,dispatch,announce,distribute,route
    find search,etract,locate,recover
    start launch,create,begin,open
    make create,set up,build,generate,compose,add,new
    • tmpやretvalなどの汎用的すぎる名前は避ける
    • i, j, k などはループの変数として理解できるため使ってもよい
    • スコープが小さければ短い名前でもいい
    • エディタの補完機能などがある現在では、長い名前を入力するのは問題じゃない
    • stringをstr、documentをdocと省略するのは問題ないが、チーム独自の省略規則はやめよう(新しい人がジョインしてきたときに、その人の理解を邪魔するため。)
  • 3章 誤解されない名前

    • 名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する
    • 限界値を示すときは min_hogehoge , max_hogehoge を使う
    • 範囲を示すときは first_hogehoge , last_hogehoge を使う
    • 包括的範囲には begin_hogehoge , end_hogehoge を使う
    • get_hogehogeは変数へのアクセッサの意味として認知されているので、そのような処理以外でgetを使用しないこと


とこんな感じでした。



早足ですが、本日はここまで。

MySQLの外部キーについて。

久しぶりに平日に投稿します。
最近は早めに仕事あがってひと駅分歩いて帰ったり、読書の時間増やしたりしております。

今日はタイトルの通り外部キーについて簡単にまとめました。

MySQLはリレーショナル・データベースです。
”リレーショナル”という言葉通りテーブル間にリレーションを貼ることができるので、存分にその威力を発揮させたいところです。

2つのテーブル間を結ぶフィールドを外部キーと呼びます。

User テーブル

id name password group_id
1 user_A ****** 1
2 user_B ****** 2
3 user_C ****** 3
1 user_D ****** 1


Groupテーブル

id name
1 group_A
2 group_B
3 group_C

のようなふたつのテーブルが存在していたとしたら、外部キーはUserテーブルのgroup_idとなります。

また2つのテーブルの関連付けの際には、テーブル間のレコードは1対多の関係になるように設定するのは正しい正規化と言われています。

と、ここまでは、調べればもっとわかりやすく説明しているサイトも存在するので、そちらを参照した方がいいかと思います。

1週間で学ぶIT基礎の基礎 - すぐわかるデータベースの基礎(3):ITpro

私は、基本DBの操作はGUIツールのSequel Proを使っていますが、今回初めて使うことになったのが、この外部キーの設定のやり方です。

f:id:tomAn:20160912215754p:plain:w300

外部キーを貼りたいテーブルを選択→上部の"関係"のタブ?を選択→タブの"+"ボタンを押す

すると上のような画面を表示することができ、外部キーに設定したい参照先のテーブル(table_A)のカラム名(column_A)、参照先のテーブル(table_B)とそのテーブルで関連付けるカラム(column_B)、動作を選択することで外部キーを設定できます。

ここでの動作とはtable_Bで設定したcolumn_Bになんらかの変更(DeleteやUpdate)を加えたときに、
関連づいたcolumn_Aにどのような動作を起こすかを決めるものです。

動作にはRESTRICT , CASCADE , SET NULL , NO ACTIONの4つがあり、それぞれ以下のような違いがあります。

UPDATE DALETE
RESTRICT エラーになる エラーになる
CASCADE 参照先の変更に追従する 参照先の変更に追従する
SET NULL NULLになる NULLになる
NO ACTION エラーになる エラーになる

上の2つのテーブルを例にするならば、Userテーブルのgroup_idが外部キーであり、参照先のGROUPテーブルのidカラムが参照先カラムで、UPDADE, DELETEそれぞれでのアクションはCASCADEするのがよさそうな気がします。



平日ですので、本日はここまで。

「SOFT SKILLS ソフトウェア開発者の人生マニュアル」を読んで part.6 ~第3部と第4部読みました~

少し時間が空いたので、第3部と第4部読みきりました。

第3部は学習について。第4部は生産性の上げ方について。

学習については、著者の実戦する学習プロセスについての話がメインでした。
10のステップに分けて学習するとのこと。
学習したいことについての知らない部分の基本的な知識を得たら、
得た情報・知識を使ってから自分が学習したいと思ってたことの範囲を決め、参考資料を集める。
そこからはLDLT(learn - do - learn - teach)のプロセスを行っていくらしい。

たしかに、この学習方法はよさそう。
しかし、結局のところ、
”どうしてそれを学びたいのか。” 
”それを学んで何がしたいのか。”
これに尽きると思います。(著者としては、もちろんそれが前提にあって話していると思いますが。)

学習の方法は人それぞれ合う・合わないがありますし、最初のモチベーションを如何に保ち続けるかが、重要なファクターになっていると思います。

私も学びたいことはたくさんありますが、結局その中で、学習を持続できているのは、一握りです。
一旦著者の学習プロセスを踏んで学習してみるのもありかもしれないなー。と思っています。
(ちなみに最近はpythonで統計の勉強がしてみたいんですが、手についていない始末です。)


第4部の生産性の上げ方についてですが、これはいろいろためになりました。
特にポモドーロ・テクニックは実践にしてみたいです。

sadakoa.hateblo.jp
私の性格上けっこう合ってる気がします。
(大学受験の時とか、自分の学習時間をトラッキングしたりして、勉強してたり、集中保ってたりしましたし。)
面白いサービスも見つけました。

245cloud.com
1日の結果をツイートするアプリとかあったら面白そうですね。

第40章の"自分自身に対して責任を取る"もよかった。
自分で自分のためにルールを作って、それに反せずに生活を送ってる人ってかっこいいですよね。
私の好きなハリウッドの俳優のジェイソン・ステイサムのトランスポーターを連想させます。

f:id:tomAn:20160911163044j:plain かっこいい.....!!!

自分で決めたルールって自分で決めたことなのに、なかなか定着しづらい気がするのは私だけでしょうか。(自分に甘いんだと思いますが。)


本日はここまで。(twitterもフォローしてください。) twitter.com

オブザーバ・パターンについて ~ Backbone.js難しい... ~

最近の投稿があんまり技術系の話から逸れ気味なので、方向を修正します。

最近はBackbone.jsというjsのフレームワークを触っています。
俗にいうMVCフレームワークなのですが、あんまりControllerの存在感がない感じでした。(ViewとModelの直接的な関係が大きい感じでしょうか。)
複数個のModelを管理しているCollectionがあったり、URLの監視を行うRouterやRouterの履歴を監視するHistoryがあったり。
jqueryすげー」ってなってた私からすれば、かなり難易度高い...。

イベント駆動のオブザーバ・パターンのフレームワークです。
イベント駆動とは、あらかじめ各Viewにトリガーと、発火メソッドを登録しておくこと。
そうすることでViewに対するイベントをトリガーにして、(MVCでいうところのController)View内のメソッドが発火します。
イベント駆動自体はJqueryでも同じような考え方をしてます。

また、基本的に複数のViewに対して1つのモデルが存在しているため、任意のView(仮にAとします。)でModelのある値を変更したとき、その他のViewにもModelの値の更新を通知しなくてはなりません。他のViewに更新がないと使ってるユーザーにはバグにしか見えないですよね?

例えば、Facebookのフィードで気になる記事があったとします。

↓フィード上の気になる記事
f:id:tomAn:20160903183821p:plain:w300


そこで、いったんこの記事をタップして、詳細ページに遷移しました。

↓詳細ページ
f:id:tomAn:20160903184245p:plain:w300


その詳細ページで”いいね”をした後、最初のフィードに戻ってきました。
さて。その時、フィードをリフレッシュさせなくても、”いいね”がフィード上でもされてる状態であるべきです。
View(詳細ページでの記事)でModel(気になった記事)の内容が”いいね”によって更新されたときに、他のView(フィード上の記事)でも、Modelの値の変更を読み取る必要があるということ。
これをオブザーバ・パターンといいます。

オブザーバ・パターン...
よくわかんないけど便利なのはわかります。

Backboneでは、listenTo()というメソッドを使って、これを実装することができます。
上の例でいうと、

var feed = Backbone.view.extend({
 collection:feed_conllection,


    initialize: function() {
   this.listenTo(this.collections, 'update', this.update);
    }


 update: function() {
  //feed_collectionの更新をハンドリングして、自身のViewに更新をかけるような処理を行う。
 } 
});

簡単に書くとこんな感じでしょうか。


まだ私も触りだしたばかりなので、わからないことが多すぎで大変です。
今月一杯で社内のbackbone.jsの仕様はある程度精通できるようにはしたいですね。



本日はここまで。


参考

qiita.com

qiita.com

blog.mitsuruog.info

akiyoko.hatenablog.jp




ついでにフォローしてください。 twitter.com