Javaおじさん初めてのGolangのinterface所感

延々とだらだらしていてたらいつか死ぬ気がしてきたので、いい加減アウトプットする。 明日続かないとしても今日書けばよいのだ。

Golangさわってみた

Javaを中心にOOPな言語をずっと触ってきて、ちょっと回帰的だがGolangSQLパーサーを描いている。

Golangは色々いわれているように、

  • package指向
  • 構文機能は手続き型レベルのしかない
  • 定番の書き方がググれば出てきてそのとおり実装するのがベストプラクティス

という、スクラッチコンポーネント作るとかどう考えても向いてねえな?な言語。 まあ異文化を痛感するのにちょうどいいだろうと思って、ちょっとリッチなSQLパーサを書いている。

Golangのintafaceに対するJavaの冗長さ

interface いいね。 Javaで例えるなら「にゃーん」と鳴くのを識別するのにオブジェクトを「猫」か「動物」か「発生源」かとか文脈によって違う名前でクラスを付けなければならなかった。 でも、実際コードに起こしてクラスを指定する際、どの文脈使うか決まっている。DIするならともかく、クラスのインスタンス化とか煩わしいことせずともサクッと関数呼び出すだけで直感的に使える。 奇跡的にも、オブジェクト指向原理主義が言うような定義の曖昧さによる述語の揺れは杞憂に過ぎず、熱心は学者先生さんは理論先行頭でっかちだとGopher君が目で訴えている。

実装がんばります

とはいえ、書いているコードがどうもJavaっぽい。 多相の表現が、どうもintafaceを構造体で実装しているだけだ。 しかもどのコードもスクラッチ気味。ググりながら、楽な書き方を覚えるしかないかな。

ちなみに、SQLパーサーが目指すものは例えば集計バッチで流れる一連のSELECT文を4つぐらい食わせて、「このSELECT文のこの項目は、このテーブルのこの項目をこの式で評価したものです。で、このテーブルの結果はまたこのSELECTで・・・」と複数再帰的に辿れるようにすること。 SQLパーサーを探していたが、なんか期待できるレベルまで分解するものがなかった。たぶんPostgreSQLとかCソースをチョチョイってやったほうが早い気がするけど、それはそれで沼っぽいしCあんまわかんないので避けた。

引き続き頑張っていこう。

【.NET】【WPF】Bindingを強制反映するやりかた

遊びでC#を触ったら、まんまと有給を潰してしまった。

毒舌に.NETのWPFのBinding

  • .NET Framework
    • Microsoftが提供している、ウィンドウアプリケーションのランタイム環境。 *ウィンドウ付きのアプリが(裏方にある膨大な概念を意識するのに比べて)いとも簡単に(小さいアプリなら)できてしまう。
  • WPF

  • Binding

    • 従来だと、テキストボックスの文字や有効/無効などのプロパティをコード上の変数とで代入したりこねたりする必要があったのを、XAMLに「{Binding プロパティ名}」って書いたら自動で関連付けてくれるようにする機能。
    • 今回一番悪口を言いたいところ

事故

やりたかったこと

  • テキストボックスのフォーカスが離れた時点で、テキストボックスの値を検証しフォーム上にエラーメッセージを出したい
public partial class ReplaceSetEntryWnd : Window

   public ReplaceSet Value { get; set; } // ビューモデル。定義は割愛

   // フォーカスを失った時に実行するイベントハンドラ
   private void Controls_LostFocus(object sender, RoutedEventArgs e)
   {
      _validateAndShowError();
   }
<!-- Valueのプロパティと連携 -->
<TextBox Name="txName" Text="{Binding Value.Name}" LostFocus="Controls_LostFocus"/>
<TextBox Name="txPattern" Text="{Binding Value.Pattern}" LostFocus="Controls_LostFocus"/>

起きたこと

  • Value.xxxに反映するのは、LostFocusイベントが終わった後。つまり、↑のコードは、テキストボックスからフォーカスが離れた時点では、編集直前のValueの状態が残ったままで _validateAndShowError() を実行してしまう。

