注:我已经 fork 了一份,以后就在那里更新了貌似作者还在不停的添加新的内容
这是 git 上的一篇关于 rails 开发实践的指南,我尝试翻译了一下,但是还是有些地方不是很明白,希望借助大家的力量纠正其中的错误,并探讨其中的合理性。
翻译水平有限,还请大家多多指教!
Apply the YAGNI and KISS principles to all of the following.
Implementation specifics
一般架构
产品及 API 功能
实现细节
UTF-8 encoding
采用空格作为缩进而不是制表符
采用 2 个空格作为一个缩进
采用 Unix 行尾结束符
采用 UTF-8 编码格式
All classes, modules, and methods must be documented using YARD formatted comments.
使用 YARD 为所有的类、模块和方法格式化注释。
These guidelines are based on Sandy Metz's programming "rules" which she introduced on Ruby Rogues.
以下的准则均基于 Sandy Metz 在 Ruby Rogues 上所介绍的编程“规则”.
The rules are purposefully aggressive and are designed to give you pause so your app won't run amok. It's expected that you will break them for pragmatic reasons... alot. See the note on YAGNI and KISS.
这些规则是故意设计成具有强制性,就是为了通过适度的“中止”,以使你的应用不会失去控制。 希望你是在基于很多务实的原因才会打破它。参考YAGNI and KISS
Never directly reference another class/module from within a class. Such references should be passed in.
类中的代码不超过 100 行
方法中的代码不超过 5 行
方法最多采用 4 个参数
控制器应该只实例化一个对象
视图应该只获取一个实例变量
永远不要直接在类中直接引用其他的类或者模块 而应该传递这些引用
find_by_...
Be thoughtful about using callbacks. They can lead to unwanted coupling.
永远不要使用动态的查找方法。例如:find_by_...
仔细斟酌对回调的使用。他们会导致不必要的耦合。
All models should be organized using the following format.
所有的模型请采用以下的格式组织代码
class MyModel < ActiveRecord::Base
# extends ...................................................................
# includes ..................................................................
# security (i.e. attr_accessible) ...........................................
# relationships .............................................................
# validations ...............................................................
# callbacks .................................................................
# scopes ....................................................................
# additional config .........................................................
# class methods .............................................................
# public instance methods ...................................................
# protected instance methods ................................................
# private instance methods ..................................................
end
NOTE: The comments listed above should exist in the file to serve as a visual reminder of the format.
注意:以上所列出的注释需明确的编写在文件中,用于在视觉上给出必要的格式提示。
Its generally a good idea to isolate different concerns into separate modules. We recommend using Concerns as outlined in this blog post.
针对不同的关注点进行模块分离通常是一个好主意。我们推荐从这篇博客中的介绍开始。
|-project
|-app
|-assets
|-controllers
|-helpers
|-mailers
|-models
|-concerns <-----
|-views
full_name
method that concats first_name
and last_name
status
method that needs to look at several other models to calculate.Complex multi-step operations should be implemented as a process. See below.
限于单个模型的 CRUD 操作应该在模型内实现。比如,采用full_name
方法合并first_name
和last_name
。
超出当前模型的 CRUD 操作应该作为一个关注点。比如,status
方法就需要依据许多其他的模型进行计算。
简单的非 CRUD 操作应该作为一个关注点实现。
非常重要! 关注点应该独立而且自包含。他们不应该假设接收者在运行时是如何组成的。一个关注去调用其他关注中的方法是不被接受的。然而,调用定义在预定接收者中的方法是允许的。
复杂的 多步 操作应该作为过程实现。见下文
A process is defined as a multi-step operation which includes any of the following.
过程是对“多步”操作的定义,它包含以下内容。
Sending emails, exporting files, etc...
需要执行复杂的、任务导向的事务。
对外部服务的调用。
执行任何操作系统级别的交互。
发送邮件、导出文件,等等...。
In an attempt to better manage processes, we loosely follow some domain driven development (DDD) principles.
Namely, we have added a processes
directory under app
to hold our process implementations.
为了更好的管理流程,我们自由(loosely)遵循一些领域驱动模型开发原则。即,我们在app
目录下添加processes
文件夹,用于支持(hold)我们对过程的实现。
|-project
|-app
|-assets
|-controllers
|-helpers
|-mailers
|-models
|-processes <-----
|-views
We recommend using a tool like Hero to help model these processes.
我们推荐使用类似Hero的工具来帮助我们对这些过程建模。
Important Do not use model or controller callbacks to invoke a process. Instead, invoke processes directly from the controller.
重要 不要通过模型或者控制器回调去调用过程。而应该取而代之的直接在控制器中调用。
We use the Yell gem for logging. Here is an example configuration.
我们使用 Yell gem 进行日志记录。下面是一份配置范例。
# example/config/application.rb
module Example
class Application < Rails::Application
log_levels = [:debug, :info, :warn, :error, :fatal]
# %m : The message to be logged
# %d : The ISO8601 Timestamp
# %L : The log level, e.g INFO, WARN
# %l : The log level (short), e.g. I, W
# %p : The PID of the process from where the log event occured
# %t : The Thread ID from where the log event occured
# %h : The hostname of the machine from where the log event occured
# %f : The filename from where the log event occured
# %n : The line number of the file from where the log event occured
# %F : The filename with path from where the log event occured
# %M : The method where the log event occured
log_format = Yell.format( "[%d] [%L] [%h][%p][%t] [%F:%n:%M] %m")
config.logger = Yell.new do |logger|
logger.adapter STDOUT, :level => log_levels, :format => log_format
end
end
end
Use an initializer
to load extensions & monkey patches.
仔细斟酌是否需要使用猴子补丁,首先应该考虑是否有能够替代的解决方案。
使用初始化程序(initializer
)载入扩展和猴子补丁。
All extensions & monkey patches should live under an extensions
directory in lib
.
所有的扩展和猴子补丁都应该存放在lib
目录下的extensions
文件夹中。
|-project
|-app
|-config
|-db
|-lib
|-extensions <-----
Use modules to extend objects or add monkey patches. This provides some introspection assistance when you need to track down weirdness.
采用模块的方式扩展对象或添加猴子补丁。这能够在你跟踪异常的时候为你提供一些自省的帮助
Here's an example:
下面是一个例子:
module CowboyString
def downcase
self.upcase
end
end
::String.send(:include, CowboyString)
String.ancestors # => [String, CowboyString, Enumerable, Comparable, Object, Kernel]
***********2013-01-29 更新****************
Gem dependencies should be hardened before deploying the application to production. This will ensure application stability.
应用所依赖的 Gem 版本在发布到生产环境的时候,必须固定。这样可以保证应用的可靠性。
We recommend using exact or tilde version specifiers. Here's an example.
我们推荐使用精确或波浪线版本的说明符。下面是一个例子。
# Gemfile
gem 'rails', '3.2.11' # GOOD: exact specifier
gem 'pg', '~>0.9' # GOOD: tilde specifier
gem 'nokogiri' # BAD: no version specifier
Bundler's Gemfile.lock solves the same problem; however, our team discovered that inadvertent bundle update
s were causing dependency problems.
It's much better to be explicit in the Gemfile and guarantee application stability.
*Bundler 所使用的 Gemfile.lock 文件也可以用来解决这个问题;但是,我们的小组发现如果不小心使用了bundle update
同样会导致依赖性问题。因此,为了保证应用的可靠性,在 Gemfile 中进行精确的定义还是最好的办法。
This will cause your project to slowy drift away from the bleeding edge. A strategy should be employed to ensure your project doesn't drift too far from contemporary gem versions. For example, we are vigilant about security patch upgrades and we periodically upgrade gems on a regular basis.
但是这可能会导致你的项目逐渐偏离前沿版本。 你必须采取一定的策略才能保证你不会偏得太远。 比如我们对安全补丁的升级保持关注,并周期性的进行常规升级。
Exciting things are happening in the world of client side frameworks.
客户端框架的世界不断的有惊喜出现,它们包括:
Be thoughtful about the decision to use a client side framework. Ask yourself if the complexity of maintaining 2 independent full stacks is the right decision. Often times there are better and simpler solutions.
谨慎选择你所要使用的客户端框架。 请从自身考虑,维护 2 套独立完整的栈(stacks)是否是一个正确的决定。特别是通常都会有更好且更简单的解决方案。
Read the following articles before deciding. In the end, you should be able to articulate why your decision is the right one.
在做出决定前,请先阅读以下的文章。最后,你应该能够说清楚为什么你的决定是正确的。
In either case be mindful of "layout thrashing" as described here.
在以上的任何一种情况下都要留心“布局抖动”,可以参考这篇文章.中的描述。