ソフトウェアメトリクスは誰のもの?

偉人と凡人の別は一言にして尽くすべきのみ。かれは人生を簡単にする者なり。これは人生を複雑にする者なり。
高山樗牛

ソフトウェア開発の現場では、成果物やプロセスの評価、見積もりのために様々なメトリクスを収集します。メトリクスと一口でいっても、プロダクトメトリクスから、プロセスメトリクス、リソースメトリクスなど様々ありますが、主要なものでは、生産性を示す指標としてソースコード行数をかかった工数でわったKSTEP/人月のようなものや、その他にも、ソースコード中のコメントの割合を示すコメント率、欠陥数をソースコード規模で割った欠陥密度(バグ密度)などなど、その多くがソースコードのステップ数、行数がベースになっています。
こういったメトリクスメトリクスを測るということ自体は、プロダクトやプロセスを客観的に眺めるために有用ではあるのですが、その特性を理解しておかないと間違った指標として使われることがあります。

ソースコード行数という脆い足場

ソフトウェア開発の現場でよく使われるKSTEP/人月ですが、なんとなく高い方が良いと思われがちかもしれません。果たしてそうでしょうか?実装されたソースコードが同じであれば確かにその通りなのですが、差分開発なのか新規開発なのか、GUIアプリケーションなのか、デバイスドライバなのか、あるいはアルゴリズム実装なのかなど、その特性によって同じ難易度であってもソースコードの開発規模(新規コード or 修正コード)は大きく変わります。さらには、同じ機能実装であっても、プログラマのスキルによって、コードサイズは大きく変わります。例えば、優れたプログラマであれば数百行程度のロジックであっても、スキルの低いプログラマではその何倍もの可読性や効率の悪いコードを書くことがあります。これら両方が1ヶ月かかって開発したコードであったときに、後者の方が生産性が高いというのはありませんよね。つまり、ソースコード行数を基準値にしたメトリクスというのは、絶対的な指標としてはなかなか使いにくいパラメータです。特に、生産性の場合、優れたプログラマほど、少ないコード量を少ない期間でしあげることになるので、スキルの低いプログラマが冗長なコードを長時間かけて書いた時と同じような指標になってしまいます。欠陥密度(欠陥数/ソースコード行数)も同じような課題があります。

コメントは多い方がいいのか?

それでも、バグや開発工数は少ないに越したことはないとはいえますが、コメントとなるとそもそも多い方がいいのか少ない方がいいのかというところから意見が別れるところです。現場によっては、不要なコメントが山のように入っているコードがありますが、こういうコメントは害悪でしかありません。コメントないと分からないような実装になっているか、あるいは、無意味なコメントか。このあたりは随分前の投稿にも書きましたが、個人的には、基本的には極力書かない(書かずともわかる)というスタンスにすべきと思いますので、コメント率は少なめ(20%以下くらい)になるのが良いと思います。この辺の話はよく議論のタネになりますが、どちらの意見にも共通するのは、ソースコードを読む人が必要な情報が必要十分な形で伝わるようにするのが大事という点かと思います。

メトリクスをとっても意味はない?

ソースコード行数をはじめとして、ソフトウェアメトリクスというのはその基準値そのものがあいまいであったり、単純な量だけでは評価できないという性質をもっています。なので、異なる種類のプロジェクトを比べて、どっちが良いとか悪いとか、あるいは、絶対的な目標値を設定するということには使えません。この辺が正しく理解されず、間違った運用(いろんなプロジェクトを十把一絡げにして目標値を決めるとか、全く別のプロジェクトの成果をベースに見積もりをするとか)がされるのは非常に危険です。

では、全く約に立たないかというとそうでもありません。同じようなスキルのメンバーが同じようなソフトウェアを作るのであれば、実績としてのメトリクスを使った見積もりは有効でしょうし、メトリクスをベースに品質を評価(予測)することもできるでしょう。また、別々のプロジェクトが単純比較はできなくても、メトリクス値からプロジェクトの中で何が怒っているのかを予測することもできます。例えば、スキルの低いメンバーと高いメンバーで生産性(KSTEP/人月)がかわらないのであれば、スキルの低いメンバーのソースコードが冗長という可能性が高いのかもしれません。コメント率が著しく低い傾向があったら、いくつかファイルを見ることで、本当に優れたコードでコメントが最小限なのか、単にコメントも何もないわかりにくいコードなのかをチェックするきっかけになります。

このように、単純にメトリクスの数値を絶対的な指標として盲信するのではなく、その裏にある背景(コード品質や担当者のスキル)を把握するツールとして利用することで、メトリクスの価値が発揮されます。

4903729958 4873115655 4822282422

mallocの落とし穴 - 組み込みLinuxでのmemory overcommit

天災は忘れた頃にやって来る
寺田寅彦

組み込みLinuxにおけるメモリ確保のエラーハンドリングに関するお話。

