Your SlideShare is downloading. ×
使い捨て python コードの書き方
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

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

4,899
views

Published on

pyfes LT 2012.08 でしゃべったときのスライドです

pyfes LT 2012.08 でしゃべったときのスライドです

Published in: Technology

0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
4,899
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
13
Comments
0
Likes
4
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 使い捨てコードの書き方   2012/08/25   @shiumachi  
  • 2. お前誰よ?  •  Sho  Shimauchi    (  @shiumachi  )  •  Cloudera  の問い合わせ担当  •  技術質問から人生相談まで幅広く対応  
  • 3. サポートに必要なもの  •  Linux  コマンド   –  sed,  awk,  grep,  find,  sort  …   –  これで対応できるなら問題なし  •  シェルスクリプト   –  for  i  in  `ls`  と  for  i  in  `seq  N`  があればなんとかなる  •  正規表現   –  最強   –  最強と使いやすいかどうかは別問題  •  軽量言語   –  上記3つで簡単に対応できない場合はこれを使う   –  特に集計処理とか入ると正規表現ブン回すより簡単だし 再利用しやすい  
  • 4. ユースケース  •  ほとんどがパース・集計処理   –  ログ内の特定の文字をカウントする   –  シーケンスIDをピックアップし、ギャップを検出、カ ウントする   –  特定のIDを時系列で追跡し、クラスタ内での移動 経路を追う  •  その一回だけでしか使わないことが大半なの で、使い捨てのコードを書くことが多い  
  • 5. ゴール  とにかく楽に使い捨てたい   できれば再利用したい  
  • 6. 使い捨て方(1)   適当なディレクトリに適当に書く  •  論外  •  まず再利用不可能   –  場所がわからん   –  何に使ったかわからん  
  • 7. 使い捨て方(2)   git  で綺麗に管理する  •  理想的だが案外面倒  •  どのコードも目的が違うので、ドキュメントの 整理・構造化も必要  •  同一名で投げ込むことができず、名前空間の 管理も必要  
  • 8. 使い捨て方(3)  gist  に突っ込んでおく  •  多くの人が選んでいるであろう方法  •  保存・管理の手間のコストパフォーマンスを考 えるとこれがベスト  
  • 9. テスト  使い捨てコードだったらテストなんていらなくね?    違います。楽するためにテスト必要  
  • 10. xUnit/TDD  の(個人的な)弊害  •  xUnit   –  クラス必須みたいに見えること   –  使い捨てコードでクラス必須って考えるだけでだるく なる(個人的に)  •  TDD   –  入門書を読むと 100%  原則を守らないといけないよう に感じる  
  • 11. nose  •  色々便利な特徴はあるが、使い捨てコードに おける大きな特徴は2つ  •  テストクラス作成が不要   –  test_*.py  としておいて、def  test_*:  というメソッド を書いておけば nosetests  で自動実行できる  •  nose.tools     –  eq_(a,  b)  だけでほぼ全てまかなえる  
  • 12. テスト=ドキュメント  •  頭の中で設計したら、ドキュメントじゃなくテス トとしてdumpしておくこと  •  どうせパースだけなので、実際の入力データ から数行ひっぱってくれば十分  •  網羅性を追求しない  •  品質を追求しない  •  実際に動かしてこけたら、その都度こけた入 力をテストに追加  
  • 13. エキPy  11  章より   テストのメリットは4つ  1.  ソフトウェアのリグレッションの防止 2.  コード、の品質の向上 3.  最適で低レベルなドキュメントの提供 4.  よりすばやく、信頼性の高いコードの生産
  • 14. エキPy  11  章より   テストのメリットは4つ  1.  ソフトウェアのリグレッションの防止 2.  コード、の品質の向上 3.  最適で低レベルなドキュメントの提供 4.  よりすばやく、信頼性の高いコードの生産  使い捨てコードにおいては3,4  だけで十分
  • 15. テストもgistにアップロードする  •  gistは一つのコンテンツに複数ファイルアップ ロード可能  •  テストも一緒に突っ込んでおく   –  テストを読めば何をするコードか大体わかる   –  別の環境(Mac  -­‐>  Linux  など)でも動くかどうかテス ト可能  
  • 16. サンプルコード  •  hYps://gist.github.com/3460244  
  • 17. 実際の入力データ   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  
  • 18. やりたいこと  •  ログに出力されているログレベル(INFO,   WARN,  ERROR,  …)  を集計したい  •  「それ awk  でできんじゃね?」とは言ってはい けない  
  • 19. テストコード  def test_parse():!    input = "2012-06-04 13:31:07,065 INFOorg.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/127.0.0.1:50010"!    input2 = "2012-06-04 13:31:05,466 WARNorg.apache.hadoop.util.PluginDispatcher: Unable to loaddfs.namenode.plugins plugins"!    expected = INFO!    expected2 = WARN’!    eq_(expected, parse(input))!    eq_(expected2, parse(input2))!入力データをベタ貼り  
  • 20. サンプルコード  def parse(line):!    arr = line.strip().split() !    log_level = arr[2]!    return log_level!  
  • 21. テストは通るが実際には動かない  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  
  • 22. 失敗した行をそのままテストに追加  def test_parse():!    input = "2012-06-04 13:31:07,065 INFOorg.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/127.0.0.1:50010"!    input2 = "2012-06-04 13:31:05,466 WARNorg.apache.hadoop.util.PluginDispatcher: Unable to loaddfs.namenode.plugins plugins"!    input3 = "/************************************************************"!    expected = INFO!    expected2 = WARN!    expected3 = _NULL!    eq_(expected, parse(input))!    eq_(expected2, parse(input2))!    eq_(expected3, parse(input3))  
  • 23. 失敗した行をそのままテストに追加  def test_parse():!    input = "2012-06-04 13:31:07,065 INFOorg.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/127.0.0.1:50010"!    input2 = "2012-06-04 13:31:05,466 WARNorg.apache.hadoop.util.PluginDispatcher: Unable to loaddfs.namenode.plugins plugins"!    input3 = "/************************************************************"!    expected = INFO!    expected2 = WARN!    expected3 = _NULL!    eq_(expected, parse(input))!    eq_(expected2, parse(input2))!    eq_(expected3, parse(input3))  
  • 24. コードもIndexErrorに対応  def parse(line):!    arr = line.strip().split()!    try: !        log_level = arr[2]!    except:!        log_level = _NULL!    return log_level!  
  • 25. おしまい