山pの楽しいお勉強生活

勉強の成果を垂れ流していきます

Googleドライブにファイルが追加されたらメール通知する

背景

子どもの写真をGoogleドライブで親達に共有しているのですが、遠方に住む義父から通知来ないといつ見ればいいかわからん!と連絡が。 さらに要望を聞くと、写真はフォルダ管理してるのですが、どのフォルダが更新されたかも教えて欲しいとのこと。

通知機能くらいGoogleドライブにあるだろと思って調べたが、そんな機能はなかったのでGoogle Apps Scriptで実装してみました。

実装

前回メールした時から更新されていた場合にメールを送る必要があるため、前回メール時の更新日時はスプレッドシートで保存することにします。

  1. Googleドライブの写真フォルダ配下から最終更新日時を取得。
    • フォルダ分けして管理していたため。
  2. 更新日時を管理しているスプレッドシートから前回メール送信時の各フォルダの更新日時を取得。
  3. スプレッドシートに保存していた最終更新日時より現在のフォルダの最終更新日時が新しかったらメールを送信。

って、ここまでblogに書いて気づいた。 毎日スクリプトを動かすんだから、前日に更新があったフォルダをメールすればよかったのでは!? その場合、スプレッドシートもいらないし、もっと簡単な実装になりますねw

まぁ、GASの練習になったので、GASのメモとして記録します。。。

コード

var PHOTO_FOLDER_ID = "xxxxxxxxxx";
var UPDATE_SHEET_ID = "yyyyyyyyyy";
var UPDATE_SHEET_NAME = "更新日時";
var SEND_MAIL_ADDRESS = ["example1@example.com", "example2@example.com"]

function updateCheck() {
  var photoFolder = DriveApp.getFolderById(PHOTO_FOLDER_ID);
  var folders = photoFolder.getFolders();
  
  // 写真フォルダ配下の最終更新日時を取得。
  var lastUpdateMap = {};
  while (folders.hasNext()) {
    var folder = folders.next();
    lastUpdateMap[folder.getName()] = folder.getLastUpdated();
  }

  // スプレッドシートに記載されているフォルダ名と更新日時を取得。
  var spreadsheet = SpreadsheetApp.openById(UPDATE_SHEET_ID);
  var sheet = spreadsheet.getSheetByName(UPDATE_SHEET_NAME);
  var data = sheet.getDataRange().getValues();

  // 取得したデータをMapに変換。
  var sheetData = {};
  // 説明とヘッダを記載しているため2からstart。
  for (var i = 2; i < data.length; i++) {
    sheetData[data[i][0]] = {name : data[i][0], lastUpdate : data[i][1], rowNo : i + 1};
  }

  // 実際のフォルダとスプレッドシート情報を比較。
  var updateFolderList = [];
  for (key in lastUpdateMap) {
    if(key in sheetData) {
      // フォルダ名がシートに存在する場合。
      if(lastUpdateMap[key] > sheetData[key].lastUpdate) {
        // フォルダが更新されている場合。
        sheet.getRange(sheetData[key].rowNo, 2).setValue(lastUpdateMap[key]);
        updateFolderList.push(key);
      }
    } else {
      // フォルダ名がシートに存在しない場合。
      sheet.getRange(sheet.getLastRow() + 1, 1).setValue(key);
      sheet.getRange(sheet.getLastRow(), 2).setValue(lastUpdateMap[key]);
      updateFolderList.push(key);
    }
  }

  // 新規及び更新された情報をメール送信。
  if (updateFolderList.length != 0) {
    SEND_MAIL_ADDRESS.forEach(function(o,i) {
      MailApp.sendEmail(SEND_MAIL_ADDRESS[i],"写真更新連絡通知",
                        "写真が更新されました。" + "\n" +
                        "更新されたフォルダは以下の通り。" + "\n" +
                        updateFolderList.join("\n") + "\n\n" +
                        "URLはこちら↓" + "\n" +
                        photoFolder.getUrl() + "\n\n" +
                        "このメールに返信しても見れませんので返信しないでください。"
                        );
    });
  }
}

家庭内の写真、タスク(買い物リスト)の共有 #家庭を支える技術