Linuxにはmemory overcommit(オーバーコミット)と呼ばれる仕組みがあります。簡単にいうと、メモリ割り当ての段階では、仮想アドレス空間だけをわりあてて、実際に使われる段階で、実メモリを割り当てるというものです。メモリ割り当て時には、実メモリはまだ割り当てられないので、実際の物理メモリの容量以上のメモリ割当てが行われることを許されることになります。

実例を見た方が早いので、例えば以下の例。
#define BLK_NUM 100
#define BLK_SIZE (100 * 1000 * 1000) /* 100MB */

int
main(int argc, char* argv[])
{
  int i;
  char* blk[BLK_NUM];

  for (i = 0; i < BLK_NUM; i++) {
    blk[i] = malloc(BLK_SIZE);
    assert(blk[i] != NULL);
  }

  return 0;
}
mallocでヒープを100MBx1000 = 10GB取得していますが、これをコンパイルしたものを実メモリ128MBのLinuxで実行してもおそらくassert()にはひっかからず正常終了します。これはmallocの段階では、仮想メモリのみが割り当てられ、実メモリが割り当てられていないためです。つまり、アドレス空間を超えるような異常なmallocでもしない限り、mallocの戻り値は常に成功(NULL以外)で返ります。実際、malloc完了したところでプロセスのstatus値を見てみると、VSSは増えているものの、RSSは増えていないことが確認できると思います。(returnをwhile(1)やsleepにでもして、psやprocでみて見るとよくわかります)。

では、以下の分をmallocのループの下に加えるとどうなるでしょうか。
  for (i = 0; i < BLK_NUM; i++) {
    memset(blk[i], 0, BLK_SIZE);
  }
今後は、メモリが10GBもないようなシステムでは、実行途中に以下のようなログとともにプロセスが強制終了したと思います。
01:00:00 xxxxx kernel: Out of memory: Killed process 10000, UID 100, (xxx)
memsetによって書き込みが発生する段階で、実メモリが割当りあてられ、この時点でプロセスがkernelに強制的にkillされてしまいます)。いわゆるOOM-killer(out of memory killer)という仕組みで、カーネルがメモリを大量消費していると思しきプロセスを強制的にkillする仕組みです。教科書的な「mallocでは、戻り値見てメモリを取得できたか確認しましょう」というのはこの場合通用しないのです。さらに、困ったことに、必ずしも犯人とは限らないプロセスが殺される場合もあります。これだと、個別のユーザーアプリケーション側では対処のしようがありません。

そういうわけで、かなり不評なしくみでもあり、memory overcommitの仕組みについては、仕様バグだという言われようもよく見かけます。そういうことで、最近(というかkernel 2.6からなので結構前から)のLinuxには、overommitの挙動を変更する仕組みがあります。具体的には、sysctl、もしくは、直接proc/sysに値を書き込むことで設定を変更できます。以下、procのman pageから引用、
/proc/sys/vm/overcommit_memory
 このファイルにはカーネル仮想メモリーのアカウントモードが書かれている。 値は以下の通り:
  0: 発見的なオーバーコミット (heuristic overcommit) (これがデフォルトである)
  1: 常にオーバーコミットし、チェックしない。
  2: 常にチェックし、オーバーコミットしない。

/proc/sys/vm/overcommit_ratio (Linux 2.6.0 以降)
 この書き込み可能なファイルは、 オーバーコミットできるメモリーの割合をパーセントで定義する。 このファイルのデフォルト値は 50 である。 /proc/sys/vm/overcommit_memory の説明を参照。
上で、「犯人と思しきプロセス」がkillされるというのが、ここでいうheuristic overcommitというやつですね。どの閾値でoom-killerが呼ばれるかは、 以下の式になります。
CommitLimit = (total_RAM - total_huge_TLB) * overcommit_ratio / 100 + total_swap
組み込みでmallocでとったメモリを確実に確保したいというのであれば、overcommit_memory=2にしてovercommit_ratioを100に近い値にしておけば、基本的にはmallocでNULL以外がかえってくれば、そのメモリは使えるというこが一応保証されることにはなります。

では、組み込みの場合は、overcommit_memory=2を使うべきなんでしょうか?

残念ながらそうとは言い切れません。仮想メモリとして確保した分だけ、実メモリも消費する(実際割り当てられないとしても総和はこえないようコントロールされる)ということになると、以下のような場合に相当の実メモリが必要になります。
  • 各プロセス、スレッド毎のスタック用メモリ
    • 通常スレッドあたり2MB
    • 通常のスレッドならそこまでメモリは使わないのでovercommit=0なら必要量のpageのみが実メモリとして割り当てられるが、overcommit=2ならまるまる必要になる。
  • forkする際のfork元プロセスが使用しているメモリ
    • 通常、forkして時にはfork元プロセスのメモリ空間がコピーされるが、いわゆるcopy on writeという仕組みで、書き込みが行われない限りは、この段階では実際のメモリコピーは発生しない。
    • overcommit=2だと、その時点で実メモリの容量も予約されてしまう
    • 結果としては、fork(あるいは、中でfork実行するsystem関数など)が失敗することがある。