対策

  • コントロールから、Binding用のクラスっぽいものを直接取得してコントロール → プロパティに強制送信する。
    private void UpdateSources()
    {
        txName.GetBindingExpression(TextBox.TextProperty).UpdateSource();
        txPattern.GetBindingExpression(TextBox.TextProperty).UpdateSource();
    }
  • ちなみに逆の プロパティ → コントロール強制送信はこれ。
    private void UpdateSources()
    {
        txName.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
        txPattern.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
    }
  • これがマジでイケてない。txNameとかを直接指定したコード組んで、ビューモデルとの連携を疎にする目的で導入したいのに、これができるんならじゃあと欲張ると、結局依存性を増やし記述がごっちゃになるハメに。
  • ちなみに、以下のようにマルチスレッドしながら遅延実行するコードも書いてみたが、.NETコントロールいじるコードで別スレッドからのアクセス違反になった。
new Task(() => {
   Task.Delay(20).Wait();
   _validateAndShowError();
}).Wait();
  • 下手にマルチスレッドするとこうなるの。。非同期でUIのロックを回避したいのに、結局シングルスレッドにせざるをえないってこれもうわかんねえな
  • バックグラウンドプロセス⇔UIの分業と同期をより細かい単位にするために、外スレッドからUI変更をキューイングしていい感じに更新するような仕組みかもしくはFLUXにインスパイヤされた新しいフレームワークがほしい
    • え?なに?Electorn?

2017/09/23 タイトル変えました

分析系システムの業務的なメモ②

ちょっと実務的な部分に絞って2枚目

データ的な特徴

ログデータ

アクセス数やPV数、UserAgentの解析をしたい。とすれば、ApacheとかのWebサーバーのアクセスログから拾って集めて、分析用のDBに片っ端から突っ込むことになる。

Google Analytics などの外部ツールでもこの系のアクセスログは蓄積できるが、内部で集計するためのデータソースにするには情報量の不足や取得までの仕組みの関係で厳しい。

想像のとおり、非常にデータ量が膨大であるため、どういう単位でデータを残すかが非常に悩ましい部分。しかもApacheのログなんかは、何か問題がった時の調査用にログ出力フォーマットを変えたりする。(ヘッダーサイズ出力とか) 柔軟な設計が試される部分。

保守業務で辛いところ

完全に愚痴

業務領域のデータにまつわる変更が全部分析DBに落ちてくる

インプットデータとして、全領域全システムの全テーブルの面倒を見ることになる。

例えば、業務領域の改修でとあるコード値が入力できなくなったとする。(もう使わないしいらないよね?)とすると、そのコード値がリリース時から分析に落ちてこないようになり、後日集計してから「〇〇コードの最新タイムスタンプがこの日で止まってるけどなんなの?この日以降の実績消えたの?」とユーザー問い合わせがくる。

集計処理の変更が滅茶苦茶怖い

5年も続けて保守してきた分析システムの集計はどうなっているだろうか? 一つの答えが、「300行SQLの集計が3個ぐらい連なったバッチ」のような、集計結果のチェーン味噌ダレ。

「とある属性値の選択ルールを、コード最小値から画面上で先頭のものに変えました」なんてのがめっちゃ怖い。レコード数増えたり減ったりしない??集計前後でjoin結果がめっちゃ変わらない?? ここらへんはなるべくポリシー化してできるならポリシーに従った集計を個別に実施して、レイヤ的な集計を実施していきたいが。。

現在、確認範囲を全て確認していっているが、ここらへんうまく自動化できないものかなと考えている。 自動テストしたい。

分析系システムの業務的なメモ

最近、分析系のシステムに携わっている。

色々と学ぶことがあったのでここにメモする。

分析システムの種類

分析システムをニーズから分類すると、「定型レポート」と「データの特徴量や関係性をデータマイニングするツール」に大別できるらしい。(受け売り)

定型レポート系

定型レポートは、アクセス実績とかの定型的な数字を出すためのツール。

例えば特集ページを打ったりしてイベントを実施して、キャンペーン対象のページのアクセスが普段よりこれぐらい上がりましたよー、などの数字を出したり、もっと一般的には、日常的なユニークユーザー(UU)数、コンバージョン(CV)数などを出したりして経営のコンディションを判断したり、サラリーマン的なできたよアピールにつかったりする。

知る限りでは、特定の業態にあった検索フォームを作成して、CSVかなんかにしたりグラフィカルな図に出力したりするツール。SalesforceとかWebForcusとかがパッケージとして有名かな?

データマイニングツール系

もう一つの大きい分野が、データサイエンスちっくに細かく傾向を割り出すツール。

「この商品購入するユーザーって、〇〇にも興味あったりするよね」など、レポーティングシステム化されていないが蓄積データから分析できそうなことをディメンションから切っていくのが主な使い方。