お約束?

家庭を支える技術 Advent Calendar 2015」の15日目の記事です。*1

はじめに

家庭を支える技術にエントリーしていますが、実はそれほど技術を駆使している訳ではありません。

結局なんだかんだあって、シンプルに使用しているというのが現実です。 今回は写真の共有と、タスク管理(買い物リスト)共有方法を紹介したいと思います。

写真

今年の1月に子どもが生まれたのですが、妻の実家が遠方*2のため、写真や動画を共有しています。 Webで調べたら色々なサービスがありましたが、結局Googleドライブでの共有に落ち着きました。(Googleフォト?違いがよくわからない。。。)

子どものアカウントを作り、そのアカウントのドライブの1フォルダに私と妻、双方の両親のアカウントを共有設定しています。これにより、子どもが成長した際にはアカウント毎プレゼントすることで、生まれてからの自分の写真も共にプレゼントできるという事も考えています。

元々、私個人ではDropBoxを使用していましたが、写真や動画が制限があるものの容量を気にせず使える事*3が決め手になりました。義父がそれなりにPC操作に詳しいので共有さえしてしまえば任せられるという点も助かっています。

ちなみに、PC操作が得意でなかった場合は、同期をしたタブレットを送りつけるという方法をとるような気がします。

家族予定管理

こちらもGoogleカレンダーを妻と共有しています。私と妻は共にiPhoneなので、標準カレンダーアプリのデフォルトをGoogleカレンダーに設定して使用しています。(設定はこことかを参照。)Googleカレンダーなのでアプリ移行や、iPhoneを卒業した際にもデータ消去することなく移行できるかと考えています。

個人用と家庭用を特に分けておらず、共有しているカレンダーにどんどん追加していますが、飲み会やら遅くなりそうな日も伝わるので問題にはなっていません。

タスク管理(買うものリスト)

これもiPhoneデフォルトのリマインダを使用しています。色々なサービスやアプリを試してみましたが、結局これに落ち着きました。

サービスやらアプリを探している時にはあれもこれもと機能が欲しくなりますが、結局タスクや買うものを追加する時には設定なんてしないので、シンプルにタスクが表示され、チェックすると消える。そして、共有が可能。という点を考えるとデフォルトアプリが最適でした。*4

話を聞くと使っていない方が多いみたいなので、iPhone同士の方はぜひ使ってみてください。

終わりに

家庭内での情報共有を考えると、色々なサービスやアプリケーションがみつかります。ですが、結局シンプルな管理になることが多いのではないかと思います。ちなみに、家計の管理は回り回って紙のノートでつけていたりします。*5

勿論それぞれ家庭にもよるのですが、複雑なサービスやアプリケーションで日々の使用に疲れている場合には、シンプルなサービスやアプリケーションを試してみてはどうでしょうか。

*1:遅れてすいません。orz

*2:私は東京住まいで、妻の実家は広島。

*3:1600万画素までの写真と1080pまでの動画

*4:使ったことはありませんが、日時指定や優先順位の設定も可能みたいです。

*5:妻が文房具オタクで色々試したいというのもあるのですが。

子育て中の時間の作り方 #childadvent

お約束?

子育てプログラマ・ITエンジニア・Webデザイナー Advent Calendar 2015」の6日目の記事です。

昨日は渡邊タツアキさんの「まだ手作業で消耗してるの?時短家電で家事をKAIZENしよう:子育てエンジニアアドベントカレンダー」でした。

前置き

自分に子どもが生まれる前、子どもが生まれたばかりのあるエンジニアから聞きました。

(子どもが生まれて)自分はエンジニアとして死んだ。

詳細を聞いたところ、子どもが生まれる前までは普通に行っていた、情報収集や、勉強、が全くできないとの事。 当時は「へ~」って感じでしたが、今年の1月に娘が産まれてその言葉が事実であることを知りました。

特に私の場合、妻が体が弱いこともあり家にいる間の子どもの世話、家事は100%私が行っていた事もあり、エンジニア的な勉強どころか自分の時間すら一切取ることができませんでした。(完全ミルクです。) やることに終われ、自分の時間が取れないことはストレスに繋がります。

