This presentation on "Getting Started with HazelCast" was made by Sandeep Kumar Pandey from Lastminute.com in Core Java / BoJUG meetup group on 24th March.
"In this session, we are going to talk about high level architecture of Hazelcast framework and we will look into the Java Collections and concepts which has been used to build the framework. We will also have a live demo on Distributed Cache using Hazelcast."
SQLite is a widely used embedded database engine, known for its simplicity and lightweight design. However, the original SQLite project does not accept contributions from third parties and does not use third-party code, which can limit its potential for innovation. This talk is an overview of SQLite architecture and an introduction to libSQL: Chiselstrike's fork of SQLite.
Piotr Sarna will show how this fork can be used in distributed settings, with automatic backups and the ability to replicate data across multiple nodes. Chiselstrike's modifications also include integration with WebAssembly, which allows users to define custom functions and procedures using Wasm, a compact and portable binary format.
You'll learn the reasons behind this fork of SQLite, and the challenges and trade-offs involved in extending the database with these new features. Piotr also presents Chiselstrike's plans for future work. This talk will be relevant to database researchers and practitioners interested in leveraging SQLite for applications that require custom functions and/or distributed support.
Kafka is becoming an ever more popular choice for users to help enable fast data and Streaming. Kafka provides a wide landscape of configuration to allow you to tweak its performance profile. Understanding the internals of Kafka is critical for picking your ideal configuration. Depending on your use case and data needs, different settings will perform very differently. Lets walk through performance essentials of Kafka. Let's talk about how your Consumer configuration, can speed up or slow down the flow of messages to Brokers. Lets talk about message keys, their implications and their impact on partition performance. Lets talk about how to figure out how many partitions and how many Brokers you should have. Let's discuss consumers and what effects their performance. How do you combine all of these choices and develop the best strategy moving forward? How do you test performance of Kafka? I will attempt a live demo with the help of Zeppelin to show in real time how to tune for performance.
One of the main strengths of serverless and AWS Lambda is that, from a developer perspective, your focus is mostly shifted toward implementing business logic. Anyway, when you are writing an handler, you still have to deal with some common technical concerns outside business logic, like input parsing and validation, output serialization, error handling, etc. Very often, all this necessary code ends up polluting the pure business logic code in your handlers, making the code harder to read and to maintain. In other contexts, like generic web frameworks (express, fastify, hapi, etc.), this problem has been solved using the middleware pattern. Middy brings the middleware pattern into AWS Lambda making it easier to focus on business logic and reuse the boilerplate code across different functions.
This presentation on "Getting Started with HazelCast" was made by Sandeep Kumar Pandey from Lastminute.com in Core Java / BoJUG meetup group on 24th March.
"In this session, we are going to talk about high level architecture of Hazelcast framework and we will look into the Java Collections and concepts which has been used to build the framework. We will also have a live demo on Distributed Cache using Hazelcast."
SQLite is a widely used embedded database engine, known for its simplicity and lightweight design. However, the original SQLite project does not accept contributions from third parties and does not use third-party code, which can limit its potential for innovation. This talk is an overview of SQLite architecture and an introduction to libSQL: Chiselstrike's fork of SQLite.
Piotr Sarna will show how this fork can be used in distributed settings, with automatic backups and the ability to replicate data across multiple nodes. Chiselstrike's modifications also include integration with WebAssembly, which allows users to define custom functions and procedures using Wasm, a compact and portable binary format.
You'll learn the reasons behind this fork of SQLite, and the challenges and trade-offs involved in extending the database with these new features. Piotr also presents Chiselstrike's plans for future work. This talk will be relevant to database researchers and practitioners interested in leveraging SQLite for applications that require custom functions and/or distributed support.
Kafka is becoming an ever more popular choice for users to help enable fast data and Streaming. Kafka provides a wide landscape of configuration to allow you to tweak its performance profile. Understanding the internals of Kafka is critical for picking your ideal configuration. Depending on your use case and data needs, different settings will perform very differently. Lets walk through performance essentials of Kafka. Let's talk about how your Consumer configuration, can speed up or slow down the flow of messages to Brokers. Lets talk about message keys, their implications and their impact on partition performance. Lets talk about how to figure out how many partitions and how many Brokers you should have. Let's discuss consumers and what effects their performance. How do you combine all of these choices and develop the best strategy moving forward? How do you test performance of Kafka? I will attempt a live demo with the help of Zeppelin to show in real time how to tune for performance.
One of the main strengths of serverless and AWS Lambda is that, from a developer perspective, your focus is mostly shifted toward implementing business logic. Anyway, when you are writing an handler, you still have to deal with some common technical concerns outside business logic, like input parsing and validation, output serialization, error handling, etc. Very often, all this necessary code ends up polluting the pure business logic code in your handlers, making the code harder to read and to maintain. In other contexts, like generic web frameworks (express, fastify, hapi, etc.), this problem has been solved using the middleware pattern. Middy brings the middleware pattern into AWS Lambda making it easier to focus on business logic and reuse the boilerplate code across different functions.
MySQL Administrator
Basic course
- MySQL 개요
- MySQL 설치 / 설정
- MySQL 아키텍처 - MySQL 스토리지 엔진
- MySQL 관리
- MySQL 백업 / 복구
- MySQL 모니터링
Advanced course
- MySQL Optimization
- MariaDB / Percona
- MySQL HA (High Availability)
- MySQL troubleshooting
네오클로바
http://neoclova.co.kr/
The talk will elaborate on how to detect and Heal your MySQL topology with MySQL Orchestrator .This talk was delivered on Mydbops database Meetup on 27-04-2019 by Anil Yadav, Lead Database Engineer with OLA and Krishna Ramanathan Database Administrator III with OLA.
Deutsche Börse’s T7: Insights into trading system dynamics | Eurex ExchangeEurex
Designed in partnership with exchange participants, Deutsche Boerse’s T7 trading architecture aims to enhance performance across the board, including reduced latency and increased throughput. It’s a new generation of technology to deliver a world of opportunity.
► Visit our website: http://www.eurexchange.com
► Twitter: http://twitter.com/eurexgroup
► LinkedIn: http://www.linkedin.com/company/eurex
Writing infinite scalability web applications with PHP and PostgreSQLGabriele Bartolini
PostgreSQL 9.2 introduced native support for the JSON data type, as well as V8/Javascript and Coffeescript procedural languages.
Learn how you can write web applications in PHP using an intelligent and horizontally sharded cluster of PostgreSQL databases, bringing you infinite scalability and parallel processing.
This talk will guide you through the development lifecycle of the application, focusing on architecture, technologies, testing and deployment.
Faster, better, stronger: The new InnoDBMariaDB plc
For MariaDB Enterprise Server 10.5, the default transactional storage engine, InnoDB, has been significantly rewritten to improve the performance of writes and backups. Next, we removed a number of parameters to reduce unnecessary complexity, not only in terms of configuration but of the code itself. And finally, we improved crash recovery thanks to better consistency checks and we reduced memory consumption and file I/O thanks to an all new log record format.
In this session, we’ll walk through all of the improvements to InnoDB, and dive deep into the implementation to explain how these improvements help everything from configuration and performance to reliability and recovery.
Since 5.7.2, MySQL implements parallel replication in the same schema, also known as LOGICAL_CLOCK (DATABASE based parallel replication is also implemented in 5.6 but this is not covered in this talk). In early 5.7 versions, parallel replication was based on group commit (like MariaDB) and 5.7.6 changed that to intervals.
Intervals are more complicated but they are also more powerful. In this talk, I will explain in detail how they work and why intervals are better than group commit. I will also cover how to optimize parallel replication in MySQL 5.7 and what improvements are coming in MySQL 8.0.
Systems Monitoring with Prometheus (Devops Ireland April 2015)Brian Brazil
Monitoring means many things to many people. This talk looks at Systems Monitoring, that is how to keep an eye on a given system and use this as part of overall management of a system. This talk will cover Why one monitors, What to monitor, How to monitor, the general design of a monitoring system and how Prometheus is a good fit for this in terms of instrumentation, consoles, alerts, general system health and sanity.
Prometheus is a next-generation monitoring system publicly announced earlier this year, developed by companies including SoundCloud, locals Boxever and Docker. Since launch there has been wide-spread interest, and many community contributions.
For more information see http://prometheus.io or http://www.boxever.com/tag/monitoring
25 Real Life Tips In Ruby on Rails DevelopmentBelighted
This is a collection of small tips and tricks related to developing web applications using the Ruby on Rails framework.
These tips are gathered from my personal experience of 4 years working with the framework, including more than 2 years of professional work at Belighted.
The talk was given in the Ruby on Rails Developer Room at Fosdem 2010 (www.fosdem.org).
MySQL Administrator
Basic course
- MySQL 개요
- MySQL 설치 / 설정
- MySQL 아키텍처 - MySQL 스토리지 엔진
- MySQL 관리
- MySQL 백업 / 복구
- MySQL 모니터링
Advanced course
- MySQL Optimization
- MariaDB / Percona
- MySQL HA (High Availability)
- MySQL troubleshooting
네오클로바
http://neoclova.co.kr/
The talk will elaborate on how to detect and Heal your MySQL topology with MySQL Orchestrator .This talk was delivered on Mydbops database Meetup on 27-04-2019 by Anil Yadav, Lead Database Engineer with OLA and Krishna Ramanathan Database Administrator III with OLA.
Deutsche Börse’s T7: Insights into trading system dynamics | Eurex ExchangeEurex
Designed in partnership with exchange participants, Deutsche Boerse’s T7 trading architecture aims to enhance performance across the board, including reduced latency and increased throughput. It’s a new generation of technology to deliver a world of opportunity.
► Visit our website: http://www.eurexchange.com
► Twitter: http://twitter.com/eurexgroup
► LinkedIn: http://www.linkedin.com/company/eurex
Writing infinite scalability web applications with PHP and PostgreSQLGabriele Bartolini
PostgreSQL 9.2 introduced native support for the JSON data type, as well as V8/Javascript and Coffeescript procedural languages.
Learn how you can write web applications in PHP using an intelligent and horizontally sharded cluster of PostgreSQL databases, bringing you infinite scalability and parallel processing.
This talk will guide you through the development lifecycle of the application, focusing on architecture, technologies, testing and deployment.
Faster, better, stronger: The new InnoDBMariaDB plc
For MariaDB Enterprise Server 10.5, the default transactional storage engine, InnoDB, has been significantly rewritten to improve the performance of writes and backups. Next, we removed a number of parameters to reduce unnecessary complexity, not only in terms of configuration but of the code itself. And finally, we improved crash recovery thanks to better consistency checks and we reduced memory consumption and file I/O thanks to an all new log record format.
In this session, we’ll walk through all of the improvements to InnoDB, and dive deep into the implementation to explain how these improvements help everything from configuration and performance to reliability and recovery.
Since 5.7.2, MySQL implements parallel replication in the same schema, also known as LOGICAL_CLOCK (DATABASE based parallel replication is also implemented in 5.6 but this is not covered in this talk). In early 5.7 versions, parallel replication was based on group commit (like MariaDB) and 5.7.6 changed that to intervals.
Intervals are more complicated but they are also more powerful. In this talk, I will explain in detail how they work and why intervals are better than group commit. I will also cover how to optimize parallel replication in MySQL 5.7 and what improvements are coming in MySQL 8.0.
Systems Monitoring with Prometheus (Devops Ireland April 2015)Brian Brazil
Monitoring means many things to many people. This talk looks at Systems Monitoring, that is how to keep an eye on a given system and use this as part of overall management of a system. This talk will cover Why one monitors, What to monitor, How to monitor, the general design of a monitoring system and how Prometheus is a good fit for this in terms of instrumentation, consoles, alerts, general system health and sanity.
Prometheus is a next-generation monitoring system publicly announced earlier this year, developed by companies including SoundCloud, locals Boxever and Docker. Since launch there has been wide-spread interest, and many community contributions.
For more information see http://prometheus.io or http://www.boxever.com/tag/monitoring
25 Real Life Tips In Ruby on Rails DevelopmentBelighted
This is a collection of small tips and tricks related to developing web applications using the Ruby on Rails framework.
These tips are gathered from my personal experience of 4 years working with the framework, including more than 2 years of professional work at Belighted.
The talk was given in the Ruby on Rails Developer Room at Fosdem 2010 (www.fosdem.org).
Want to spice up your next corporate presentation? Take it from us, Make your next presentation Out Of This World! Download this Presentation for a Tweet here: http://goo.gl/YEheL
MongoDB San Francisco 2013: Schema design presented by Jason Zucchetto, Consu...MongoDB
MongoDB’s basic unit of storage is a document. Documents can represent rich, schema-free data structures, meaning that we have several viable alternatives to the normalized, relational model. In this talk, we’ll discuss the tradeoff of various data modeling strategies in MongoDB using a library as a sample application. You will learn how to work with documents, evolve your schema, and common schema design patterns.
Large data with Scikit-learn - Boston Data Mining Meetup - Alex PerrierAlexis Perrier
A presentation of adaptive classification and regression algorithms available in scikit-learn with a Focus on Stochastic Gradient Descent and KNN. Performance examples on 2 Large datasets are presented for SGD, Multinomial Naive Bayes, Perceptron and Passive Aggressive Algorithms.
Tips for creating a Self Organizing TeamsYves Hanoulle
The presentation was delivered in
Kjiv (AgileEE)
Geneve (AgileTourGeneve),
Agilis2009 (Iceland)
Scandinavian Developer Conference 2010
Agile Tour Bordeaux 2010
Modernizations prolong the economic service life of your overhead crane. They can provide a complete transformation of your existing crane as an alternative to replacing it and give you an opportunity to add current technologies.
Essa é uma apresentação que reúne algumas iniciativas e soluções que podem ser aplicadas no Governo Brasileiro e claro, serve para outros países também, pois a grande idéia é implementar alguns pontos do Governo Eletrônico, ou como prefiro chamar: Governo Aberto.
Adaptive pre-processing for streaming dataLARCA UPC
Many supervised learning approaches that adapt to changes in data distribution over time (e.g. concept drift) have been developed. The majority of them assume that data comes already pre-processed or that pre-processing is an integral part of a learning algorithm. In real application tasks data that comes from, e.g. sensor readings, is typically noisy, contains missing values, redundant features and a large part of model training needs to be devoted to data cleaning and pre-processing. As data is evolving over time, not only learning models, but also pre-processing mechanisms need to adapt. We will discuss under what circumstances it is beneficial to handle adaptivity of pre-processing and adaptivity of the learning model separately.
4. Agenda
• Concept: What’s good code?
• Move Code from Controller to Model
• RESTful best practices
• Model best practices
• Controller best practices
• View best practices
5. Warning! you should have testing before modify!
本次演講雖沒有提及測試,
但在修改重構程式前,
應有好的測試,
以確保程式於修改後執行無誤。
12. Best Practice Lesson 1:
Move code from Controller to
Model
action code 超過15行請注意
http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model
13. 1.Move finder to named_scope
class PostsController < ApplicationController
def index
@public_posts = Post.find(:all, :conditions => { :state => 'public' },
:limit => 10,
:order => 'created_at desc')
@draft_posts = Post.find(:all, :conditions => { :state => 'draft' },
:limit => 10,
:order => 'created_at desc')
end
end
Before
14. class UsersController < ApplicationController
def index
@published_post = Post.published
@draft_post = Post.draft
end
end
class Post < ActiveRecord::Base
named_scope :published, :conditions => { :state => 'published' },
:limit => 10, :order => 'created_at desc')
named_scope :draft, :conditions => { :state => 'draft' },
:limit => 10, :order => 'created_at desc')
end
1.Move finder to named_scope
After
15. 2. Use model association
class PostsController < ApplicationController
def create
@post = Post.new(params[:post])
@post.user_id = current_user.id
@post.save
end
end
Before
16. class PostsController < ApplicationController
def create
@post = current_user.posts.build(params[:post])
@post.save
end
end
class User < ActiveRecord::Base
has_many :posts
end
2. Use model association
After
17. class PostsController < ApplicationController
def edit
@post = Post.find(params[:id)
if @post.current_user != current_user
flash[:warning] = 'Access denied'
redirect_to posts_url
end
end
end
3. Use scope access
不必要的權限檢查
Before
18. class PostsController < ApplicationController
def edit
# raise RecordNotFound exception (404 error) if not found
@post = current_user.posts.find(params[:id)
end
end
After
3. Use scope access
找不到自然會丟例外
19. 4.Add model virtual attribute
<% form_for @user do |f| %>
<%= text_filed_tag :full_name %>
<% end %>
class UsersController < ApplicationController
def create
@user = User.new(params[:user)
@user.first_name = params[:full_name].split(' ', 2).first
@user.last_name = params[:full_name].split(' ', 2).last
@user.save
end
end
Before
20. 4.Add model virtual attribute
class User < ActiveRecord::Base
def full_name
[first_name, last_name].join(' ')
end
def full_name=(name)
split = name.split(' ', 2)
self.first_name = split.first
self.last_name = split.last
end
end
example code from http://railscasts.com/episodes/16-virtual-attributes
After
21. <% form_for @user do |f| %>
<%= f.text_field :full_name %>
<% end %>
class UsersController < ApplicationController
def create
@user = User.create(params[:user)
end
end
example code from http://railscasts.com/episodes/16-virtual-attributes
After
22. 5. Use model callback
<% form_for @post do |f| %>
<%= f.text_field :content %>
<%= check_box_tag 'auto_tagging' %>
<% end %>
class PostController < ApplicationController
def create
@post = Post.new(params[:post])
if params[:auto_tagging] == '1'
@post.tags = AsiaSearch.generate_tags(@post.content)
else
@post.tags = ""
end
@post.save
end
end
Before
23. 5. Use model callback
class Post < ActiveRecord::Base
attr_accessor :auto_tagging
before_save :generate_taggings
private
def generate_taggings
return unless auto_tagging == '1'
self.tags = Asia.search(self.content)
end
end
After
24. <% form_for :note, ... do |f| %>
<%= f.text_field :content %>
<%= f.check_box :auto_tagging %>
<% end
class PostController < ApplicationController
def create
@post = Post.new(params[:post])
@post.save
end
end
After
25. 6. Replace Complex Creation
with Factory Method
class InvoiceController < ApplicationController
def create
@invoice = Invoice.new(params[:invoice])
@invoice.address = current_user.address
@invoice.phone = current_user.phone
@invoice.vip = ( @invoice.amount > 1000 )
if Time.now.day > 15
@invoice.delivery_time = Time.now + 2.month
else
@invoice.delivery_time = Time.now + 1.month
end
@invoice.save
end
end
Before
26. 6. Replace Complex Creation
with Factory Method
class Invoice < ActiveRecord::Base
def self.new_by_user(params, user)
invoice = self.new(params)
invoice.address = user.address
invoice.phone = user.phone
invoice.vip = ( invoice.amount > 1000 )
if Time.now.day > 15
invoice.delivery_time = Time.now + 2.month
else
invoice.delivery_time = Time.now + 1.month
end
end
end
After
27. class InvoiceController < ApplicationController
def create
@invoice = Invoice.new_by_user(params[:invoice], current_user)
@invoice.save
end
end
After
28. 7. Move Model Logic into the
Model
class PostController < ApplicationController
def publish
@post = Post.find(params[:id])
@post.update_attribute(:is_published, true)
@post.approved_by = current_user
if @post.create_at > Time.now - 7.days
@post.popular = 100
else
@post.popular = 0
end
redirect_to post_url(@post)
end
end
Before
29. 7. Move Model Logic into the
Model
class Post < ActiveRecord::Base
def publish
self.is_published = true
self.approved_by = current_user
if self.create_at > Time.now-7.days
self.popular = 100
else
self.popular = 0
end
end
end
After
30. class PostController < ApplicationController
def publish
@post = Post.find(params[:id])
@post.publish
redirect_to post_url(@post)
end
end
After
31. 8. model.collection_model_ids
(many-to-many)
class User < ActiveRecord::Base
has_many :user_role_relationship
has_many :roles, :through => :user_role_relationship
end
class UserRoleRelationship < ActiveRecord::Base
belongs_to :user
belongs_to :role
end
class Role < ActiveRecord::Base
end
32. <% form_for @user do |f| %>
<%= f.text_field :email %>
<% for role in Role.all %>
<%= check_box_tag 'role_id[]', role.id, @user.roles.include?(role) %>
<%= role.name %>
<% end %>
<% end %>
class User < ApplicationController
def update
@user = User.find(params[:id])
if @user.update_attributes(params[:user])
@user.roles.delete_all
(params[:role_id] || []).each { |i| @user.roles << Role.find(i) }
end
end
end
Before
33. <% form_for @user do |f| %>
<% for role in Role.all %>
<%= check_box_tag 'user[role_ids][]', role.id, @user.roles.include?(role)
<%= role.name %>
<% end %>
<%= hidden_field_tag 'user[role_ids][]', '' %>
<% end %>
class User < ApplicationController
def update
@user = User.find(params[:id])
@user.update_attributes(params[:user])
# 相當於 @user.role_ids = params[:user][:role_ids]
end
end
After
34. Before
9. Nested Model Forms (one-to-one)
class Product < ActiveRecord::Base
has_one :detail
end
class Detail < ActiveRecord::Base
belongs_to :product
end
<% form_for :product do |f| %>
<%= f.text_field :title %>
<% fields_for :detail do |detail| %>
<%= detail.text_field :manufacturer %>
<% end %>
<% end %>
35. class Product < ApplicationController
def create
@product = Product.new(params[:product])
@details = Detail.new(params[:detail])
Product.transaction do
@product.save!
@details.product = @product
@details.save!
end
end
end
example code from Agile Web Development with Rails 3rd.
Before
36. After
9. Nested Model Forms (one-to-one)
Rails 2.3 new feature
class Product < ActiveRecord::Base
has_one :detail
accepts_nested_attributes_for :detail
end
<% form_for :product do |f| %>
<%= f.text_field :title %>
<% f.fields_for :detail do |detail| %>
<%= detail.text_field :manufacturer %>
<% end %>
<% end
37. After
class Product < ApplicationController
def create
@product = Product.new(params[:product])
@product.save
end
end
38. 10. Nested Model Forms (one-to-many)
class Project < ActiveRecord::Base
has_many :tasks
accepts_nested_attributes_for :tasks
end
class Task < ActiveRecord::Base
belongs_to :project
end
<% form_for @project do |f| %>
<%= f.text_field :name %>
<% f.fields_for :tasks do |tasks_form| %>
<%= tasks_form.text_field :name %>
<% end %>
<% end %>
39. Nested Model Forms
before Rails 2.3 ?
• Ryan Bates’s series of railscasts on complex forms
• http://railscasts.com/episodes/75-complex-forms-part-3
• Recipe 13 in Advanced Rails Recipes book
41. Why RESTful?
RESTful help you to organize/name controllers, routes
and actions in standardization way
42. class EventsController < ApplicationController
def index
end
def show
end
def create
end
def update
end
def destroy
end
end
def watch_list
end
def add_favorite
end
def invite
end
def join
end
def leave
end
def feeds
end
def add_comment
end
def show_comment
end
def destroy_comment
end
def edit_comment
end
def approve_comment
end
def white_member_list
end
def black_member_list
end
def deny_user
end
def allow_user
end
def edit_managers
end
def set_user_as_manager
end
def set_user_as_member
end
Before
43. After
class EventsController < ApplicationController
def index; end
def show; end
end
class CommentsControlers < ApplicationController
def index; end
def create; end
def destroy; end
end
def FavoriteControllers < ApplicationController
def create; end
def destroy; end
end
class EventMembershipsControlers < ApplicationController
def create; end
def destroy; end
end
45. 1. Overuse route customizations
Find another resources
map.resources :posts do |post|
post.resources :comments
end
After
46. Suppose we has a event model...
class Event < ActiveRecord::Base
has_many :attendee
has_one :map
has_many :memberships
has_many :users, :through => :memberships
end
47. Can you answer how to design
your resources ?
• manage event attendees (one-to-many)
• manage event map (one-to-one)
• manage event memberships (many-to-many)
• operate event state: open or closed
• search events
• sorting events
• event admin interface
48. Learn RESTful design
my slide about restful:
http://www.slideshare.net/ihower/practical-rails2-350619
49. 2. Needless deep nesting
過度設計: Never more than one level
Before
map.resources :posts do |post|
post.resources :comments do |comment|
comment.resources :favorites
end
end
<%= link_to post_comment_favorite_path(@post, @comment, @favorite) %>
50. After
map.resources :posts do |post|
post.resources :comments
end
map.resources :comments do |comment|
comment.resources :favorites
end
<%= link_to comment_favorite_path(@comment, @favorite) %>
2. Needless deep nesting
過度設計: Never more than one level
51. 3. Not use default route
Before
map.resources :posts, :member => { :push => :post }
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
52. 3. Not use default route
After
map.resources :posts, :member => { :push => :post }
#map.connect ':controller/:action/:id'
#map.connect ':controller/:action/:id.:format'
map.connect 'special/:action/:id', :controller => 'special'
54. 1. Keep Finders on Their Own Model
class Post < ActiveRecord::Base
has_many :comments
def find_valid_comments
self.comment.find(:all, :conditions => { :is_spam => false },
:limit => 10)
end
end
class Comment < ActiveRecord::Base
belongs_to :post
end
class CommentsController < ApplicationController
def index
@comments = @post.find_valid_comments
end
end
Before
55. 1. Keep Finders on Their Own Model
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
named_scope :only_valid, :conditions => { :is_spam => false }
named_scope :limit, lambda { |size| { :limit => size } }
end
class CommentsController < ApplicationController
def index
@comments = @post.comments.only_valid.limit(10)
end
end
After
56. 2. Love named_scope
class PostController < ApplicationController
def search
conditions = { :title => "%#{params[:title]}%" } if params[:title]
conditions.merge!{ :content => "%#{params[:content]}%" } if params[:content]
case params[:order]
when "title" : order = "title desc"
when "created_at" : order = "created_at"
end
if params[:is_published]
conditions.merge!{ :is_published => true }
end
@posts = Post.find(:all, :conditions => conditions, :order => order,
:limit => params[:limit])
end
end
Before
example code from Rails Antipatterns book
57. 2. Love named_scope
After
class Post < ActiveRecord::Base
named_scope :matching, lambda { |column, value|
return {} if value.blank?
{ :conditions => ["#{column} like ?", "%#{value}%"] }
}
named_scope :order, lambda { |order|
{ :order => case order
when "title" : "title desc"
when "created_at" : "created_at"
end }
}
end
58. After
class PostController < ApplicationController
def search
@posts = Post.matching(:title, params[:title])
.matching(:content, params[:content])
.order(params[:order])
end
end
59. 3. the Law of Demeter
class Invoice < ActiveRecord::Base
belongs_to :user
end
<%= @invoice.user.name %>
<%= @invoice.user.address %>
<%= @invoice.user.cellphone %>
Before
60. 3. the Law of Demeter
class Invoice < ActiveRecord::Base
belongs_to :user
delegate :name, :address, :cellphone, :to => :user,
:prefix => true
end
<%= @invoice.user_name %>
<%= @invoice.user_address %>
<%= @invoice.user_cellphone %>
After
61. 4. DRY: Metaprogramming
class Post < ActiveRecord::Base
validate_inclusion_of :status, :in => ['draft', 'published', 'spam']
def self.all_draft
find(:all, :conditions => { :status => 'draft' }
end
def self.all_published
find(:all, :conditions => { :status => 'published' }
end
def self.all_spam
find(:all, :conditions => { :status => 'spam' }
end
def draft?
self.stats == 'draft'
end
def published?
self.stats == 'published'
end
def spam?
self.stats == 'spam'
end
end
Before
62. 4. DRY: Metaprogramming
class Post < ActiveRecord::Base
STATUSES = ['draft', 'published', 'spam']
validate_inclusion_of :status, :in => STATUSES
class << self
STATUSES.each do |status_name|
define_method "all_#{status}" do
find(:all, :conditions => { :status => status_name }
end
end
end
STATUSES.each do |status_name|
define_method "#{status_name}?" do
self.status == status_name
end
end
end
After
64. 5. Extract into Module
class User < ActiveRecord::Base
validates_presence_of :cellphone
before_save :parse_cellphone
def parse_cellphone
# do something
end
end
Before
65. # /lib/has_cellphone.rb
module HasCellphone
def self.included(base)
base.validates_presence_of :cellphone
base.before_save :parse_cellphone
base.send(:include,InstanceMethods)
base.send(:extend, ClassMethods)
end
module InstanceMethods
def parse_cellphone
# do something
end
end
module ClassMethods
end
end
After
66. class User < ActiveRecord::Base
include HasCellphone
end
After
67. 6. Extract to composed class
Before
# == Schema Information
# address_city :string(255)
# address_street :string(255)
class Customer < ActiveRecord::Base
def adddress_close_to?(other_customer)
address_city == other_customer.address_city
end
def address_equal(other_customer)
address_street == other_customer.address_street &&
address_city == other_customer.address_city
end
end
68. After
6. Extract to composed class
(value object)
class Customer < ActiveRecord::Base
composed_of :address, :mapping => [ %w(address_street street),
%w(address_city city) ]
end
class Address
attr_reader :street, :city
def initialize(street, city)
@street, @city = street, city
end
def close_to?(other_address)
city == other_address.city
end
def ==(other_address)
city == other_address.city && street == other_address.street
end
end
example code from Agile Web Development with Rails 3rd.
69. 7. Use Observer
class Project < ActiveRecord::Base
after_create :send_create_notifications
private
def send_create_notifications
self.members.each do |member|
ProjectNotifier.deliver_notification(self, member)
end
end
end
Before
70. class Project < ActiveRecord::Base
# nothing here
end
# app/observers/project_notification_observer.rb
class ProjectNotificationObserver < ActiveRecord::Observer
observe Project
def after_create(project)
project.members.each do |member|
ProjectMailer.deliver_notice(project, member)
end
end
end
7. Use Observer
After
72. 1. Isolating Seed Data
Before
class CreateRoles < ActiveRecord::Migration
def self.up
create_table "roles", :force => true do |t|
t.string :name
end
["admin", "author", "editor","account"].each do |name|
Role.create!(:name => name)
end
end
def self.down
drop_table "roles"
end
end
73. 1. Isolating Seed Data
After
# /db/seeds.rb (Rails 2.3.4)
["admin", "author", "editor","account"].each do |name|
Role.create!(:name => name)
end
rake db:seed
74. After
# /lib/tasks/dev.rake (before Rails 2.3.4)
namespace :dev do
desc "Setup seed data"
task :setup => :environment do
["admin", "author", "editor","account"].each do |name|
Role.create!(:name => name)
end
end
end
rake dev:setup
75. 2. Always add DB index
class CreateComments < ActiveRecord::Migration
def self.up
create_table "comments", :force => true do |t|
t.string :content
t.integer :post_id
t.integer :user_id
end
end
def self.down
drop_table "comments"
end
end
Before
76. 2. Always add DB index
class CreateComments < ActiveRecord::Migration
def self.up
create_table "comments", :force => true do |t|
t.string :content
t.integer :post_id
t.integer :user_id
end
add_index :comments, :post_id
add_index :comments, :user_id
end
def self.down
drop_table "comments"
end
end
After
78. 1. Use before_filter
class PostController < ApplicationController
def show
@post = current_user.posts.find(params[:id]
end
def edit
@post = current_user.posts.find(params[:id]
end
def update
@post = current_user.posts.find(params[:id]
@post.update_attributes(params[:post])
end
def destroy
@post = current_user.posts.find(params[:id]
@post.destroy
end
end
Before
79. 1. Use before_filter
class PostController < ApplicationController
before_filter :find_post, :only => [:show, :edit, :update, :destroy]
def update
@post.update_attributes(params[:post])
end
def destroy
@post.destroy
end
protected
def find_post
@post = current_user.posts.find(params[:id])
end
end
After
80. 2. DRY Controller
class PostController < ApplicationController
def index
@posts = Post.all
end
def show
@post = Post.find(params[:id)
end
def new
@post = Post.new
end
def create
@post.create(params[:post]
redirect_to post_path(@post)
end
end
Before
def edit
@post = Post.find(params[:id)
end
def update
@post = Post.find(params[:id)
@post.update_attributes(params[:post])
redirect_to post_path(@post)
end
def destroy
@post = Post.find(params[:id)
@post.destroy
redirect_to posts_path
end
82. After
2. DRY Controller
class PostController < InheritedResources::Base
# if you need customize redirect url
def create
create! do |success, failure|
seccess.html { redirect_to post_url(@post) }
failure.html { redirect_to root_url }
end
end
end
83. • You lose intent and readability
• Deviating from standards makes it harder
to work with other programmers
• Upgrading rails
DRY Controller Debate!!
小心走火入魔
from http://www.binarylogic.com/2009/10/06/discontinuing-resourcelogic/
86. 1. Move code into controller
<% @posts = Post.find(:all) %>
<% @posts.each do |post| %>
<%=h post.title %>
<%=h post.content %>
<% end %>
Before
class PostsController < ApplicationController
def index
@posts = Post.find(:all)
end
end
After
87. 2. Move code into model
<% if current_user && (current_user == @post.user ||
@post.editors.include?(current_user) %>
<%= link_to 'Edit this post', edit_post_url(@post) %>
<% end %>
<% if @post.editable_by?(current_user) %>
<%= link_to 'Edit this post', edit_post_url(@post) %>
<% end %>
class Post < ActiveRecord::Base
def ediable_by?(user)
user && ( user == self.user || self.editors.include?(user)
end
end
Before
After
88. 3. Move code into helper
<%= select_tag :state, options_for_select( [[t(:draft),"draft" ],
[t(:published),"published"]],
params[:default_state] ) %>
Before
After
<%= select_tag :state, options_for_post_state(params[:default_state]) %>
# /app/helpers/posts_helper.rb
def options_for_post_state(default_state)
options_for_select( [[t(:draft),"draft" ],[t(:published),"published"]],
default_state )
end
89. 4. Replace instance variable
with local variable
<%= render :partial => "sidebar" %>
<%= render :partial => "sidebar", :locals => { :post => @post } %>
Before
After
class Post < ApplicationController
def show
@post = Post.find(params[:id)
end
end
90. 5. Use Form Builder
<% form_for @post do |f| %>
<p>
<%= f.label :title, t("post.title") %> <br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :content %> <br>
<%= f.text_area :content, :size => '80x20' %>
</p>
<p>
<%= f.submit t("submit") %>
</p>
<% end %>
Before
91. 5. Use Form Builder
After
<% my_form_for @post do |f| %>
<%= f.text_field :title, :label => t("post.title") %>
<%= f.text_area :content, :size => '80x20',
:label => t("post.content") %>
<%= f.submit t("submit") %>
<% end %>
92. module ApplicationHelper
def my_form_for(*args, &block)
options = args.extract_options!.merge(:builder =>
LabeledFormBuilder)
form_for(*(args + [options]), &block)
end
end
class MyFormBuilder < ActionView::Helpers::FormBuilder
%w[text_field text_area].each do |method_name|
define_method(method_name) do |field_name, *args|
@template.content_tag(:p, field_label(field_name, *args) +
"<br />" + field_error(field_name) + super)
end
end
def submit(*args)
@template.content_tag(:p, super)
end
end
After
93. 6. Organize Helper files
# app/helpers/user_posts_helper.rb
# app/helpers/author_posts_helper.rb
# app/helpers/editor_posts_helper.rb
# app/helpers/admin_posts_helper.rb
class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
end
# app/helpers/posts_helper.rb
Before
After
94. 7. Learn Rails Helpers
• Learn content_for and yield
• Learn how to pass block parameter in helper
• my slide about helper: http://www.slideshare.net/ihower/building-web-interface-on-rails
• Read Rails helpers source code
• /actionpack-x.y.z/action_view/helpers/*