メモリ容量が少ない組み込みでは、こういう隠れた予約メモリがばかにならないので、結果としてovercommit=2で使うのはなかなか厳しいのではないかと。言い換えると、overcommit memoryという仕組みがあるおかげで、こういうケースにもうまく対応できているのだと考えられます。

じゃあ、一回メモリ不足はどうやってハンドリングしたらいいんだという話になりますが、基本的には組み込みなんだからメモリ使用量くらいちゃんと把握しましょうというのが基本ですが、エラー検出の方法としては、メモリ総量をwatchして不適切なプロセスがいればkillする、あるいは、リブートさせるという仕組みを自分でいれる方法になるのかと思います。ちなみに、oom-killerで中途半端にシステムを混乱させるくらいなら、kernel panicに落として、watchdogリセットにでももっていきたいということであれば、以下のproc設定(manpage引用)も検討候補になります。
/proc/sys/vm/panic_on_oom (Linux 2.6.18 以降)
 このファイルは、メモリー不足時にカーネルパニックを 起こすか起こさないかを制御する。
 このファイルに値 0 を設定すると、 カーネルの OOM-killer がならず者のプロセスを kill する。 普通は、OOM-killer がならず者のプロセスを kill することができ、 システムは何とか動き続けることができる。

 このファイルに値 1 を設定すると、 メモリー不足の状況が発生すると、カーネルは普通はパニックする。

memory overcommitにかぎらず、本当に必要なところまで処理を遅らせるという遅延処理は、パフォーマンスを最大化する上で非常に有用ですが、エラー処理が難しくなるので注意が必要ですね。

Linuxカーネル解析入門 (I・O BOOKS)Linuxカーネル Hacks ―パフォーマンス改善、開発効率向上、省電力化のためのテクニック UNIXという考え方―その設計思想と哲学

mbotでSTEM入門 - シャフトが壊れた時の修理方法

アトムは完全ではないぜ。なぜなら、悪い心を持たねぇからな。
手塚治虫 -『鉄腕アトム』

2020年、小学校でのプログラミング教育が必修化されることになり、「STEM教育」用の教材が増えてきました。STEMとは、"Science, Technology, Engineering and Mathematics" すなわち科学・技術・工学・数学の教育分野を総称する言葉で、これらを統合的に学ぶ機会を子どもたちに提供することで、次世代を担う人材に育てようという教育方針です。最近では、これに芸術(Airt)のAを加えてSTEAM教育という言葉も聞かれます。ニューヨーク市立大学教授のキャシー・デビッドソン氏がインタビューで語ったとされる「2011年度にアメリカの小学校に入学した子供たちの65%は、大学卒業時に今は存在していない職業に就くだろう」という予測も話題になりました。

さて、そんな中で種類も増えてきているSTEM教育用の教材ですが、やはり子供心をくすぐるのは自分でプログラミングできるロボットでしょう。子供向けのロボット教室も結構増えているようですが、最近はscratch(スクラッチ)というビジュアルプログラミング環境で、子供でもかんたんにプログラムが作れる環境が整っているので、キットさえ買えば自宅でも簡単にロボットプログラミングが始められます。

最初にどれを買うべきか

いろんなロボットが発売されていますが、最初の選択肢としてあがるのは以下あたりでしょうか。

LEGO midstorms

おそらく最も有名なのはLEGOのmindstormsでしょう。カスタム部品も抱負で、LEGOブランドの安心感もありますが、何分価格が高い。。大人も一緒に本格的にはじめたいというのならいいかもしれませんが、最初の子供用にはちょっと高いかな。

スタディーノではじめるうきうきロボットプログラミング

専用の解説書もあって、LEDチカチカから自動ドア、床ゆきお掃除ロボットと段階をおっていろんなものを作る楽しみがあります。これもなかなか楽しそうなので、次のmbotと迷いました。

Makeblock mBot

結局買ったのは、こちらのmbot距離センサ(超音波センサ)、ライントレースセンサ光センサブザーLEDと一通り入門に必要と思われるセンサが最初から搭載されており、bluetooth対応なので、付属のリモコンやPCあるいはスマホ、タブレットから操作までできます。これで1万円代中盤くらいなので、midstormと比べるとかなりお手頃です。プログラミング環境も、scratchベースのビジュアルプログラミング環境があるので、プログラミング経験のない小学生でもかんたんにはじめられます。ipad版ならPCもいらないのでさらにお手軽です (残念ながらiphone版はないのと、私の家のipad2はBLE(Bluetooth4.0)非対応なのでだめでしたが...新しいipadほしい..)。なお、mbotには、bluetooth版以外に赤外線版なるものもあるようですが、それだとリモートでプログラムの書き込み/デバッグができない(USBつながないといけない)ので、買うなら絶対bluetooth版がおすすめです。

私はサンワダイレクトさんから発売されているものを買ったのですが、詳しい説明がはいっていたので子供(小学校高学年)だけでかんたんに組み立てていました。プログラミングは、最初はさすがに少し説明しましたが、試行錯誤で距離センサーみてよけるものは結構手軽に作れてました。ビジュアルプログラミングなかなかあなどれないです。子供だけでできるように日本語の解説本(Makeblock公式 mBotで楽しむ レッツ! ロボットプログラミング)も購入しましたが、基本から順番に説明されていて、なかなかよかったです。

