はじめに
一般的には、コードの再利用は推奨されていることかもしれませんが、かえって時間がかかってしまいました。再利用というとすでにあるコードに多少手を加えて簡単に作れると思いますが、今回は逆でした。
シンプルなWebサイトを作ろうと思い立ち、仕様的に機能のあるコードをベースにして、不要な機能のコードを削り取ってゆきました。この作業が思ったよりも時間がかかり、再利用としては失敗だったかなと思っています。
今回の再利用
シンプルなyoutube検索再生プラグインを作ろうと思い、前回作成したプラグインをベースにしました。ところが、このプラグインのコードが整理されてなく、そのことが再利用にあたり、困難を極めました。
このプラグインは、二つのタブが連携して動作します。このことも障害の原因になりました。タブは親子の関係で動作します。
困難だった作業
(1) ベースとなるコードの複雑さ content.jsの再利用ベースとなるコードが複雑すぎました。選択を誤りました。
何が複雑かと言いますと、コードが整理されていませんでした。あとからの、機能追加の連続で変数がその都度、追加されていて、全体の見直しがなく、変数のお化け状態でした。変数の全体見直しは確認作業も多くなり、設計のしなおしにもなりますので、しませんでした。結果的には、似たような意味の変数が多数できてしまいました。
content.jsは、二つのタブが別々に動作します。それぞれのタブのDOMへアクセスします。しかし、プラグインの仕様上、コードは一つです。このコードの中で、それぞれのタブの処理を行っています。ここで、ベースとなったコードは、その分離が明確ではなく、数カ所で、現在、どちらのタブで動作しているかを判断していました。
タブの動作自体は、親タブが子タブをオープンしたら、以後、子タブがアクティブになり、youtube検索を続行します。検索が終了して、リストを生成し、そのリストをbackgroundへ送信します。background.jsが親タブをアクティブにし、このタブへリストを送信します。親タブはプレーヤータブで、そこのcontent.jsがリストを受信し、プレーヤータブのリスト要素へ格納します。これらの処理が整理されてないため、再利用が難しかったことです。様々なメッセージ通信がその困難を助長していました。
(2) 今回には不要なコードを一件づつ取り除いて行く作業
ひとつづづ、取り除いてはテストを行い、問題がないことを検証します。これがまた、大変で、しばらく後になって、そのコードはそのまま削除してはいけなかったりします。再度、コードを元に戻してさらに修正を加えたりします。
(3) 無理やり元の仕様に合わせようとする
今回の仕様には不似合いの元のコードでも、変更するよりは手っ取り早い場合、そのまま利用したりすると後々、痛い目にあいます。とにかく、コードが汚くなります。
(4) 部分的に丸々コピーできる再利用は、元のコード次第
よくできているコードは、丸々コピーしても問題はすくないが、関数でもインターフェースがしっかりしているとか、クラス設計されているとかならいいが、関数の中で、グローバル変数を使っていたりするとインターフェースを再設計することになります。
(5) セレクター要素がまだ未表示の時の取得
再利用するときに、ついでにコードを整理したく、いじり回すと余計おかしくなります。この場合も手を加えて、見通しの良いコードにしたいと思いました。
特に、IMG要素ゃサムネイルのあるリストで発生します。あるdom要素を取得して、そのオブジェクトにあるデータへアクセスしようとしても、まだ、データがなく、取得エラーが返ってきます。そこで、思い切って非同期処理を取り入れてみました。$.Deferred()を採用しました。youtube検索ページで、
自動スクロールして検索を続ける処理で、逐次、サムネイルリストを取得して行きますが、画像付きのリストデータはすぐには取得できず、何もない画面に対して要素の取得要求が出ています。これは、エラーが返ってきます。そのため、非同期関数で何件かのリストデータが取得できた時点でresolve()を実行し、promise()でリターンします。この関数で何とか、クリアできたようです。
background.jsの再利用
このコードは、content.jsとは逆に、すべてのタブを管理していますが、個々のタブのDOMにはアクセスできません。タブ連携するにはなくてはならないモジュールです。
タブが個々のcontent.jsへメッセージを送信するには、タブidが必要になりますが、そのタブidをbackground.jsは取得できます。content.jsはbackground.jsへ送信するだけですので、タブidは不要です。
background.jsを再利用するときにも、タブを意識した処理コードブロックで管理するといいかと思います。どのタブとアクセスするかで、ブロックを分けたいと思います。それまでは、特にブロックを明確に分けていたわけでなく、ただ漫然とコードを書いていました。
(1) 困ったこと
'using strict'構文を使いたかったので、入れてみたところ、想定通り、動作しなくなりました。あっちこっちで変数がundefinedになっています。'using strict'を入れてないときは、未定義でも動作していましたが、それでは、なにか気持ち悪い気がします。何とか、'using strict'で動作させようとデバッグしています。
(2) 不要コードの削除
ここでも、不要コードの削除では苦労しています。見込みで削除すると動きません。他のところにも悪影響が波及しているのかもしれません。この作業が一番大変でした。
コードをよくしようとして、折角、動作しているコードに手を入れると、動作しなくなることはしょっちゅうです。直そうと思って、次から次へと修正してゆくと、最後はとんでもないことになり、結局は、元のベースのコードに戻すことになります。それまでの数々の修正はすべておじゃんです。不要コードの削除作業は、この繰り返しです。
結論
(1) 再利用するときは、元のコードは整理されたコードであること。
(2) 機能を落とす再利用か、機能を追加する再利用かにより、ベースとなるコードを見極める
(3) 'using strict'してから再利用する
(4) 再利用は昔からある手法だが少しでも手を加えたコードは、一からテストし直さなければならない。
(5) 辛抱強く、修正&確認の作業に耐えること。焦らないこと。
あとがき
結局、コードの再利用の容易さは、ベースとなる元コードの品質次第ということになります。
オープンソースとして公開するには、それなりに整理されてなくてはなりませんが、まず、自分自身で自分のコードを再利用してみることから始めたいと思います。今、そのコードを見直しているところです。
ご参考まで
youtubeつぶやきサイト
このようなサイトを作成しています。