• Save
技術トレンディセミナー フレームワークとしてのTrac
Upcoming SlideShare
Loading in...5
×
 

技術トレンディセミナー フレームワークとしてのTrac

on

  • 5,212 views

 

Statistics

Views

Total Views
5,212
Views on SlideShare
5,081
Embed Views
131

Actions

Likes
2
Downloads
0
Comments
0

4 Embeds 131

http://www.smg.co.jp 97
http://www.slideshare.net 29
http://webtest.smg.co.jp 4
http://static.slidesharecdn.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

技術トレンディセミナー フレームワークとしてのTrac 技術トレンディセミナー フレームワークとしてのTrac Presentation Transcript

  • 技術 Trendy Seminar フレームワークとしてのTrac 2009/03/03 エスエムジー株式会社 鈴木貴典 ※資料中に記載の会社名および製品名は、各社商標または登録商標です。 ※本資料の無断転載・複写を禁じます。 Copyright © SMG Co., Ltd. All rights reserved.
  • Hot Topic 1. 分散バージョン管理Git/Mercurial/Bazaar徹底比較(@IT) http://www.atmarkit.co.jp/fjava/rensai4/devtool03/devtool03_1.html 最近は、分散バージョン管理が流行り!? Gitは、はてなで標準として利用しているらしい – 「株式会社はてなの開発戦略」(デブサミ2009 ) Mercurialは、本も出ている – 「入門Mercurial Linux/Windows対応」(秀和システム) 2. Shibuya.trac 2009新年会の動画アップ(Shibuya.trac) http://gihyo.jp/news/report/2009/02/0301 gihyo.jpで公開 2 Copyright © SMG Co., Ltd. All rights reserved.
  • 目次 1. Tracとは? 2. Tracのプラグイン フレームワークとして見たTrac 3. アークテクチャの詳細 4. まとめ 5. 3 Copyright © SMG Co., Ltd. All rights reserved.
  • 1. Tracとは? 1. Tracの概要 ITS(Issue Tracking System)のひとつ – Subversionの流行から、利用者が増えている Pythonで開発されている – Google App EngineがPythonをサポートしているので、今後、利用者 がさらに増える可能性あり 2. Tracの特徴 Subversionと簡単に連携できる – リビジョン⇔チケットの相互関連付け プラグインが豊富 Wikiも提供 Eclipse、VisualStudioなどからも連携可能 4 Copyright © SMG Co., Ltd. All rights reserved.
  • 2. Tracのプラグイン 1. Trac Hacksで公開 250個を超えるプラグインが公開 Trac Hacks自体もTracで構築 誰でも自由にプラグインを登録できる 2. アーキテクチャ コンポーネントベースのアーキテクチャ コンポーネントの1つ、もしくは複数から、 1つのプラグインとなる 詳しいチュートリアルはないが、他のプ ラグインを参考にすれば、初めてでも開 参考: 発できてしまう簡単さ Trac Component Architecture 5 Copyright © SMG Co., Ltd. All rights reserved.
  • 3. フレームワークとして見たTrac 1. 優れたプラグインアーキテクチャ 基本は、必要な機能に合わせて、インタフェースを実装すれば、 Tracが必要なときに探し出して呼び出す IoC(Inversion Of Control=制御の反転)の見本となる 2. ビューの分離 HTMLテンプレートを利用 テンプレートエンジンであるGenshiで実現 3. 簡単なコンフィギュレーションの管理 設定ファイル(trac.ini)の読み込み/書き込みも、メソッドを1つ 呼び出すだけ カスタマイズ可能な設定を、ユーザに公開するのも簡単 6 Copyright © SMG Co., Ltd. All rights reserved.
  • 4. アークテクチャの詳細 インタフェースの実装 1. 2. HTMLテンプレート 3. Web API 4. Ticket API 5. DB API 6. Permission API 設定ファイルの読み込み/書き込み 7. カスタマイズ可能な設定の公開 8. 今回は、アーキテクチャの有効性が分かりやすい一部のAPIについて、呼び出さ れる側(プラグイン)から、フレームワークを見てみることにします。 Pythonでの実装ですが、フレームワークとしての考え方は、言語に依らず、参考 になります。 7 Copyright © SMG Co., Ltd. All rights reserved.
  • 【4. アーキテクチャの詳細】 インタフェースの実装 全てのクラスは、 class TicketTemplateModule(Component): Componetntクラスを継承 implements(ITemplateProvider, IRequestFilter, ITemplateStreamFilter) →Tracのプラグインとして認識 # ITemplateProvider method def get_htdocs_dirs(self): from pkg_resources import resource_filename return [('ticketext', resource_filename(__name__, 'htdocs'))] ITemplateProvider 静的なコンテンツを取得する # ITemplateProvider method 場合に利用する。 def get_templates_dirs(self): from pkg_resources import resource_filename return [resource_filename(__name__, 'templates')] # IRequestFilter method IRequestFilter def post_process_request(self, req, template, data, content_type): HTTPリクエストを処理する if template == 'ticket.html': add_script(req, 'ticketext/ticketext.js') 場合に利用する。 add_stylesheet(req, 'ticketext/ticketext.css') return (template, data, content_type) ITemplateStreamFilter # ITemplateStreamFilter method def filter_stream(self, req, method, filename, stream, data): ページにHTMLを埋め込み if filename != 'ticket.html': たい場合に利用する。 return stream インタフェースさえ実装すれば、良い構成になっている。 それだけ、メソッド粒度、引数などが洗練されているということ。 8 Copyright © SMG Co., Ltd. All rights reserved.
  • 【4. アーキテクチャの詳細】 HTMLテンプレート <legend>チケットテンプレートの変更</legend> <div class=quot;fieldquot;> <label for=quot;typequot;>チケットの分類:</label><br /> <select id=quot;typequot; name=quot;typequot;> def _process_read(self, req, page_param): <div py:for=quot;type in template.typesquot;> <option py:if=quot;type.selected” ticket_types = [{ value=quot;${type.name}quot; 'name' : type.name, selected=quot;selectedquot;> 'value' : type.value, ${type.name} 'selected' : (type.name == ticket_type) </option> } for type in ticket.Type.select(self.env)] <option py:if=quot;not type.selectedquot; value=quot;${type.name}quot;> page_param['types'] = ticket_types ${type.name} </option> </div> </select> レスポンスパラメータに、 サーバで指定された値を、 </div> HTML内で指定。 画面に表示される値を格納。 Beanのようなオブジェクトも、 利用できる。 ifやforなどの処理は、 テンプレートエンジンが解決 ロジックとビューの分離は一般的。 HTMLテンプレートにより、簡単にレイアウトが確認できる。 9 Copyright © SMG Co., Ltd. All rights reserved.
  • 【4. アーキテクチャの詳細】 Web API(画面の表示を処理する) # INavigationContributor methods def get_active_navigation_item(self, req): これだけ実装すれば、 return 'importer' タブメニューとして def get_navigation_items(self, req): リンクが表示される。 if not req.perm.has_permission('IMPORT_EXECUTE'): return yield ('mainnav', 'importer', html.a('インポート', href=req.href.importer())) # IRequestFilter method def post_process_request(self, req, template, data, content_type): 表示画面に、JavaScriptを if template == 'ticket.html': 追加。 add_script(req, 'ticketext/ticketext.js') add_stylesheet(req, 'ticketext/ticketext.css') return (template, data, content_type) 表示画面に、CSSを追加。 決まったレイアウトになったり、決まった処理をするものは、簡単に利用できるように、 ユーティリティメソッドなどを用意しておく。 10 Copyright © SMG Co., Ltd. All rights reserved.
  • 【4. アーキテクチャの詳細】 Ticket API(チケットの変更に対する処理をする) # ITicketChangeListener method def ticket_created(self, ticket): self.action = 'created' self.ticket = ticket def ticket_changed(self, ticket, comment, author, old_values): self.action = 'changed' self.ticket = ticket self.comment = comment self.author = author 追加、変更、削除の処理が発生した際に、 self.old_values = old_values Listenerが呼び出される。 何らかの処理を実行する前後などで、 def ticket_deleted(self, ticket): 処理をフックしたい場合に利用する。 self.action = 'deleted' self.ticket = ticket そのシステムで中心的な処理の前後には、フックできるような仕組みを提供しておくと、 拡張が簡単になる。 11 Copyright © SMG Co., Ltd. All rights reserved.
  • 【4. アーキテクチャの詳細】 DB API(DBアクセスの処理をする) DBアクセスが必要な処理であるが、 良く使われる処理であるため、 ユーティリティとして、値をメソッド1つで 取得できるようにしている。 def _delete_ticket(self, id): major, minor = self._get_trac_version() if major > 0 or minor >= 10: ticket = Ticket(self.env,id) SQLを簡単に発行。 ticket.delete() →commitメソッドで、コミット完了。 else: db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute(quot;DELETE FROM ticket WHERE id=%squot;, (id,)) cursor.execute(quot;DELETE FROM ticket_change WHERE ticket=%squot;, (id,)) cursor.execute(quot;DELETE FROM attachment WHERE type='ticket' and id=%squot;, (id,)) cursor.execute(quot;DELETE FROM ticket_custom WHERE ticket=%squot;, (id,)) db.commit() DBアクセスが必要な処理も、頻繁に呼び出されるような処理は、フレームワークとして、 APIを提供する。 ただし、トランザクションの設計は注意しておく必要がある。 12 Copyright © SMG Co., Ltd. All rights reserved.
  • 【4. アーキテクチャの詳細】 Permission API(権限に関する処理をする) プラグインに実装されて # IPermissionRequestor methods いる権限を取得し、 def get_permission_actions(self): yield 'TICKET_BATCH_MODIFY' 一覧へ表示する。 ユーザ毎に権限を設定 # ITemplateStreamFilter methods 権限を判定して、処理を分岐 def filter_stream(self, req, method, filename, stream, formdata): させる。 if filename == 'query.html' and ( req.perm.has_permission('TICKET_ADMIN') or req.perm.has_permission('TICKET_BATCH_MODIFY') ): return stream | Transformer('//div[@id=quot;helpquot;]').before(self._generate_form(req, formdata) ) return stream プラグイン毎に、権限を自由に設定することができる。 権限を一元管理する方法も考えられるが、プラグインアーキテクチャの場合は、 プラグインに権限処理の責務を持たせる。 13 Copyright © SMG Co., Ltd. All rights reserved.
  • 【4. アーキテクチャの詳細】 設定ファイルの読み込み/書き込み self.run_server = self.config.getbool('ldap', 'autocomplete_run_server', False) self.width = self.config.get('ldap', 'autocomplete_width', '400') self.minChars = self.config.get('ldap', 'autocomplete_minchars', '1') 設定ファイルから、 self.delay = self.config.get('ldap', 'autocomplete_delay', '400') 設定値を読み込み。 デフォルト値を 「カテゴリ」+「項目」 # trac.ini 指定することも可能。 [ldap] で定義 autocomplete_run_server = True autocomplete_width = 500 template_key = type_name.encode('utf-8') + '.template' template = template.replace('¥r¥n', '¥n'); template = template.replace('¥n', self._LB); self.config.set('ticketext', template_key, template) enablefields_key = type_name.encode('utf-8') + '.enablefields' 設定値をセットし、 self.config.set('ticketext', enablefields_key, enablefields) saveメソッドを実行する だけ self.config.save() フレームワークだけでなく、システムには設定ファイルはつきもの。 頻繁に利用される処理であるため、ユーティリティで簡単にアクセスできるようにする。 14 Copyright © SMG Co., Ltd. All rights reserved.
  • 【4. アーキテクチャの詳細】 カスタマイズ可能な設定の公開 「カテゴリ」 「項目」 class DiscussionApi(Component): 「デフォルト値」 「説明文」 default_display = Option('discussion', 'default_display', 'tree', を定義 'Default display mode of topic message list.') forum_sort = Option('discussion', 'forum_sort', 'id', →Javaでいうところの、 'Column by which will be sorted forum lists.' + クラス変数みたいなもの 'Possible values are: id group name subject ' + 'time moderators description topics replies lasttopic lastreply') クラスファイルを、 フレームワークが 自動で読み取り、 オプションとして表示。 設定値は、設定ファイ ルに保存される。 ユーザがカスタマイズすることを可能にする設定値を定義している。 フレームワークが自動で読み取り、保存可能にしているため、プラグイン側では 定義のみで済んでしまう。 15 Copyright © SMG Co., Ltd. All rights reserved.
  • 5. まとめ 1. プラグインアーキテクチャとして、Tracのアーキテクチャ は参考になる。 2. IoC(Inversion Of Control=制御の反転)は、フレーム ワークとしての基本である。 3. ロジックとビューは分離する。 4. 頻繁に利用される処理は、ユーティリティなどを提供し、 簡単に利用できるようにする。 5. 権限、設定ファイルの管理など、共通機能に関しては、 全体に影響するため、特に早めにフレームワーク化し ておく。 16 Copyright © SMG Co., Ltd. All rights reserved.