10ヶ月がたち、多少は落ち着いてきたことありますが、時間を作るコツがわかってきたので記事にしたいと思います。(あくまでも自分の場合なので賛否はあるかと思います。)

家事時間圧縮

食品購入は宅配を活用。

Amazon楽天で物を買っていても、食品はスーパーやコンビニで買っている方が多いのではないでしょうか。 会社帰りに店に寄る時間が勿体ないので、家まで持ってきてもらいましょう。

そこで問題となるのが送料ですが、各サービス共に赤ちゃん割引的なことを行っているため、無料もしくはかなり安く使用が可能です。

うちの場合は、コープデリ赤ちゃん割引・子育て割引で送料無料)、イトーヨーカドー母子手帳の提示で送料が100円)を使用しています。(うちの近くの店舗は赤ちゃん本舗の商品も含まれるためかなり便利。) イオンも候補だったのですが、選択する際に品物数がかなり少なかったため候補から外れました。(イオンブランド以外が少なかった。)

条件が良くても、品数がかなり少なかったり、お気に入りのおむつや粉ミルクがなかったりするので、いくつかサービスを比べてみると良いと思います。 おむつや粉ミルクならAmazonでも扱っていますので、食品は不要でいいならAmazonでも良いかと思います。

料理は冷凍。

料理は作るときに大量に作って冷凍しておきましょう。 だいたいの物は冷凍可能です。(正直生まれたばかりの時は食べ物を味わう余裕なんてないので、多少味が落ちても気にならないw)

掃除はある程度手を抜く。

生まれたばかりの赤ちゃんは動けないのである程度ものが散らばっている程度ならば問題ありません。 赤ちゃんのために綺麗にしないと!と考えていたらストレスになりますし、最低限埃がたまらない程度(私は土日のどちらかで行っていました。)で良いのではないでしょうか。(性格にもよるでしょうけど。。。)

情報収集は効率よく。

正直、ここはフォーカスしている部分にもよるかと思いますが、はてブ、まとめ、Twitterなど、ある程度情報がまとまっている所を抑えるようにしました。

情報ソースを多く持っている方は、ある程度の切り捨てが必要な箇所かもしれません。

コードを書く時間と考える時間は分ける。

考えている時間はありません。通勤時間、料理中、子どもを寝かしつけている時などに実装を考えておきましょう。 コードを書く時間ができたらその思いをエディタにぶつけましょう。

子どもに構いすぎない。

生まれたばかりの赤ちゃんはいつまでも見てたくなりますが、寝たら静かに急いでやることをやりましょう。 どうせすぐ起きて、見ることになります。

最後に

時間がなくなるのはわかっていましたが、これ程何もできないとは思っていませんでした。 ただ、上記の事によってできた細かな空き時間をかき集める事で多少なりとも時間を作ることができたと思います。 そして、その時間にエンジニアとしての勉強、自分の趣味を行うことで、エンジニアとしての知識の維持、ストレス解消を行うことができました。

子育ては大変です。ストレスや体力低下は気づいた時には結構深刻な事になっています。 子どもの体調に気を配るのは勿論ですが、自分自身の体調にもより一層気を配っていきましょう。

ハチイチ忘年会に参加してきた。 #1981s

ハチイチ忘年会って何?

ハチイチ忘年会は 1981年生 のWeb・IT系エンジニアの人達が「幹事をする」 忘年会です

ようは、ただの飲み会です。

atnd.org blog.yusuke.be

概要

毎年年末恒例のハチイチ忘年会に参加してきました。 昨年は全く覚えてないほど飲んで、4時まで妻に怒られたりしてましたが、なんとか許しを得て2011年、2013年、2014年に続いて4回目の参加となりました。

今年はいつも以上に色々なテーブルを回ることを意識していたのですが、ほんと各テーブルでいろんな人がいて面白い! 基本的には1981年付近生まれのエンジニアが多いと思っていたのですが、最初のテーブルは経営者が多く、次のテーブルではデザイナー、別のテーブルでは営業、アーティスト?、年齢も学生、新卒の方からIT業界の歴史を語れる人までまぁほんと様々な方とお話することができました。

