この間、海外に住んでる友達と久しぶりに会ってその一味と映画を見に行きました。ただ共通の友達が英語ネイティブが多く、ふとした話に全然ついていけずに悔しい思いをしました。あとLINEでの略語表現が全然わからん。
(雑談なので文脈がわかりづらく、例えば「ICカード乗車券付きのクレジットカードを使ってるんだけど、設定の問題でオートチャージ機能が使えてなかったんだ」みたいな話だったそうなので特に難しかった気はするんですが)
なので今年は英語を毎日勉強しようと思います(完)。
続きを読むData Platform Meetup Vol.2に参加したので、その参加レポートを書きます。
実は既に @ikedaosushi さんが記事を書いているのでそちらを読んでください。よくまとまった記事なので「私は書く必要ないんじゃないか」とも思ってしまったのですが、私が感じたこと + 質疑応答の内容を追記していきます。
個人的に三行でまとめると↓のような感想でした。
- 社内コミュニティやドキュメントなどの啓蒙活動でスキルやナレッジの伝達を各社努力している
- Redshiftはマジで大変そう(自分はBig Queryにかなり救われている)
- 縦持ち、横持ちはコンテキストによって必要性が変わるので使い分ける(snowflake schema)
私も似た感想でした。
特にpixivの長部さんの発表でよく触れられていました。「分析・データ加工の代行を期待されてしまう」というのは自分たちの会社でも起こっていて、「(悪く言うと)便利屋からどう脱却して専門性を発揮していくか」という話はデータ組織に普遍的なテーマなのかもしれません。
そのためにナレッジ共有の場や教材作成を作ったそうなのですが、個人的にはそこのモチベーションや目標の置き方をどうやっているのか気になりました。実際そういう質問もあり、それには「元々問題意識を持った人の寄り合いが部署になった経緯があるのでメンバーのモチベーションが高く、問題になってない」というような趣旨の回答されていました。
CookpadのInuzukaさんの発表。RedShiftの同時接続数などの制約をどう回避して便利に使うかという発表もありました。技術的な話としては面白かったのですが、自分たちのチームでGCPのBigQueryを利用しているところではあまり問題になったことがない箇所(課金額の見積もりちゃんとしてないと困る程度)ではありました(一応同時実行数などの制限もあるのですが、自分たちのユースケースだと全然余裕です)。
ただ自分たちのチームでは、DWHがBigQueryで、(機械学習も含めた)システムの開発や運用をAWSで行っているので、データやモデルをどうやり取りするかといった別の問題はあるように思います。実際にはそこまで考えて技術選定する必要があると思います。
できるだけメモを取ったつもりですが、抜け漏れや要旨が間違っている点があればご指摘ください🙏
Q. 学習教材はエンジニア向け以外にもあるか?
A. ビジネス職向けのSQLのチュートリアルもある。もちろんエンジニア向けも用意している。
Q. BigQueryは従量課金なので、自由に使わせるのは課金額の点で怖くないか?
A. 裁量にまかせているものの、監視はしている。特に前日のクエリの課金額順の通知はしていて、問題のあるクエリを書いた人に指摘はしている。
Q. 教材のモチベーション維持ってどうやってる?直接ビジネスに影響しない箇所なので、KPIの設定など苦戦するのでは?
A. 元々、組織の発端が問題意識を持った人の寄り合い状態から始まっていて、メンバーのモチベーションも高いので大きな問題になってない。
Q. 民主化のためにLOOKERを利用しているとのことだが、LOOKMLは誰が定義してる?
A. リポジトリは統一していて、そこに各部署のエンジニアがコミットしてる。また規約の定義やコードレビューはデータ駆動推進室が行っている。
Q. 事業部制を取っている会社でデータを集約してるのすごい。ガバナンスを効かせるのって工夫したのでは?
A.\ データの追加はこちら側がやってる。プロダクトのDBのコピーと、個人情報のマスキングして入れるのが大変だった。ただ要望を定型フォーマットで出してくれるように工夫してる。
Q. (クックパッドのコミッタの方から)dmemoの要望ってありますか?
A. Redshiftに直接繋いでいて、ActiveRecordのinteger型がRedshiftと互換性がないので独自に潰す必要があった点が大変だった。
Q. 具体的に「こういうことをしたら喜ばれた」って話はありますか?
A. データの使い方といってもいろいろあって、分析・機械学習などの応用がいくらの価値を創出したか出しづらいんですけど…。ただ、インプレッションログの表示順位を工夫した(受注確率が高い顧客を上にもってくるなど)。
時間が取れなかったため質疑応答の時間なし。他の発表も短い時間だったので、もう少し一つ一つの発表をじっくり聞きたかった気がします…。
Q. クライアントサイドの時刻ってイベント発生時刻と送信時刻のどちらか?クライアント側で時刻が狂ってる場合はどう扱ってる?
A. 時刻は基本的にイベント発生時刻で、タイムゾーンはすべてUTC。イベント発生時にオフラインだった場合のデータが後でバルク送信された場合に過去のデータが変わることはあるので、3日さかのぼってデータマートを作ってる。
Q. テーブルの設計で、ディメンションとファクトを分けるのが習慣としてある人とない人がいて、「なぜこう持たないの?」って衝突があるはず。そこは乗り越えた?
A. レビューや「規約に乗るとこういうメリットがある」と説明することで乗り越えている。また規約に則って作ると便利になるように補助するツールを実装している。
Q. 「指標」部分はどうしてるのか?(ここの質問の意図がメモできませんでした…)
A. 具体的な指標の話は(業務の話になるので)外で話しづらいが、再利用しやすい形にはしてる。指標のカタログを作っているイメージ。
↑最近こちらに悩んでいます。感覚的には積極的にmix-in(と委譲)を使ったほうがモデリングしやすいのですが、もしかすると継承のほうが便利なケースがあるかも分かりません。それで以下の2つを調べていました。
ところが、前者はきちんと追おうとすると型理論の話が分からないし、後者もGitHubのissueなどにあるんじゃないかと思ったのですが見つけられていません。一応それっぽい議論はあったのですが、こちらも「継承がないとGUIプログラミングきつくない?」「いやいやそんなことないよ」程度の内容に見えて、もう少し具体的じゃないときつい感じします。
一旦諦めて他のことやろうと思います。
最近、Pythonでコードを書いていて、薄々「継承で使うのはmix-inクラスだけでいいんじゃないか」と感じています。ここでいうmix-inクラスというのは、以下の記事で述べられているような「インスタンス変数を含まず、メソッドのみを持つ多重継承用のクラス」のことです。
あるいは、「インスタンス変数を含むクラスを継承するのは1つだけ」とするルールを自らに課す方法もある。その場合、追加で継承できるのは「メソッドのみを含んだクラス」となる。そうすることで、インスタンス変数の共有によって生じる問題を回避できるようになる。
これに反論のある方は少ないと思います。また、「親クラスでインスタンス変数を定義する処理(ほぼ __init__
だと思います)を共通化する必要性がなければ、通常の親クラスを使わずにmix-inクラスだけで表現できるのではないか?」さらに「 __init__
などの処理を共通化して得られるコストメリットは少ないのではないか?」と感じています。その理由は以下の通りです。
この話を友人にしたところ、「多重継承したい場合に『インスタンス変数を含むクラスを継承するのは1つだけ』とするルールが必要なのは異論ない」「ただ、 __init__
の処理を共通化するメリットがある場面もあるのではないか?(極端な例だが子クラスが100個あって全部で同じ初期化処理がある場合)」というような意見を貰いました。
というわけで、「mix-inだけでいいんじゃないか説」の完全な証明にはならないものの、「子クラスが100個あって全部で同じ初期化処理がある場合」に、「インスタンス変数を含まない多重継承用のクラス」しかない言語ではどう解決しているのか(それとも __init__
を共通化するより楽な設計はあるのか)を調べてみようと思います。
と思ったのですが、サクッと調べた程度では全然結論が出なかったので一旦諦めました。
class Dog include Runnable end class Cat include Runnable end module Rannable def run end end Dog.new.run
こちらも「Dogは走れるものの一種(Dog is a Runable)」と解釈できるんじゃないかと思ってしまいます。
TODO:: Rustのtraitが導入されるまでの議論を追う
TODO:: 「inheritance is not subtyping」問題
Pythonはドキュメントが整備された言語ですが、専門的な用語も多く「結局この機能をどう使えば良いんだ」と思ってしまうことがあります。
この間同僚と abc
モジュールの話になり、「結局何のメリットがあんのや」という話になりました。私は abc.ABC
を使うことが多いのですが、改めて考えるとメリットを説明できなかったので調べてみます。
このモジュールは Python に PEP 3119 で概要が示された 抽象基底クラス (ABC) を定義する基盤を提供します。なぜこれが Python に付け加えられたかについてはその PEP を参照してください。 (ABC に基づいた数の型階層を扱った PEP 3141 と numbers モジュールも参照してください。)
そして抽象基底クラスの説明はこちらです。これはきつい😅
(抽象基底クラス) 抽象基底クラスは duck-typing を補完するもので、 hasattr() などの別のテクニックでは不恰好であったり微妙に誤る (例えば magic methods の場合) 場合にインタフェースを定義する方法を提供します。ABC は仮想 (virtual) サブクラスを導入します。これは親クラスから継承しませんが、それでも isinstance() や issubclass() に認識されます; abc モジュールのドキュメントを参照してください。Python には、多くの組み込み ABC が同梱されています。その対象は、(collections.abc モジュールで) データ構造、(numbers モジュールで) 数、(io モジュールで) ストリーム、(importlib.abc モジュールで) インポートファインダ及びローダーです。 abc モジュールを利用して独自の ABC を作成できます。
上の例にあるPEP3119を追ってみます。翻訳を引用していきますが、必要に応じて原文も当たります。
一方で、古典的 OOP 理論家による覗き込み批判の一つは形式化の欠如であり、 何が覗き込まれるかについての場当たり的な性質です。 Python のような言語、つまりオブジェクトのほとんど全ての部分を外部コードが覗き込み、直接アクセスできるような言語においては、オブジェクトが特定のプロトコルに適合しているかどうかを調べるいくつもの異なった方法があります。 たとえば「このオブジェクトは変更可能なシーケンスのコンテナですか?」 という問には、’list’ が基底クラスにあるかどうか探す、’__getitem__’ という名のメソッドを探すといった解答方法が思いつきます。 しかし間違えてはいけないのは、これらのテストが当たり前に見えるとしても、 どちらも正しくないということです。 一方は間違って否定することがあり、もう一方は間違って肯定することがあります。
「呼び出し」は「オブジェクトにメソッド呼び出しを通して働きかけること」で「覗き込み」は「外部のコード(オブジェクトのメソッド以外のもの)が、型やオブジェクトのプロパティを調べたり、その情報に基づいてそのオブジェクトをどのように扱うか決める」ことだと説明されています。原文には'invocation' and 'inspection'とあります。
一方で、古典的 OOP 理論家による覗き込み批判の一つは形式化の欠如であり、 何が覗き込まれるかについての場当たり的な性質です。 Python のような言語、つまりオブジェクトのほとんど全ての部分を外部コードが覗き込み、直接アクセスできるような言語においては、オブジェクトが特定のプロトコルに適合しているかどうかを調べるいくつもの異なった方法があります。 たとえば「このオブジェクトは変更可能なシーケンスのコンテナですか?」 という問には、’list’ が基底クラスにあるかどうか探す、’__getitem__’ という名のメソッドを探すといった解答方法が思いつきます。 しかし間違えてはいけないのは、これらのテストが当たり前に見えるとしても、 どちらも正しくないということです。 一方は間違って否定することがあり、もう一方は間違って肯定することがあります。
abc導入の目的は、「そのオブジェクトに特定のメソッドが存在することを保証すること」のようです。
この PEP はこうしたテストの組織化戦略、抽象基底クラス (Abstract Base Class, ABC) として知られるものを提案します。 抽象基底クラスは単純な Python クラスでオブジェクトの継承ツリーに加えられ、 外部からの覗き込みに対してそのオブジェクトの特定の特性を伝えるものです。 テスト自体は isinstance() を使って行われ、 特定の ABC の存在はそれの定めるテストを通ったことを意味します。
それに加えて、ABC はある型の特徴的な振る舞いを確立する最小メソッド集合を定義します。 ABC に基づいてオブジェクトを判別するコードは、 それらのメソッドの存在を信じることができます。 これらのメソッドのそれぞれは一般化された抽象的な意味の定義を ABC の文書中に見つけることができます。 これら標準的な意味定義は強制力はありませんが、 従うことが強く推奨されます。
仕様は概要で列挙されたカテゴリーの順番に従います:
3つめは collections.abcの話です。
具体的には「isinstance/issubclassでの判定を正確にすること」「 abstractmethod
などのデコレータで、子クラスにメソッドの実装を強制できること」が具体的な機能として挙げられています。
ここは私自身まだ混乱してます。この間の記事でも調べた構造的部分型も、「メソッドが存在することを保証する」ことが目的なのでどういう関連なのか気になっています。typingモジュールでは構造的部分型もサポートされています。
www.slideshare.net
こちらでも「そのオブジェクトに特定のメソッドが存在することを保証すること」は保証できるはずなので、どう使い分けるのか調べてみたいです。
今日は @classmethod
と @staticmethod
の使い分け方が話題になりました。私はなんとなく「コンストラクタが複数ある場合は @classmethod
を使う」ようにしています。ただ、他の使い道も自分が知らないだけであるんじゃないかと思い、少し調べてみました。
こちらの記事にある通りです。
よく使われる例としては、そのクラスを作るメソッドを書くことです。 以下の例ではクラス Item と、Itemの情報をあるAPIから取得して返す retrieve_from_api というクラスメソッドを実装しています。
class Item: def __init__(self, id, name): self.id = id self.name = name @classmethod def retrieve_from_api(cls, id): res = requests.get(f"https://api.example.com/items/{id}") data = res.json() return cls(id, data["name"])
これはFactory Methodパターンと呼ばれるデザインパターンです。
やや古い記事なので、Python2系の xrange
が使われていて少し懐かしいですね。
class Shape: collection = set() def __init__(self,x, y): self.x = x self.y = y def update(self): self.x += 1 self.y += 1 @classmethod def add_new_shape(cls, (x, y)): shape = Shape(x, y) Shape.collection.add(shape) @classmethod def update_all(cls): for shape in Shape.collection: shape.update() def main(): for p in xrange(10): Shape.add_new_shape((p, p)) q = 0 while q < 60: Shape.update_all() q += 1 if __name__ == "__main__": main()
また、 @staticmethod
は「関数をまとめたクラスオブジェクト(モジュール)を作る場合」に使っています。ただ、Pythonだとファイル単位でモジュールができるので、個人的にはあまり必要性を感じたことがないです。
あとはインスタンス変数やインスタンスメソッドにアクセスしないときにも @staticmethod
を使いますが、個人的な経験では、結局後で他のメソッドを呼ぶことになって self
を書き足すことが多かったのであまりメリットは感じません。
こちらの例は鮮やかですが、なかなかこういう機会はなさそう。