mBotの折れたシャフトの修理

なお、うちのmbotですが、完成してまだ電源をいれる前に、足で踏まれてシャフトがポッキリおれるという事故がありました。。修理部品をさがしてみたのですが、すぐには見つからず途方にくれそうになったのですが、そうえば、組立時にシャフトのあまりらしきものがあったのを思い出しました。「もしや、スペア部品?でも、何の説明もなかったけど・・・」と思って、もう少しぐぐってみると、以下の動画が見つかりました。
どうやら、シャフトは机からの落下等でよく折れるので、予備部品が最初からはいっていたようです。助かった。。
修理方法は動画の通りなのですが、モーターからキャップ外すのが結構固くて苦労しました。ドライバでひっかけて思い切ってやるしかないようです。

ということで、トラブルもありましたが、やっぱり目に見えて動くというのは、PC上に閉じたプログラミングとはまた全く違う楽しみがありますね。子供用と言いつつ、自分用にセンサ買い足したくなったきました ^^)

4865940847ロボットを動かそう! mBotで おもしろプログラミング
石井モルナ MAKO.
リックテレコム 2017-04-08

printfとtypedefの微妙な関係 - 無視されがち?なformt warning

型ができていない者が芝居をすると型なしになる。メチャクチャだ。
型がしっかりした奴がオリジナリティを押し出せば型破りになれる。どうだ、わかるか?
立川談志 - 『赤めだか』より

ひさびさにコーディングの話を書きたいと思います。組み込みの現場なんかで結構よく見かける話かと思いますが、以下のようなコードに対してでるwarningのお話です。

printfとtypdefの微妙な関係

ケースとしては、int等の組み込み型が環境依存なのを嫌って、typedefでint32_tやINT32という型におきかえることがあります。例えば以下のコード。
typedef long INT32;
int
main(int argc, char* argv[])
{
  INT32 val = 1;
  printf("val=%d\n", val);
  return 0;
}
さて、これをコンパイルすると、例えばgccなら以下のようなwarningがでます。(-Wallや-Wformatがある場合)
$ gcc -o test.c
test.c:9:22: warning: format specifies type 'int' but the argument has type
      'INT32' (aka 'long') [-Wformat]
  printf("val=%d\n", val);
-Werrorがついていればエラーになりますが、そうでない場合は、 実害なし、というか、別にあってるよね、くらいで無視されがちな気がしています。

実際のところ一般的な32bit処理系であれば、intとlongはどちらも符号付きの32bit整数型なので、 数値計算等で使っている範囲では全く同じなのですが、それでもwarningは出ます。なぜでしょうか?

INT32のようなtypedefを定義する理由は処理系依存の型を直接使わずに、 移植性を高めるために使われるものです。
(上の例なら、longが64bitになる64bitの処理系では、intへのtypedefに変えるなどする) 一方で、printfの%dは、そもそも処理系依存の型であるintを期待するものなので、 そこはintでなければ、処理系によっては不一致を起こすので、32bit系であろうと%dにはlongを渡す必要があるのです。

では、どうですればいいのでしょう?
上の例であれば、%dの代わりに%ld(signed long指定)を用いればwarningはなくなります。あるいは、引数側でintへのcastをしてやれば同じく問題はなくなります。
typedef long INT32;
int
main(int argc, char* argv[])
{
  INT32 val = 1;
  printf("val=%d\n", (int)val);
  return 0;
}
個人的には、printfのようなログ出力は処理系依存なので、引数の型の方にcastする上記やり方がスマートかと思います。 もちろんログなどではなくてファイルフォーマットにかかわるもので、移植時の型サイズ維持が重要なものはformat string側をかえるのが筋がいいものもあるとは思います。

「移植性をあげる」という目的で、処理系依存型を非依存型に変換するのはよく見かけるコードですが、一方で、非依存型から処理系依存型への変換というのは結構ないがしろにされがちです。strcmp等のstring系の関数でchar型を期待している関数を使う時も同じようなことがままあります。

なお、size_t, ssize_tについては、C99から専用のformat指定子zが定義されていますのでそれを使いましょう。(size_tから%zu、ssize_tなら%zd)

無視して良いwarning?

unsed-variablesとformatのwarningは無視されがちなwarningの2大巨頭ではないかと思います。どちらも大抵の場合は、確かに実害はないのですが、ごくまれにバグのものもあります。例えば以下のコード。
const char* name="taro";
printf("%d: name=%s\n", name, strlen(name)); 
引数順間違って%sに数値渡しているのでbuffer overrunをひきおこします。
ここで言いたいのは、「実害なし」という名目でwarningを残したり、 あえて、-Wno-formatのようにwarning抑制したりすることは、こういう本当にバグを埋もれさせかねないので、 基本的にはwarningは全て除去するというのは基本ポリシーとして実施すべきかと思います。