毎年言ってますが、今年も生きててよかったと思う位楽しかった! 来年も必ず参加するので、今年お世話になった方は来年もよろしくお願い致します。

その他

  • お酒は飲んでいないのにも関わらず、話した方あまり覚えてませんので、どこかであったら声かけてくれると嬉しいです。(顔覚えるの苦手なのです。)
  • コーラ20杯は飲んだ。
  • 1次会終わった後、挨拶もそこそこにダッシュで帰ったので今年は妻に怒られませんでした!
    • 来年は2次会も参加できるといいな。
  • 幹事の方々ありがとうございました!

2つのリストボックス内でアイテムを入れ替えるBootstrapプラグイン「Bootstrap Dual Listbox」

概要

2つのリストボックス内でアイテムを入れ替えるBootstrapプラグイン「Bootstrap Dual Listbox」を使用したのでメモ。 このUIを言葉で説明するのは難しいので下記のサンプルを参照。 ちなみに、社内アプリケーション作成中に要件として必要だったので導入。

f:id:yamap_55:20150808132822j:plain

サンプル

Bootstrap Dual Listbox Sample on jsbin.com

コード

↑のサンプルに記載していますが、消えたとき用にコピペ。

  • multipleなselect要素に対してbootstrapDualListbox()メソッドを呼べばOK。
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Bootstrap Dual Listbox Sample</title>
  <script src="https://code.jquery.com/jquery.min.js"></script>
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
  <link href="https://rawgit.com/istvan-ujjmeszaros/bootstrap-duallistbox/master/dist/bootstrap-duallistbox.css" rel="stylesheet" type="text/css"  />
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
  <script src="https://code.jquery.com/jquery-git.js"></script>
  <script src="https://rawgit.com/istvan-ujjmeszaros/bootstrap-duallistbox/master/dist/jquery.bootstrap-duallistbox.js"></script>
</head>
<body class="container">
    <select multiple="multiple" size="10" id="sample">
      <option value="option1">Option 1</option>
      <option value="option2">Option 2</option>
      <option value="option3" selected="selected">Option 3</option>
      <option value="option4">Option 4</option>
      <option value="option5">Option 5</option>
      <option value="option6" selected="selected">Option 6</option>
      <option value="option7">Option 7</option>
      <option value="option8">Option 8</option>
      <option value="option9">Option 9</option>
      <option value="option0">Option 10</option>
    </select>
</body>
</html>
var demo1 = $('#sample').bootstrapDualListbox({
  filterTextClear:'全件表示',
  filterPlaceHolder:'検索',
  moveSelectedLabel:'選択済みに移動',
  moveAllLabel:'選択済みに全て移動',
  removeSelectedLabel:'選択を解除',
  removeAllLabel:'選択を全て解除',
  moveOnSelect: false,
  nonSelectedListLabel: '一覧',
  selectedListLabel: '選択済み一覧',
  infoText:'{0}件',
  showFilterInputs:true,
  infoTextEmpty:'0件',
  infoTextFiltered:'{1}件中{0}件表示',
});

オプション

V3.0.4(2015/08/07時点の最新)のオプションを日本語訳してみた。(原文は公式のSettings) 英語は得意ではないので参考程度にどうぞ。