ある程度の規模に収まるんだったら「SQL叩けよ」で済みそうな気もするが、ベンダー間保守契約とか資産管理とかセキュリティとかそもそもそんな人材確保できんの?的な観点で、こういうのもツール化することが多いらしい。

用途的にSQLたたきたーい!みたいなことに近いので、下手にオレオレ製品を作るのはあまりないのかな?(調査不足) 今のところでいうと、 Tableauという製品が流行りのようだ。(今の仕事で使っているし、記事にも紹介が頭から出ていた。) (ガチ勢はSQLやらHadoopやら叩けるんだろうが、前述の通り云々)

基本的なアーキテクチャ戦略

グレーな範囲で今の現場のシステムの基本的な戦略を紹介。

多分バレたら怒られると思うけど、正直ショボいし一般的なものだと思うので大丈夫かもしれない。

分析用DBとデータ移送

データ5万件とかそういう規模だと別に気にしなくてもよいが、ある程度の規模になると、「業務用DB」と「分析用DB」でDBが物理的に分かれる。

理由は2つあって、

  • 1つは参照ロックで業務影響を与えないようにすること。分析のクエリって10分ロックかけるような重いものが普通で、分析システムにて秒でコミットガンガン飛ばそうとしているのに更新待ちになったりタイムアウトしたりと致命的なレベルで問題が発生するため。
  • 2つは分析データの時間軸確定のため。リアルタイム更新するデータを参照しちゃうと、1つめの検索と2つめの検索でちょっとデータ量や数値違って「これ何?」って上司や客先にいわれちゃう。なので、夜間に昨日までのデータだけコピーして集計!みたいなことをする。

DBを分けると、データ移送が必要になる。要するに、業務DBと分析DBで同じテーブル作ってデータをコピーする処理のこと。

データ量によって、全件移送(分析DBを一度クリアして全件コピー)、差分移送(最後に分析DBにコピーした時点から、現在までの更新分だけをコピー・過去データ更新する)の2つを選択する。

差分移送にはいくつか注意点がある。

  • 〇〇時以降のデータのみコピー!が基本的な考えになるが、検索の境界値となるタイムスタンプや連番の最小値を取ってからすぐ移送を開始してはいけない。一度トランザクションを終了し、業務システムが確実にコミットするであろう期間をあけて移送を開始する。
    • DBはコミットするまで更新後データは他のクエリ上から見えない。長引くトランザクションの影響で「2017/01/01 00:11」時点では「2017/01/01 00:10」のタイムスタンプが刻まれた処理が未コミットで移送漏れが起きるかもしれない。
    • Oracleなどトランザクションを切らないとトランザクション中に他のクエリが更新した内容が見れないこともある
  • 異常終了のリカバリをミスると、データが重複してインポートしてしまうことが考えられる。主キー重複だと辛い。
    • 更新キーを予め設定するのもありかな。

集計処理

毎日の夜とか月1とかでよく流す。以下の目的をもって作られる。

  • その日時点の業務データを集計 or 変換して日ごとに蓄積する。(次の日でレコード更新するとデータが変わってしまうため)
  • 分析クエリが複雑になったり無理のあるテーブルのjoinなどでパフォーマンス劣化が考えられるとき、あらかじめ問題になりそうなデータを集計しておく。

気を付けたいのが、集計期間を指定するときに、WHERE句などの中にCURRENT_DATEとか組み込まないで外部パラメータ化すること。

例えば、日付用のテーブルとして「集計開始タイムスタンプ = 2017/01/01 00:00:00」「集計終了タイムスタンプ = 2017/01/02 00:00:00」という値を設定してそこを参照するようにすると、 障害でその日集計できなかったとしても、上記パラメータを設定して後日再集計ができる。

【Linux】rsyncで半角英数記号(半角スペース含む)のみのファイル名のみを同期する

rsyncは、ファイル同期を行うLinuxコマンド。 主→従へ完全にファイルの権限やタイムスタンプをコピーする。 デフォルトでは全てのファイルが対象(再帰的なコピーは-rオプションが必要)だが、名前にフィルタリングルールを適応することができる。

rsync -rtv --include='[a-zA-Z0-9!-.:-@[-`{-~]' --exclude='[^ ]' src/ dest/

半角スペース入りを対象外にする場合

rsync -rtv --include='[a-zA-Z0-9!-.:-@[-`{-~]' --exclude='*' src/ dest/

-rtvについて

-rtvは割愛。

--include と --excludeについて

