Top Banner
使い捨てコードの書き方 2012/08/25 @shiumachi
26

使い捨て python コードの書き方

Jun 18, 2015

Download

Technology

Sho Shimauchi

pyfes LT 2012.08 でしゃべったときのスライドです
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 使い捨て python コードの書き方

使い捨てコードの書き方  

2012/08/25  @shiumachi  

Page 2: 使い捨て python コードの書き方

お前誰よ?  

•  Sho  Shimauchi    (  @shiumachi  )  •  Cloudera  の問い合わせ担当  •  技術質問から人生相談まで幅広く対応  

Page 3: 使い捨て python コードの書き方

サポートに必要なもの  •  Linux  コマンド  –  sed,  awk,  grep,  find,  sort  …  –  これで対応できるなら問題なし  

•  シェルスクリプト  –  for  i  in  `ls`  と  for  i  in  `seq  N`  があればなんとかなる  

•  正規表現  –  最強  –  最強と使いやすいかどうかは別問題  

•  軽量言語  –  上記3つで簡単に対応できない場合はこれを使う  –  特に集計処理とか入ると正規表現ブン回すより簡単だし

再利用しやすい  

Page 4: 使い捨て python コードの書き方

ユースケース  

•  ほとんどがパース・集計処理  – ログ内の特定の文字をカウントする  – シーケンスIDをピックアップし、ギャップを検出、カ

ウントする  – 特定のIDを時系列で追跡し、クラスタ内での移動

経路を追う  

•  その一回だけでしか使わないことが大半なので、使い捨てのコードを書くことが多い  

Page 5: 使い捨て python コードの書き方

ゴール  

とにかく楽に使い捨てたい  できれば再利用したい  

Page 6: 使い捨て python コードの書き方

使い捨て方(1)  適当なディレクトリに適当に書く  

•  論外  •  まず再利用不可能  – 場所がわからん  – 何に使ったかわからん  

Page 7: 使い捨て python コードの書き方

使い捨て方(2)  git  で綺麗に管理する  

•  理想的だが案外面倒  •  どのコードも目的が違うので、ドキュメントの

整理・構造化も必要  •  同一名で投げ込むことができず、名前空間の

管理も必要  

Page 8: 使い捨て python コードの書き方

使い捨て方(3)  gist  に突っ込んでおく  

•  多くの人が選んでいるであろう方法  •  保存・管理の手間のコストパフォーマンスを考

えるとこれがベスト  

Page 9: 使い捨て python コードの書き方

テスト  

使い捨てコードだったらテストなんていらなくね?    

違います。楽するためにテスト必要  

Page 10: 使い捨て python コードの書き方

xUnit/TDD  の(個人的な)弊害  •  xUnit  – クラス必須みたいに見えること  – 使い捨てコードでクラス必須って考えるだけでだるく

なる(個人的に)  •  TDD  – 入門書を読むと 100%  原則を守らないといけないよう

に感じる  

Page 11: 使い捨て python コードの書き方

nose  

•  色々便利な特徴はあるが、使い捨てコードにおける大きな特徴は2つ  

•  テストクラス作成が不要  –  test_*.py  としておいて、def  test_*:  というメソッド

を書いておけば nosetests  で自動実行できる  

•  nose.tools    – eq_(a,  b)  だけでほぼ全てまかなえる  

Page 12: 使い捨て python コードの書き方

テスト=ドキュメント  

•  頭の中で設計したら、ドキュメントじゃなくテストとしてdumpしておくこと  

•  どうせパースだけなので、実際の入力データから数行ひっぱってくれば十分  

•  網羅性を追求しない  •  品質を追求しない  •  実際に動かしてこけたら、その都度こけた入

力をテストに追加  

Page 13: 使い捨て python コードの書き方
Page 14: 使い捨て python コードの書き方

エキPy  11  章より  テストのメリットは4つ  

1.   ソフトウェアのリグレッションの防止

2.   コード、の品質の向上

3.   最適で低レベルなドキュメントの提供

4.   よりすばやく、信頼性の高いコードの生産

Page 15: 使い捨て python コードの書き方

エキPy  11  章より  テストのメリットは4つ  

1.   ソフトウェアのリグレッションの防止

2.   コード、の品質の向上

3.   最適で低レベルなドキュメントの提供

4.   よりすばやく、信頼性の高いコードの生産  

使い捨てコードにおいては3,4  だけで十分

Page 16: 使い捨て python コードの書き方

テストもgistにアップロードする  

•  gistは一つのコンテンツに複数ファイルアップロード可能  

•  テストも一緒に突っ込んでおく  – テストを読めば何をするコードか大体わかる  – 別の環境(Mac  -­‐>  Linux  など)でも動くかどうかテス

ト可能  

Page 17: 使い捨て python コードの書き方

サンプルコード  

•  hYps://gist.github.com/3460244  

Page 18: 使い捨て python コードの書き方