なお、デバッグ用にprintfを自作のマクロや関数でラップすることがありますが、 何もしないとprintfのformatチェックが機能しないことになり、 warning無視と同じくバグに気づくチャンスを逃すことになりかねません。 対策としては、例えばgccでは、独自定義マクロでもformatチェックするようにattributeしていることで コンパイラに指定する機構がありますので、あわせて活用することをおすすめします。
以下はgccの例です。
void debug_printf(const char* format, ...) __attribute__ ((format(printf, 1, 2)\
));

void debug_printf(const char* format, ...)
{
  va_list arg;
  va_start(arg, format);
  vprintf(format, arg);
  vfprintf(stderr, format, arg);
  va_end(arg);
}
上の例だと、__attribute__ formatという属性のを関数に付与することでformatチェックが入るようになります。引数の意味は、関数タイプ(この例だとprintf)、format文字列の位置(この例では1)、最初の引数の位置(この例では2)になっています。詳細は、以下gccのmanualが詳しいです。 ようするに、warningは正しく活用しましょうということですね。

なお、デバッグ出力用の可変個引数マクロやwarningの話は随分前にもとりあげていたので、よろしければご参考までに。

【関連記事】
可変個引数マクロを使う
warningに気を配る
使用しない仮引数

DVDで保存していた撮影動画をGoogleフォトで管理

忘れるにまかせるということが、結局最も美しく思い出すということなんだ。
川端康成 「散りぬるを」

前回に続いてmac環境でのGoogleフォトへの動画バックアップのTIPSを自分用メモもかねて紹介したいと思います。前回はAVCHD形式で撮った動画の保存についてでしたが、今回はDVDに保存した動画についてです。

さて、一口に「DVDで保存した動画」といってもいろいろな種類があります。PCにmp4形式のファイルをDVDにファイル保存したものもあれば、DVDやBlu-rayのレコーダでダビングしたものもあります。後者の場合、DVD-VideoやDVD-VR(Video Recording)といった形式で記録されることがほとんどだと思いますが、この場合、個々の動画が個別のファイルにはなっていないのでちょっと工夫が入ります。ここでは、多くのDVD/Blu-rayレコーダで採用されているDVD-VR形式で保存されたものについて説明したいと思います。

流れとしては、だいたい以下の手順になります。
  1. タイトル毎のファイルへの分割
  2. 撮影時刻の設定
  3. 拡張子変更
では順を追って説明します。

タイトル毎のファイルへの分割

Googleフォトはファイル単位で動画を管理するので、まずは撮影動画をファイル化する必要があります。このために以下のページで紹介されているdvd-vrというツールを利用します。 一応ツールのURLも。現時点ではv0.9.7でした。 このツールはコマンドラインベースのツールなのですが、実行バイナリではなくソースコードのみ公開されていますので、まずはビルドして実行ファイルを作成する必要があります。configureも必要ないので、適当なディレクトリで展開してmakeするだけでOKです。
$ tar zxvf dvd-vr-0.9.7.tar.gz 
$ cd dvd-vr-0.9.7
$ make
これで、dvd-vrという実行ファイルが作成されます。パスを通したい場合は、適切なフォルダに移動しましょう。

具体的なツールの使い方は上のURL参照頂ければいいかと思いますので、ここではポイントだけ説明します。基本的には、VR_MANGR.IFOファイルと、VR_MOVIE.VROファイルを指定してファイルを分割するだけです。
例として、タイトル確認 (パスが通っているところにdvd-vrがある前提で、DVD_VIDEO_RECORDERというボリューム名でマウントされているDVD内のタイトルを表示したいとした場合、コマンドとしては以下のようになります。
$ dvd-vr-0.9.7 /Volumes/DVD_VIDEO_RECORDER/DVD_RTAV/VR_MANGR.IFO
これでタイトルが確認できますので、次、ストリームファイルと分割後ファイルのprefixを指定してファイルを分割します。実際には既存ファイルを分割するのではなく、ファイルを区切りながらコピーするという動作になります。なお。分割後のファイルはコマンド実行したディレクトリ以下に作成されますので、あらかじめ分割後ファイルを入れたいフォルダに移動しておきましょう。
$ dvd-vr-0.9.7 /Volumes/DVD_VIDEO_RECORDER/DVD_RTAV/VR_MANGR.IFO /Volumes/DVD_VIDEO_RECORDER/DVD_RTAV/VR_MOVIE.VRO name=DVD
これで、DVD#001.vob, DVD#002.vob・・・というファイルが作成されます。

これで終了!と言いたいところですが、もう少し。
このままだと撮影日が本日になってしまいますので、これらに撮影日時情報を作成日及び変更日として記録します。
$ SetFile -d '09/24/2006 10:00:00' DVD#001.vob 
$ SetFile -m '09/24/2006 10:00:00' DVD#001.vob 
これでここのファイルへの分割というのは一端完了です。

拡張子の変更

上でできたvobファイルですが、残念ながらこのままだとGoogleフォトは****.vobをファイルとして見てくれません。vobの中身は基本的にはMPEGと同じでようなので、まとめてファイルをrenameします。
変更自体は以下のようなワンライナーで十分です。
for i in `ls *.vob`; do mv $i ${i%.vob}.mpg; done
ここで使っている部分一致の書き方は知らない方もいると思うので参考リンクあげておきますね。
これでDVD上の動画が全て.mpgファイルになったので、これらをアップロード対象ディレクトリに移動するなりすれば完了です。

DVDは保存やTVで見るには便利ですが、Googleフォトにいれると昔の動画もスマホで見れて楽しいですよ ^^)