取込対象を指定する --include--exclude は上記のようになんちゃって正規表現が使える。

あとは*でワイルドカードで指定ができる。

適応ルールは下記のとおり。

  • 無指定の場合、全ファイルが対象
  • --include=...-exclude=... の指定順で処理していき、最初にマッチした条件のみが適応。

例:「src/java」と「src/resources」と「src/pom.xml」だけをコピー対象として、他は除外する

rsync --include="java/" --include="resources/" --include="pom.xml" --exclude=* src/ dest/

ひっかけ例1:まず『名前が「contents」であるディレクトリを対象にする』それ以外のものは『デフォルトで対象にする』(除外ルールないので結局全部対象)

rsync --include="contents/" src/ dest/

ひっかけ例2:まず『すべてのパターンを除外する』それ以外のものから『a,b,cいずれかを含むファイルのみを対象とする』(結局全部除外するパターン)

rsync --exclude="*" --include="[abc]" src/ dest/

【Linux】bashで文字として評価してしまった環境変数中のクォーテーション・ダブルクオーテーションを再度引用符として評価する

$ echo 'a' 'b'

a b

$ export CMD="echo 'a' 'b'"
$ $CMD

‘a’ ‘b’

‘は文字となってしまっている。そのため、例えば以下の文は記号含む「'want-to-exclude.txt'」に一致するファイル名のみを除外してrsyncするコマンドになる。

$ export CMD="rsync -rtv --delete --exclude='want-to-exclude.txt' src/ dest/
$ CMD >> rsync.log

クォーテーションにしたいとき

  • その1 evalコマンド
$ eval $CMD

double scoreによる脆弱性に注意。

  • その2. そもそもそんなことしない
$ echo $PARAM1 $PARAM2 $PERMANENT_PARAM

SEO対策ことはじめ

最近SEO対策に関する作業をしているが、実は全然知識がなく試しに一冊本を買った。 技術者向けの参考書ではなかったが、いくつか要旨を得られたのでメモする。

SEO対策とは?

  • Search Engine Optimization(検索エンジン最適化)。Googleなどの検索順位を上にあげるようにする施策の事全般。
  • いくつかに分けられる。以下、安易に「SEO」「書籍」で検索して引っかかったエントリーより。 manablog.org

    内部対策のスキル

    外部対策のスキル

    コピーライティングのスキル

    キーワード理解のスキル

エンジニアとして関わりそうなのは前2者。(たぶんWEBディレクターとかアフィリエイターになったら全部有用なんだろう)

  • 内部対策
    • 自サイトのコンテンツ(HTML等)にSEO対策を実施すること
  • 外部対策
    • 外部サイト、サービスにより自サイトのSEO対策を実施すること

ひとまず、買ったのは内部対策についての本。 www.amazon.co.jp

(今のところ、外部対策はどうも流行り廃れが激しく、ちょっと量を当たらないと理解できそうにない印象がある。) (情弱?うるさい。)

内部対策について教科書ひとかじり

業務妨害にならない程度に。

HTMLはW3C勧告に従え

  • 基本。非推奨の使い方は順位を下げやすくするらしい

表示速度は重要

  • 基本。
  • ただでさえ自前のJavaScriptが跳ね回っているのに、外部サービス導入しまくると遅くなるよね

コンテンツはキーワードを意識する

  • さて、これがシステム屋には難しい。なんでも、検索キーワードをコンテンツ中に意識して埋め込むとよいのだそうだ。記事ならともかくそんな面倒なことできるか。

headタグは標準的な形に

  • ちょっとダラって書いたぐらいで減点するらしい。
  • がりがり動くリソースはbundleしないとだめっすか?
  • 規模が大きいほど、そんな頻繁にリファクタもできねーしな。。しかしまあ、心構えとして覚えておこう。

URLがSEOの単位なので、複数のURLで同じものを出すのを防ぐ

  • URL1つで1つのSEO測定単位となる。同じ意味のが複数あると、SEO効果が分散する。
  • 有名なのでいえば動的URL(クエリパラメータがある)、www.host.com/ と www.host.com/index.html などで重複するなど。
  • これ、SPAのrouterとかってどうなるんだろう。最近のGoogleJavaScriptも実行するよ!っていってるから、最初にrenderした結果を見るのかな。

リンクツリーを意識する

  • リンク階層を意識する。
  • リンクの深さが○以上だとたどってくれないかも
  • ページの総数が○○以上だとたどってくれないかも