実際の入力データ  hadoop  のネームノード(マスタ)のログ  2012-­‐06-­‐04  13:30:59,197  INFO  org.apache.hadoop.hdfs.server.namenode.NameNode:  STARTUP_MSG:    /************************************************************  STARTUP_MSG:  Starcng  NameNode  STARTUP_MSG:      host  =  sho-­‐mba.local/192.168.100.130  STARTUP_MSG:      args  =  []  STARTUP_MSG:      version  =  0.20.2-­‐cdh3u4  STARTUP_MSG:      build  =  git://ubuntu-­‐slave01/var/lib/jenkins/workspace/CDH3u4-­‐Full-­‐RC/build/cdh3/hadoop20/0.20.2-­‐cdh3u4/source  -­‐r  214dd731e3bdb687cb55988d3f47dd9e248c5690;  compiled  by  'jenkins'  on  Mon  May    7  13:01:39  PDT  2012  ************************************************************/  2012-­‐06-­‐04  13:30:59,680  INFO  org.apache.hadoop.metrics.jvm.JvmMetrics:  Inicalizing  JVM  Metrics  with  processName=NameNode,  sessionId=null  2012-­‐06-­‐04  13:30:59,683  INFO  org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics:  Inicalizing  NameNodeMeterics  using  context  object:org.apache.hadoop.metrics.spi.NullContext  2012-­‐06-­‐04  13:30:59,788  INFO  org.apache.hadoop.hdfs.ucl.GSet:  VM  type              =  64-­‐bit  2012-­‐06-­‐04  13:30:59,788  INFO  org.apache.hadoop.hdfs.ucl.GSet:  2%  max  memory  =  19.9175  MB  2012-­‐06-­‐04  13:30:59,788  INFO  org.apache.hadoop.hdfs.ucl.GSet:  capacity            =  2^21  =  2097152  entries  2012-­‐06-­‐04  13:30:59,789  INFO  org.apache.hadoop.hdfs.ucl.GSet:  recommended=2097152,  actual=2097152  2012-­‐06-­‐04  13:30:59,940  INFO  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:  fsOwner=sho  (auth:SIMPLE)  2012-­‐06-­‐04  13:30:59,940  INFO  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:  supergroup=supergroup  2012-­‐06-­‐04  13:30:59,940  INFO  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:  isPermissionEnabled=true  2012-­‐06-­‐04  13:30:59,953  INFO  org.apache.hadoop.hdfs.server.namenode.FSNamesystem:  dfs.block.invalidate.limit=1000  

Page 19: 使い捨て python コードの書き方

やりたいこと  

•  ログに出力されているログレベル(INFO,  WARN,  ERROR,  …)  を集計したい  

•  「それ awk  でできんじゃね?」とは言ってはいけない  

Page 20: 使い捨て python コードの書き方

テストコード  def test_parse():!    input = "2012-06-04 13:31:07,065 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/127.0.0.1:50010"!    input2 = "2012-06-04 13:31:05,466 WARN org.apache.hadoop.util.PluginDispatcher: Unable to load dfs.namenode.plugins plugins"!

    expected = 'INFO'!    expected2 = 'WARN’!    eq_(expected, parse(input))!    eq_(expected2, parse(input2))!

入力データをベタ貼り  

Page 21: 使い捨て python コードの書き方

サンプルコード  

def parse(line):!    arr = line.strip().split() !    log_level = arr[2]!    return log_level!  

Page 22: 使い捨て python コードの書き方

テストは通るが実際には動かない  2012-06-04 13:30:59,197 INFO org.apache.hadoop.hdfs.server.namenode.NameNode: STARTUP_MSG: "/************************************************************"Traceback (most recent call last):" File "nn_parse.py", line 23, in <module>" main(sys.stdin)" File "nn_parse.py", line 11, in main" log_level = parse(line)" File "nn_parse.py", line 5, in parse" log_level = arr[2]"IndexError: list index out of range  

Page 23: 使い捨て python コードの書き方

失敗した行をそのままテストに追加  def test_parse():!    input = "2012-06-04 13:31:07,065 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/127.0.0.1:50010"!    input2 = "2012-06-04 13:31:05,466 WARN org.apache.hadoop.util.PluginDispatcher: Unable to load dfs.namenode.plugins plugins"!

    input3 = "/************************************************************"!    expected = 'INFO'!    expected2 = 'WARN'!    expected3 = '_NULL'!    eq_(expected, parse(input))!    eq_(expected2, parse(input2))!    eq_(expected3, parse(input3))  

Page 24: 使い捨て python コードの書き方

失敗した行をそのままテストに追加  def test_parse():!    input = "2012-06-04 13:31:07,065 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/127.0.0.1:50010"!    input2 = "2012-06-04 13:31:05,466 WARN org.apache.hadoop.util.PluginDispatcher: Unable to load dfs.namenode.plugins plugins"!

    input3 = "/************************************************************"!    expected = 'INFO'!    expected2 = 'WARN'!    expected3 = '_NULL'!    eq_(expected, parse(input))!    eq_(expected2, parse(input2))!    eq_(expected3, parse(input3))  

Page 25: 使い捨て python コードの書き方

コードもIndexErrorに対応  

def parse(line):!    arr = line.strip().split()!    try: !        log_level = arr[2]!    except:!        log_level = '_NULL'!    return log_level!  

Page 26: 使い捨て python コードの書き方

おしまい