B015XZLMKIパナソニック 1TB 2チューナー ブルーレイレコーダー 4Kアップコンバート対応 DIGA DMR-BRW1010
パナソニック 2015-10-16

googleフォトアップロード用に動画ファイルの変更日を作成日にあわせる

紙に書かず、心に書きとどむべし。
アンティステネス 「断片」

最近写真や動画の管理とバックアップはGoogleフォトに頼っているのですが、なかなか面倒なのがムービーで録画したAVCHD形式の動画。
当初、AVCHDをフォルダ毎HDDにコピーした先をGoogleフォトの同期先に指定して、アップロードするようにしていたのですが、MTSのままだとPCだとやっぱり使いづらい。
やっぱりmp4やmovに変換した方がいいのかなと思って、以下記事にあたりました。iMovieでかんたんにmov変換できるのですね。全然知りませんでした。
試しにSDカード上のAVCHDを取り込んでみると、たしかに変換される!名前がClip #1.movとかになるのはイマイチですが問題はないです。変更日は、取り込んだ日になっていますが、作成日もちゃんと引き継がれている。これはいい!

と、いうことで、早速いくつかたまっていたAVCHDをmovに変換しつつ取り込んだ後、Googleフォトのアップロードフォルダにコピー。これで完璧!!
と思ったのですが・・・

「日付が今日になってる。。。」

どうも、Googleフォトは作成日ではなく変更日をベースに日付を決定するようです。。そこは作成日じゃないのか、と言いたいところですが、そうはいってもむなしいだけなので対策を調べます。
結論としては、特に設定等はなさそうなので、Googleフォト上でアップロード後に手で日付修正するか、アップロード前に変更日を修正するしかなさそうです。

さすがに手で一つづつ作成日をコピーするのもバカバカしいので、shell scriptを用意しました。
#!/bin/sh

for i in `seq 1 $#`
do
	CREATED=`GetFileInfo -d "$1"`
	echo $1 ":" $CREATED
	SetFile -m "$CREATED" "$1"
	shift
done
これをchdate.shとかいう名前を実行パスの通ったところにでも保存して、変換後の動画の入ったディレクトリ上で、
$ chdate.sh *.mov
とかすれば完了です。
なお、これはmov変換時に変更日がかわったことによる対策ですが、MTSのままバックアップ取る場合は、mvコマンドやcp -pとかで日付が保存されるような形でバックアップとればもとの日付が保存されます。但し、SD上のデータが既に内部HDDからのコピーだったりすると、既に日付がコピー時のものなので、やっぱり今回のような対策は必要です。
そもそも、作成日を見てくれていれば話は早いのですが、まぁ無料でこれだけのサービスがある事自体がすごいわけで、わがままは言えないですね :-)

【関連書籍】
「シェル芸」に効く!AWK処方箋 斉藤 博文
[改訂第3版]シェルスクリプト基本リファレンス ──#!/bin/shで、ここまでできる (WEB+DB PRESS plus) 山森 丈範

Googleトレンドで見るバスワードの盛衰 - ユビキタスからIoTへ

怪しげな新興宗教の大半は、「目を覚ませ」と怒鳴りながら、
信者たちの目を瞑ったままにさせようとする。
ラッシュライフ』 - 伊坂 幸太郎

ここしばらく、といっても、かれこれ1,2年くらい頻繁に目にするようになったバズワード「IoT」, Internet of things, 日本語でいうところの「モノのインターネット」。今まではネットワークに接続されていなかった「モノ」が、ネットワーク、インターネットにつながり情報をやりとりすることで、新たな価値を生み出そうというもので、その「モノ」だけでなく、それらを利用したサービスやら、それを実現するための要素部品まで、あちこちで見かけます。なかには、もともとネットワークにつながっていたようなデバイスもIoTの仲間に入れられたりして、もうネットワーク機能がついたものなら何でもIoTという感じです。

思えば、一昔前に、クラウドというキーワードがもてはやされた頃、ネットワークを介してつながるサービスはなんでもかんでも「クラウド」とつけられて、「クラウドさえあれば何でもできる」みたいな風潮があったころを思い出します。 もちろん、IoTにせよ、クラウドにせよ、大きなイノベーションだと思いますが、本来の意味以上の拡大解釈とともに乱用されるさまは、まさにバズワードという感じです。