オプション名 概要
bootstrap2Compatible Bootstrap2の場合は「true」?デフォルト「false」
filterTextClear フィルタリングを行っている際に、全件表示するボタンのラベル名。デフォルト「show all」
filterPlaceHolder フィルタリング文字列を入力するテキストボックスのPlaceHolder。デフォルト「Filter」
moveSelectedLabel 選択済みに移動する「→」ボタンにマウスを当てた際に表示される文字列。デフォルト「Move selected」
moveAllLabel 選択済みに全件移動する「→→」ボタンにマウスを当てた際に表示される文字列。デフォルト「Move all」
removeSelectedLabel 選択済みから移動する「←」ボタンにマウスを当てた際に表示される文字列。デフォルト「Remove selected」
removeAllLabel 選択済みから全件移動する「←←」ボタンにマウスを当てた際に表示される文字列。デフォルト「Remove all」
moveOnSelect マウスクリックで移動させるか否か。falseにすると移動させるための「→」、「←」ボタンが表示されます。trueじゃないとAndroidで動かない?デフォルト「true」
preserveSelectionOnMove 移動させた要素を移動後に選択状態にするかどうか。「moveOnSelect」がfalseの場合に効果が出る。デフォルト「false」
selectedListLabel 選択済みの上部に表示される項目名。デフォルトは表示しない。
nonSelectedListLabel 未選択の上部に表示される項目名。デフォルトは表示しない。
helperSelectNamePostfix デフォルトは「helper」。意味わからず。原文「'helper': The added selects will have the same name as the original one, concatenated with this string and 1 (for the non selected list, e.g. element_helper1) or 2 (for the selected list, e.g. element_helper2).」
selectorMinimalHeight 最小の高さ。単位はpxか?デフォルト「100」
showFilterInputs フィルタリングを行うテキストボックスの表示有無。デフォルト「true」
nonSelectedFilter 未選択のフィルタリングテキストボックスの初期値。デフォルト「」
selectedFilter 選択済みのフィルタリングテキストボックスの初期値。デフォルト「」
infoText 現在の件数の文字列。「{0}」が現在の件数に置き換わる。デフォルト「Showing all {0}」
infoTextFiltered フィルタリングされている際の表示文字列。「{0}」がフィルタリング後の件数、「{1}」が全体件数に置き換わる。デフォルト「Filtered {0} from {1}」
infoTextEmpty 要素が0件の際に表示される文字列。デフォルト「Empty list」
filterOnValues Option要素のvalue値でフィルタリングするか否か。デフォルト「false」

ちなみに

同じ様なUIがBootsnippもあったけど、少しピンとこなかったので今回はスルーしました。

参考URL

console.logの出力にスタイルを指定する方法

概要

cookpadを見ていてふと開発者ツールを開いたら、警告が表示された。 細かいところまで行き届いてるのか、はたまた、実際にコンソールで操作させて何か行わせた事例でもあったのか。 それとも、小粋な遊び心?(「cookpad.joinUs();」と実行するとcookpad内の採用情報ページに飛ばされる。)

それはそれとして、表示されたメッセージに色がついていたことに驚愕。 ライブラリでも使っているのかなと思って調べたら、引数でスタイルを渡し、出力文字列に「%c」で指定することでスタイルをあてる事ができるらしい。

具体的には以下の通り。

console.log("%cこれは赤字です。", "color: red");