さて、Googleが提供しているサービスにGoogle Trends (グーグルトレンド)というのがあるのをご存知でしょうか。マーケティング等にかかわっている方は、よく使われているかもしれません。ある単語がGoogleでどれだけ検索されているかというトレンドをグラフで見ることができるツールで、話題のキーワードやその推移をみることができます。IoTっていつ頃から使われ始めたんだろう?というのを調べようと使ってみたのですが、いろいろ他のバズワードやキーワードも見てみると。結構面白かったのでいくつか紹介したいと思います。

ユビキタスからクラウド、IoTへ

カタカナ語と英単語がまざっているので、この結果は地域=日本に限定しています。

ubiquitous-web2_0-cloud-sns-iot.png

一昔前に一斉を風靡したバズワードといえば「ユビキタス」。私が社会人になった当時、これからはユビキタス社会だ!と言われていたのを思い出します。最近ではめっきり使われなくなったように思いますが、検索結果にもそれがあらわれていますね。
「IoT」については2014年あたりから伸びてきているのがわかります。「SNS」については、意外と結構前から検索件数としては多いのがわかります。カテゴリ限定していないのでノイズもあるとは思いますが。
なお、少し前から「スマートxxx」という単語もよく使われるようになっていたので、「スマート」もまぜてみようかと思ったのですが、単語が一般的すぎていまいちでした。そのかわりに「Web2.0」というこれまた一斉を風靡したキーワードをまぜてみました。2006-2007年をピークに減ってきて、最近ではめっきり使われなくなりましたね。

モバイルOS

スマートフォン向けOSの検索結果。今回は地域限定なしの結果です。
smarphone-os-share.png

これはあくまでGoogleでの検索数ですので、これがそのままマーケットシェアとイコールではありません。iOSについては、iPhoneやiPadという形で検索されることも多いのでその分少ないところはあるかもしれませんね。なお、マーケットシェアという点では以下の記事にグラフがありましたが、そんなにはずれてない気はします。 一時は企業用スマートフォンといえば、blackberryでしたが、最近ではAndroid, iOSにおされてすっかり低シェアになりました。world wideでみると今や1%以下のシェアのようですが、アフリカやアジアの一部ではまだ高シェアを保っているようです。 ナイジェリアでは40%もあるんですね。強いブランド力によってステータスシンボルであること、Blackberry Messenger(BBM)がキラーとなっていること、端末の更新頻度が低いことが寄与しているらしいです。自分たちの常識と、グローバル市場を十把一絡げの統計だけみていると、見えてこない事実があるという好例ですね。

Webブラウザ

比較といえば、やっぱりこれ。Webブラウザの比較です。
web browser google trends

これまた、検索数なのでシェアではありませんが、概ねシェアと連動してそうですね。実際のシェアはwikipediaにデータがありました。 これを見て驚いたのはアフリカの国々ではOperaがブラウザシェアNo.1だということ。貧弱なネットワークでは、Opera miniの圧縮転送がかなり重宝されているのがその要因だそうです。なるほど!

opera-stats.png

検索結果だけで全てが見えるわけではないですが、Googleトレンドはいろいろ比較するにはいいツールです。あれ?ということろは、違う角度でしらべると新たな発見もありましたし。今までほとんど使ってなかったツールですが、これからちょくちょく使っていきたいと思います。
B00SMGZ1UI
【関連記事】
【関連書籍】

モジュール分割とタスク分割 - 誰のためのデザイン?

困難は分割せよ
方法序説』 - デカルト

ソフトウェアの設計上重要な二つの要素、モジュール分割とタスク分割。その目的と必要性、効果とともに、初心者が陥りやすい過度な分割による弊害について書いてみたいと思います。

モジュール分割は誰のため?

まず「モジュール分割」ですが、その目的は、ソフトウェアの意味的、機能的な単位に分割することにより、可読性や再利用性、あるいは、複数人開発での分担効率をあげようというもの。ソフトウェア設計における最も基本的な部分であり、最終的な、成果物の品質を左右する重要な設計要素ですね。

さて、モジュール分割でググると、STS分割技法、TR分割技法などの技法を紹介するページがあたります。
例えば以下あたりはまとまっていて参考になります。 私の場合、基本組み込み開発の世界にいますが、開発の現場でこれら単語を聞くことは少ない気がします。組み込みソフトの開発が大規模化してきたあたりから、組み込みでもオブジェクト指向設計が浸透しているので、最近の「オブジェクト指向ネイティブ」な世代には、クラス設計とか、デザインパターンから入った人が多いからかもしれません。そういう方には以下記事が、構造化プログラミングを経てオブジェクト指向に至る歴史がよくわかっておすすめです。

さて、前振りはここまでにして、今回の主題に入りたいと思います。それは、モジュール分割はそのソフトウェアを搭載した製品やサービスのためのものではないという点です。モジュール分割の意義は、
  • 開発者のため : ソフトウェアの可読性、分業効率の向上
  • 部品の再利用のため : 成果物の一部(又は全て)を使った派生開発
にあります。