複数指定する場合には、引数にスタイルを再度追加して、出力文字列には「%c」を再度指定する事で可能。(文字列は「"」で区切られる。)

console.log("%c赤色%c1.5倍", "color: red", "font-size:150%");

指定したスタイルを消すには空文字を指定というのを見ましたが、2015/07/28現在ではこれはChromeのみ。 firefoxだとその前の指定を引き継ぎ、IEだとそもそもスタイルの指定が効きません。

うまく使えば色々便利そうですが、consoleオブジェクトって仕様決まってるんですかね?

参考URL

リーダブルコード1章から3章までまとめ

概要

社内でリーダブルコードの輪読会を開催してみるので、1章から3章までをまとめた。 せっかくなのでblogにも記載。

はじめに

  • 本書の目的は、読みやすいコードを書く事。
  • 本書の目的は、君のコードを良くすること。
  • コードは理解しやすくなければいけない。
    • 誰かが君のコードを読んで理解する時間を最短にする。

1章 理解しやすいコード

1.1 「優れた」コードって何?

1.2 読みやすさの基本定理

  • 優れたコードとは読みやすいコード。
  • コードは他の人が最短時間で理解できるように書かなければならない。
    • ○日後の自分自身も含む

1.3 小さなことは絶対いいこと?

  • 大きいより小さい方が理解するまでに係る時間は短い。
  • ただしコードが小さければ必ず良いということではない。
  • コードは短くしたほうが良いが、「理解するまでにかかる時間」を短くするほうが大切。

1.4 「理解するまでにかかる時間」は競合する?

  • 高度に最適化されたコードでも、もっと理解しやすくはできる。
  • 理解しやすいコードは設計、テストを行いやすい傾向がある。

でもやるんだよ

  • 理解しやすいかどうかを考えるのは大変だが、優秀なプログラマになるために頑張ろう。

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

2.1 明確な単語を選ぶ

  • 「get*」では何をどこからどのように取ってくるのか不明瞭。
    • FetchPage,DownloadPageなどはどうか。
  • 「size」は何のサイズか不明瞭。
    • Height,NumNodes,MemoryBytesなどはどうか。

もっと「カラフル」な単語を探す

  • 類語辞典を使う。
    • オンラインでは良い所みつからず。
  • 気取った言い回しよりも明確で正確な方がいい。
    • 正直気取った言い回しかどうかがわからないので、注意しようがないか?
    • githubとかの使用頻度とか?

2.2 tmpやretvalなどの汎用的な名前を避ける

  • 変数の値を表す名前を選ぶ。
    • 私はやりがちなので気をつける。
  • 汎用的な名前を使用するときには、それ相応の理由がある場合。

tmp

  • 生存期間が短くて、一時的な補完が最も適切な変数に使用する。
    • temporaryとしての本来の意味がある場合に使用する。

ループイテレータ

  • 明確な名前を使用する。(club_i、ci、members_i、miなど)
    • club_iならまだわかるが、ciとなると分かりにくい気がする。
    • forがネストしてi,jを間違えるというのはよくあるが、名前を付けるほどか?
    • そもそも最近はstreamなどループを使用しないようにするのか?

2.3 抽象的な名前よりも具体的な名前を使う

  • 正直この辺りは英語が苦手なので難しい。

DISALLOW_EVIL_CONSTRUCTORS

  • 正直よくわからず。

--run_locally

  • この場合、使用用途ではなく、機能をOptionにするべきという理解しかできなかった。

2.4 名前に情報を追加する

値の単位

  • 有効な場合もあると思うが、単位を入れることで助かるケースは少ない気がする。

その他の重要な属性を追加する

  • htmlの文字コード : html_utf8
  • エスケープ前のコメント : unescaped_comment
  • 安易に変数名を付けガチ。ここは意識していきたい。

2.5 名前の長さを決める

スコープが小さければ短い名前でもいい

  • 逆に、スコープが大きければ長い名前を付ける。
  • 1文字で良いスコープの範囲は数行か?

長い名前を入力するのは問題じゃない

  • 補完がある
  • が、やはり限界があると思う。(似た長い名前など。)

頭文字と省略形

  • 一般的な略語はOK。(str、doc、evalなど)

不要な単語を投げ捨てる

  • これによって短くなるのはわかるが、選別が難しい。

2.6 名前のフォーマットで情報を伝える

その他のフォーマット規約

  • 大文字やアンダースコアなどに意味を含める。
  • Javaではfinalは全て大文字とか。

2.7 まとめ

3章 誤解されない名前

  • 名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する。

3.1 例 : filter()

  • フィルタリングの条件でtrueの値かfalseの値か不明瞭。
  • 通常はtrueの値ではないか?

3.2 例 : Clip(text, length)

  • 正直Clipという単語に馴染みがないのでなんとも言えなかった。

3.3 限界値を含めるときはminとmaxを使う

3.4 範囲を指定するときはfirstとlastを使う

3.5 包含/排他的範囲にはbeginとendを使う

  • startといったらendな気がしたが、これは日本人だから?

3.6 ブール値の名前

  • is,has,can,shouldを頭に。
  • 個人的にcanとshouldはあまり使わない。shouldは見たことないがどうか?

3.7 ユーザの期待に合わせる

例 : get*()

  • Javaの場合、メソッド内で変換してるという事自体がイレギュラーか?

例 : list::size()

  • Javaでも以下のコードはあまりよろしくない。
for (int i = 0; i < list.getLength(); i++) {}

3.8 例 : 複数の名前を検討する

  • 2章の最初、2.1辺りと被るが、類語辞典などか?

3.9 まとめ

  • 最善の名前とは誤解されない名前。