そうはいっても、実際は、ソフトウェアの品質は、それを作る「人」に依存しますので、開発効率をあげることが、プログラムの方が品質に直結するので、上の話は極論ですが、何のためかという観点は非常に重要です。この考えに立てば、「成果物として何をつくるか」よりも、「誰が作るか、どうやって作るか」、そして、「成果物の再利用のスコープはどこまでか」が、モジュール設計を考える上で重要になるからです。

なぜこんなことを強調するのかというと、ソフトウェアのモジュール設計を見ていると、過度なモジュール分割がなされているケースが多いように思うからです。 4788514346 もちろん、ソフトウェアの部品化や階層化は、再利用性という観点で非常に重要な観点なのですが、全てのプログラムがそれらを考慮しないといけないというわけではありません。むしろ、再利用性を全く必要としない部分について、過度なモジュール分割を行って、厳密なインターフェースを定義していくことで、開発者が増えたり、必要以上のドキュメントやテストが増えることになりかねません。内部設計としてきちんとモジュール化するのはもちろん必要ですが、そこを外部公開してしまったとたん、害の方が多くなることがあるので注意が必要です。また、拡張性が全く必要ないとわかっているようなケースで、過剰なフレームワークを作ったりするのも、同じく害しかありません。

本来のスコープを超えた過剰設計は、百害あって一利なしです。

タスク分割は何のため?

もう一つのテーマであるタスク分割について。モジュール分割が静的な分割であるのに対し、こちらはプログラムの動的なふるまいを決定する上で重要な要素です。タスク分割というと、uITRONや VxWorksのようなRTOSの設計がイメージされますが、Linux等の非リアルタイムシステムにおけるプロセル分割、スレッド分割でも同じような考え方は必要です。(※ 厳密にはメモリ空間の扱いとか、リアルタイム性の保証の話とかで、違う点はありますが。)
タスク分割の動機は大きく分けると以下二点になります。
  • (1) モジュール化のための分割
  • (2) 並列性、リアルタイム処理のための分割

(1)の方は、先のモジュール分割の延長ですね。その機能毎にタスクを割り当てようというものです。タスク分割にとっては(2)の方が本質で、基本的には独立した実行コンテキストをもって、並列処理させることが主な目的です。(2)をもう少し細かくわけると、
  • 処理要求の間隔とそれに対する処理時間の吸収のため、処理タスクをわける
    (例) 入力デバイスからのイベント受付と、それをキューイングして順次処理するタスクをわける
  • 互いに独立した処理の並列実行
    (例) 複数クライアント毎に処理タスクをわける
  • リアルタイム性の高い処理の優先実行
    (例) 緊急度の高いタスクに高優先度を割り当てて、優先的に割り込み処理させる。
あたりでしょうか。これらに該当しない処理は、実行時の要求事項という観点からは特にタスクにわける必要がないので、あるとすれば、(1)モジュール化のための分割、ということになります。

確かに、機能単位にタスクを分けるのは、ソフトウェア構造をわかりやすくする上で有用なことも多いのですが、これが過剰すぎる場合があります。分割された各タスクが各々完全独立、依存関係なく並列動作できるものなら問題ないですが、これが一連の手続きの前後、あるいは、上下関係出会ったりする場合が問題です。タスク分割するということは、タスク間のやりとりは、関数コールではなく、キューなりイベントフラグなりのメッセージになっているはずですが、この時のタスク間の機能呼び出しは、同期型のものもあれば、非同期のものもあるでしょう。ここでいう同期型は、要求メッセージを投げた後、結果応答があるまで、イベント待ちで要求元タスクを待ち状態にさせるというものを指しています。これって、単なる関数コールと何が違うのでしょうか?一件、独立性が確保されて、可読性があがったように思えるのかもしれませんが、 機能呼び出しがメッセージになると、
  • ソースコードツアーや問題発生時のバックトレースが困難になる
  • コールグラフが作れないので、静的解析が困難
  • コンテクストスイッチが入ることで、処理負荷が増える
ということで、実行効率や解析性を落とすことになります。

このようなモジュールに紐付いた不必要なタスク分割は、先に書いたような過度なモジュール分割がされたシステムでよく見かけます。おそらく、モジュール分割した単位で担当者がかわっており、それぞれがつくりやすいように個々でタスク設計をしたために、不必要なタスク間イベントリレーができてしまったのではないかと思います。タスク設計については、「分けることはいいことだ」では決してありません。システム全体としての最適化という観点を意識しての設計が必要です。

過ぎたるは猶及ばざるが如し

モジュール設計にせよ、タスク設計にせよ、ただ一つの正解というものはありません。どちらにも言えることは、「何をつくるか」というだけでなく、「誰がつくるか」、「拡張性のスコープはどこまでか」を考えないといけないということ、そして、それを踏まえて、過度な分割をしすぎていないか確認すること、が大切かと思っています。

何事も、「過ぎたるは猶及ばざるが如し」ですね。
4434159372
【関連記事】
【関連書籍】

本のおすすめ

4873115655

4274065979

4822236862

4274068579

4822255131

B00SIM19YS


プロフィール

  • Author:proger
  • 組み込み関係で仕事してます

ブログ内検索