卡巴斯基悲催:美国全力封杀全球第一杀软

虽然在AV-TEST最新杀软评测中,卡巴斯基得到了满分成为第一,但美国依然不允许它出现在政府采购名录中,而这个封杀的事态还在加剧。

据外媒CNET报道称,除了美国的政府机构外,FBI也在悄悄暗示那些私营机构停止使用卡巴斯基,情况十分严重。

报道中提到,能源行业以及使用工业控制系统等企业,都在被警告的名单中,而按照美国的意思,就是先让该国企业尽可能快的从其系统中移除卡巴斯基。

虽然卡巴严正否认自己进行涉嫌收集不法信息的“间谍”活动,甚至可以交出软件源代码,但目前的情况是,这丝毫没有打动当局控制者,而消息中还透露,俄罗斯也正努力移除美国科技公司如微软的操作系统。

对于微软来说,这件事他们暗地里非常开心,因为这样可以让更多的用户来换用Windows Defender,尤其是随着创意者更新全面升级的“新安全中心”。

来自:驱动之家

转自:https://www.oschina.net/news/87919/kaspersky-banned-by-american-government

React 定义组件的参数-生命周期

定义组件的参数-生命周期
创建期:getDefaultProps
创建期:getInitialState
创建期:componentWillMount
创建期:componentDidMount
存在期:componentWillReceiveProps
存在期:shouldComponentUpdate
存在期:componentWillUpdate
存在期:componentDidUpdate
销毁&清理期:componentWillUnmount

定义组件的参数-生命周期
生命周期相关参数,是React定义组件时提供的一系列处理函数(钓子函数),这些函数会在组件生命周期的某个阶段调用。

创建期:getDefaultProps

object getDefaultProps()

创建期:getInitialState

object getInitialState()
在组件挂载前(即:创建期)调用一次,其返回值将做为this.state的初始值。

getInitialState()方法会组件类创建的时候调用一次,其返回值会被缓存下来。该方法用于设置props属性的默认值,但仅对于非必须属性。如果父组件没有指定props中的某个值,此返回对象中的相应属性将会合并到this.props。

getInitialState()方法会在组件实例创建前调用,这时还不能使用this.props属性,且其返回对象是在所有实例间共享的。

创建期:componentWillMount

componentWillMount()
componentWillMount()服务器端和客户端都只调用一次,在初始化渲染执行之前被调用。如果在这个方法内调用setState()方法,render()方法将会收到更新后的state,也就是说这是我做在组件渲染前最后一个修改state的机会。

创建期:componentDidMount

componentDidMount()
componentDidMount()会在组件初始化(渲染完成)后立即调用一次,我们一般在这个方法中使用this.getDOMNode()方法访问原始DOM。

存在期:componentWillReceiveProps

componentWillReceiveProps(object nextProps)

componentWillReceiveProps在将要接受新的props时被调用
componentWillReceiveProps()方法会在组件生命周期的存在期调用,当组件感知到props属性改变,会调用此方法。render()方法将会在其后调用,这时我们可以通过this.setState()来阻止组件的再次渲染。

存在期:shouldComponentUpdate

boolean shouldComponentUpdate(object nextProps, object nextState)
shouldComponentUpdate()方法发生在组件生命周期的存在器,在组件收到新的props或state。在这个方法中,我们可以访问组件的props和state属性,通过这两个属性可以确认组件是否需要更新,如果不需要更新,则返回false,则其后的方法将不会在执行。如:

shouldComponentUpdate: function(nextProps, nextState) {
return nextProps.id !== this.props.id;
}

存在期:componentWillUpdate

componentWillUpdate(object nextProps, object nextState)
componentWillUpdate()会在收到新的props或state后调用,类似componentWillMount()。

存在期:componentDidUpdate

componentDidUpdate(object prevProps, object prevState)
componentDidUpdate()会在组件重新渲染后立即被调用,当我们需要在组件重新渲染后操作DOM则需要使用这个方法。

销毁&清理期:componentWillUnmount

componentWillUnmount()
componentWillUnmount()是组件销毁&清理期唯一调用的方法,它会在组件从DOM中移除时被调用,这时我们可以清理一些状态或清理在componentDidMount中创建的DOM元素。

据说只有程序员才能看懂的时钟 [转]

据说只有程序员才能看懂的时钟,你看明白了吗?

最近发现一个关于程序员的“数学钟”,也就是非常流行的下面这幅图:

以前,只知道其中十一个点钟的分析;对于3点钟,一直没有思路。于是发了一条朋友圈,求助大神解释其中的3点钟。在刘梓溪、贾顾森、黎鸣等大神的指导下,明白了其中是怎么回事。所以这里介绍下这十二个点,应该如何解释。个人观点,仅供参考。

12点

不用说了,1728的立方根。

1点

可能很多人不大知道,这是勒让德常数:
勒让德常数

其中的π(x)表示不大于x的素数的个数,可以用近似。

这个值经过勒让德、高斯等一批数学大佬的努力,最后被数学家Charles Jean证明为1。

2点

无穷递缩等比级数的求和,首项为1,公比为1/2,所以它的和为

3点

在刘梓溪、贾顾森、黎鸣等大神的帮助下,终于知道了。

广泛用于XML、HTML中。&#后面接十进制字符,&#x后面接十六进制字符。相当于转义序列吧。

其中十六进制33,等于十进制51,即’3’。

4点

同余问题(Modular Multiplicative Inverse)


5点

ϕ表示黄金分割比,

黄金分割比在斐波那契数列的通项公式中出现。

不过这个地方,我没搞懂,不知道这是不是这幅图作者的笔误?个人认为应该是 而不是

6点

不用说了,阶乘。

7点

表示6.999999999…其中9的头上一横,表示循环节是9。

那么,6.9999….为什么等于7呢?恩,还是无穷递缩等比级数的视角来考虑,就老少皆宜了。

6.9999…= 6 + 0.9 + 0.09 + 0.009 + 0.0009 + …

后面的那个,

0.9 + 0.09 + 0.009 + 0.0009 + …

首项为0.9,公比为0.1,收敛于1。

因此6.9999… = 7

8点

代表1000(二进制),因为只有第一个是亮的,其他是暗的。(亮为1,暗为0,bitmap的感觉。可能是盲文),因此为8。

9点

四进制。21(四进制) = 2 * 4 + 1 = 9。

10点

组合数,5! /(2! * 3!) = 10

11点

十六进制,A是10,B是11,C是12。注意,注意,这里是0x0B,不是0x08。哈哈。

点评:知识点有点重复,比如进制就有好几个。

来源:程序师

原标题:程序员的时钟

原文:https://www.oschina.net/news/87686/programmer-clock

巴科斯-诺尔范式 (BNF) 基本语法[转]

语法规范:BNF与ABNF

BNF 

巴科斯范式(BNF: Backus-Naur Form 的缩写)是由 John Backus 和 Peter Naur 首先引入的用来描述计算机语言语法的符号集。现在,几乎每一位新编程语言书籍的作者都使用巴科斯范式来定义编程语言的语法规则。

在BNF中,双引号中的字(“word”)代表着这些字符本身。而double_quote用来代表双引号。

在双引号外的字(有可能有下划线)代表着语法部分。

< > : 内包含的为必选项。
[ ] : 内包含的为可选项。
{ } : 内包含的为可重复0至无数次的项。
|  : 表示在其左右两边任选一项,相当于”OR”的意思。
::= : 是“被定义为”的意思
“…” : 术语符号
[…] : 选项,最多出现一次
{…} : 重复项,任意次数,包括 0 次
(…) : 分组
|   : 并列选项,只能选一个
斜体字: 参数,在其它地方有解释

下面是是用BNF来定义的Java语言中的For语句的实例:

FOR_STATEMENT ::= 
      "for" "(" ( variable_declaration | 
  ( expression ";" ) | ";" ) 
      [ expression ] ";" 
      [ expression ] ";" 
      ")" statement

 

理解巴科斯-诺尔范式 (BNF) 语法

语法结构使用BNF范式形式给出,先做一个简单了解。

在双引号中的字(“word”)代表着这些字符本身。而double_quote用来代表双引号。
在双引号外的字(有可能有下划线)代表着语法部分。
尖括号( < > )内包含的为必选项。
方括号( [ ] )内包含的为可选项。
大括号( { } )内包含的为可重复0至无数次的项。
竖线( | )表示在其左右两边任选一项,相当于”OR”的意思。
::= 是“被定义为”的意思。

BNF 语法使用下表中显示的表示法。

约定/符号 含义
::= 等效
| OR
X+ 一个或多个 X。
[X] X 可选。可选的分隔符由 [] 表示。
任何粗体文本 字符串。
任何斜体 文本 如何构造字符串。

正如前表中所指出的,注册器脚本使用字符串。这些值是必须出现在脚本中的实际的文本。下表描述 ATL 注册器脚本中使用的字符串。

字符串 操作
ForceRemove 完全移除下一项(如果存在),然后重新创建它。
NoRemove 在“注销”期间不移除下一项。
val 指定 <Key Name> 实际上是一个命名值。
Delete 在“注册”期间删除下一项。
s 指定下一个值为字符串 (REG_SZ)。
d 指定下一个值为 DWORD (REG_DWORD)。
m 指定下一个值为多字符串 (REG_MULTI_SZ)。
b 指定下一个值为二进制值 (REG_BINARY)。

  ABNF

RFC2234 定义了扩展的巴科斯范式(ABNF)。近年来在Internet的定义中 ABNF 被广泛使用。ABNF 做了更多的改进。扩充巴科斯-瑙尔范式(ABNF)基于了巴科斯-瑙尔范式(BNF),但由它自己的语法和推导规则构成。这种元语言的发起原则是描述作为通信协议(双向规范)的语言的形式系统。它建档于 RFC 4234 中通常充当 IETF 通信协议的定义语言。

ABNF 规定是一组推导规则,写为:

规则 = 定义 ; 注释 CR LF

这里的规则是大小写敏感的非终止符,定义由定义这个规则的符号序列,一个文档注释组成,并结束于回车换行。

规则名字是大小写不敏感的: <rulename><Rulename><RULENAME> 和 <rUlENamE> 都提及同一个规则。规则名字由开始于一个字母的字母、数字和连字符组成。不要求用尖括号(“<”, “>”) (如 BNF 那样)包围规则名字。但是它们可以用来界定规则名字,比如在冗文中识别出规则名字的时候。ABNF 使用 7-位 ASCII 编码,在 8-位域中把高位置零。

终结符由一个或多个数值字符指定。数值字符可以指定为跟随着基数(b = 二进制, d = 十进制, x = 十六进制)的一个百分号“%”,随后是这个数值,或数值的串联(用“.” 来指示)。例如回车可以指定为十进制的 %d13 或十六进制的 %x0D。回车换行可以指定为 %d13.10

文字正文通过使用包围在引号(")中字符串来指定。这些字符串是大小写不敏感的,使用的字符集是 US-ASCII。所以字符串“abc”将匹配“abc”, “Abc”, “aBc”, “abC”, “ABc”, “AbC”, “aBC” 和 “ABC”。对于大小写敏感匹配,必须定义明确的字符: 要匹配 “aBc” 定义将是 %d97 %d66 %d99

操作符

空白被用来分隔定义的各个元素: 要使空格被识别为分割符则必须明确的包含它。

串联

规则1 规则2

规则可以通过列出一序列的规则名字来定义。

要匹配字符串“aba”可以使用下列规则:

fu = %x61; a
bar = %x62; b
mumble = fu bar fu

选择

规则1 / 规则2

规则可以通过用反斜杠(“/”)分隔的多选一规则来定义。

要接受规则 <fu> 或规则 <bar> 可构造如下规则:

fubar = fu / bar

递增选择

规则1 =/ 规则2

可以通过使用在规则名字和定义之间的“=/”来向一个规则增加补充选择。

规则

ruleset = alt1 / alt2 / alt3 / alt4 / alt5

等价于

ruleset = alt1 / alt2
ruleset =/ alt3
ruleset =/ alt4 / alt5

值范围

%c##-##

数值范围可以通过使用连字符(“-”)来指定。

规则

OCTAL = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7"

等价于

OCTAL = %x30-37

序列分组

(规则1 规则2)

元素可以放置在圆括号中来组合定义中的规则。

要匹配“elem fubar snafu”或“elem tarfu snafu”可以构造下列规则:

group = elem (fubar / tarfu) snafu

要匹配“elem fubar”或“tarfu snafu”可以构造下列规则:

group = elem fubar / tarfu snafu
group = (elem fubar) / (tarfu snafu)

可变重复

n*n规则

要指示一个元素的重复可以使用形式 <a>*<b> 元素。可选的 <a> 给出要包括的元素的最小数目,缺省为 0。可选的 <b> 给出要包括的元素的最大数目,缺省为无穷。

对零或多个元素使用 *元素,对一或多个元素使用 1*元素,对二或三个元素使用 2*3元素

特定重复  

n规则

要指示明确数目的元素可使用形式 <a> 元素,它等价于 <a>*<a>元素

使用 2DIGIT 得到两个数字,使用 3DIGIT 得到三个数字。(DIGIT 在下面的核心规则中定义)。

可选序列

[规则]

要指示可选元素下列构造是等价的:

[fubar snafu]
*1(fubar snafu)
0*1(fubar snafu)

注释

; 注释

分号(“;”)开始一个注释并持续到此行的结束。

操作符优先级

上述操作符有从最紧绑定(binding)到最松绑定的给定优先级:

  1. 字符串,名字形成(formation)
  2. 注释
  3. 值范围
  4. 重复
  5. 分组,可选
  6. 串联
  7. 选择

与串联一起使用选择操作符可以造成混淆,建议使用分组来做明确串联分组。

核心规则

核心规则定义于 ABNF 标准中。

规则 形式定义 意义
ALPHA %x41-5A / %x61-7A 大写和小写 ASCII 字母 (A-Z a-z)
DIGIT %x30-39 数字 (0-9)
HEXDIG DIGIT / “A” / “B” / “C” / “D” / “E” / “F” 十六进制数字 (0-9 A-F a-f)
DQUOTE %x22 双引号
SP %x20 空格
HTAB %x09 水平tab
WSP SP / HTAB 空格和水平tab
LWSP *(WSP / CRLF WSP) 线性空白(晚于换行)
VCHAR %x21-7E 可见(打印)字符
CHAR %x01-7F 任何 7-位 US-ASCII 字符,不包括 NUL
OCTET %x00-FF 8 位数据
CTL %x00-1F / %x7F 控制字符
CR %x0D 回车
LF %x0A 换行
CRLF CR LF 互联网标准换行
BIT “0” / “1”

例子

在巴科斯范式(BNF)条目中的邮政地址的例子可以被指定为:

postal-address = name-part street zip-part

name-part = *(personal-part SP) last-name [SP suffix] CRLF
name-part = / personal-part CRLF

personal-part = first-name / (initial ".")
first-name = *ALPHA
initial = ALPHA
last-name = *ALPHA
suffix = ("Jr." / "Sr." / 1*("I" / "V" / "X"))

street = [apt SP] house-num SP street-name CRLF
apt = 1*4DIGIT
house-num = 1*8(DIGIT / ALPHA)
street-name = 1*VCHAR

zip-part = town-name "," SP state 1*2SP zip-code CRLF
town-name = 1*(ALPHA / SP)
state = 2ALPHA
zip-code = 5DIGIT ["-" 4DIGIT]

引用

参考

来源:http://kb.cnblogs.com/page/189566/

来源:http://tianya23.blog.51cto.com/1081650/633141

IceGrid应用配置[转]

1. 概述

1.1 配置目标

本文档是描述Ice中间件中的IceGrid服务的应用配置,通过使用IceGrid服务来实现:
1. 服务器端服务分布式部署。
2. 服务器端服务按需激活。
3. 服务器端服务多节点负载均衡。
4. 注册服务主/从热备(Master/Slaves)
5. 集成IceBox服务

1.2 实验环境

1. 硬件:hp服务器,3台
2. 操作环境:Red Hat 5
3. 服务器程序:ServerApp.jar
4. 说明:实际应用中,服务器节点可任意扩充、操作系统可被更换、服务器程序可用实际项目的服务程序替换,本文档所描述的配置方式具有通用性,适用但不局限于当前实验环境。

1.3 局限

本文档不详细描述IceGrid服务的运行机制和实现原理,不详细介绍服务器端和客户端程序的实现,主要描述IceGrid服务应用的配置步骤、主要配置项及验证配置结果等。

2. 配置过程

2.1 服务器端配置

配置步骤:
1. 创建主注册服务(Master)的配置文件config_master.grid,文件名称可以任意
2. 创建从注册服务(Slave)的配置文件 config_slave.grid, 文件名称可以任意
3. 创建各节点服务的配置文件config.node,文件名称可以任意
4. 创建分布式应用配置文件app.xml,文件名称可以任意,但格式最好定义成xml
5. 运行Ice提供的工具,启动我们的分布式应用,主要有如下两个工具:icegridnode和icegridadmin。详细启动过程如下:
1) icegridnode–Ice.Config=config_master.grid 启动主注册服务
2) icegridnode–Ice.Config=config_slave.grid 启动从注册服务
3) icegridadmin–Ice.Config= config_master.grid -e “application add app.xml” 部署分布式服务
icegridadmin –Ice.Config= config_master.grid-e “application update app.xml” 重新部署分布式服务
4) icegridnode–Ice.Config=config.node 将各节点注册到注册服务的注册表中
配置文件清单:
假设有n个节点(n > 0), 其中从注册服务有x个,(x > 0)
config_master.grid ———- 主注册服务配置文件 ——— 1份
config_slave.grid ———– 从注册服务配置文件 ——— x份
config.node —————– 节点配置文件 ————– n份
app.xml ———————- 部署配置文件 ————– 1份
通常情况下,由于注册服务占用资源很少,所以一般都会和一个节点集成在一起,并且可以和节点服务在一个进程中运行。因此,如果假设服务部署到n个服务器,通常情况下配置文件清单如下:
config_master.grid– 主注册服务配置文件 — 1份 — 主注册服务信息+节点信息
config_slave.grid— 从注册服务配置文件 — x份 — 从注册服务信息+节点信息
config.node——— 节点配置文件 —- n-1-x份 — 节点信息
app.xml————- 部署配置文件 ——– 1份 — 部署信息
其中app.xml要和config_master.grid放在一台服务器上,下面的各章节将详细介绍各配置文件。

2.1.1 主注册服务配置

config_master.grid的内容:

#
# The IceGrid InstanceName
#
IceGrid.InstanceName=YunIceGrid # 1
#
# The IceGridlocator proxy.
#
Ice.Default.Locator=YunIceGrid/Locator:default-h liyunde.com -p 4061:default -h ice.liyunde.com -p 4061 #2
#
# IceGridregistry configuration.
#
IceGrid.Registry.Client.Endpoints=default-p 4061 #3
IceGrid.Registry.Server.Endpoints=default #4
IceGrid.Registry.Internal.Endpoints=default #5
IceGrid.Registry.Data=master #6
IceGrid.Registry.PermissionsVerifier=YunIceGrid/NullPermissionsVerifier #7
IceGrid.Registry.AdminPermissionsVerifier=YunIceGrid/NullPermissionsVerifier#8
IceGrid.Registry.SSLPermissionsVerifier=YunIceGrid/NullSSLPermissionsVerifier#9
IceGrid.Registry.AdminSSLPermissionsVerifier=YunIceGrid/NullSSLPermissionsVerifier #10
#
# IceGrid SQLconfiguration if using SQL database.
#
#Ice.Plugin.DB=IceGridSqlDB:createSqlDB #11
#IceGrid.SQL.DatabaseType=QSQLITE #12
#IceGrid.SQL.DatabaseName=register/Registry.db #13
#
#
#Ice Error andStandard output Set
#
#Ice.StdErr=master/stderr.txt #14
#Ice.StdOut= master/stdout.txt #15
#
#Trace Registryproperties
#
Ice.ProgramName=Master #16
IceGrid.Registry.Trace.Node=3 #17
IceGrid.Registry.Trace.Replica=3 #18
#
# IceGrid nodeconfiguration.
#
IceGrid.Node.Name=node_1 #19
IceGrid.Node.Endpoints=default #20
IceGrid.Node.Data=node_1 #21
IceGrid.Node.CollocateRegistry=1 #22
#IceGrid.Node.Output=node_1 #23
#IceGrid.Node.RedirectErrToOut=1 #24
# Traceproperties.
#
IceGrid.Node.Trace.Activator=1 #25
#IceGrid.Node.Trace.Adapter=2 #26
#IceGrid.Node.Trace.Server=3 #27
#
# Dummy usernameand password for icegridadmin.
#
IceGridAdmin.Username=mygrid #28
IceGridAdmin.Password=mygrid #29

配置项说明:
#1 为这个应用实例指定一个唯一的标识
# 2 注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到
# 3 客户端访问注册服务器的端点信息
# 4 服务访问注册服务器的端点信息,通常是default
# 5 内部访问端点信息,通常是default,节点用这个端口和注册服务通信
# 6 注册服务的数据目录的路径
# 7 设定防火墙安全代理,从而控制客户端访问注册表时可用的权限
# 8 设定防火墙安全代理,从而控制注册表管理者可用的权限
# 9 设定SSL安全代理,从而设定客户端访问注册表时的SSL安全访问机制
# 10 设定SSL安全代理,从而设定注册表管理者的SSL安全访问机制
# 11 指定Ice对象序列化的机制,如果不设置,默认用Freeze机制
# 12 指定使用数据库的类型
#13 指定使用数据库的名称
#14 指定标准错误输出文件
#15 指定标准输出文件
#16 指定主注册服务的名称
#17 指定主注册服务跟踪节点信息的级别(0~3),默认为0
#18 指定主/从热备注册服务的跟踪级别(0~3),默认为0
# 19 定义节点的名称,必须唯一
# 20 节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default
# 21 节点的数据目录的路径
# 22 定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置
# 23 节点标准输出信息重定向蹈的目录路径,会自动生成输出文件
# 24 节点上的服务程序的标准错误重定向到标准输出
# 25 激活器跟踪级别,通常有0,1,2,3级,默认是0
# 26 对象适配器跟踪级别,通常有0,1,2,3级,默认是0
# 27 服务跟踪级别,通常有0,1,2,3级,默认是0
# 28 IceGrid管理器登录该应用的用户名
# 29 IceGrid管理器登录该应用的密码
未涉及的属性还有一些,如果需要请参考官方文档。

2.1.2 从注册服务配置

config_slave.grid的内容:
#
# The IceGridlocator proxy.
#
Ice.Default.Locator=YunIceGrid/Locator:default-h 10.0.2.241 -p 4061:default -h 10.0.2.242-p 4061 #1
#
# IceGridregistry configuration.
#
IceGrid.Registry.Client.Endpoints=default-p 4061 #2
IceGrid.Registry.Server.Endpoints=default #3
IceGrid.Registry.Internal.Endpoints=default #4
IceGrid.Registry.Data=slave_1 #5
IceGrid.Registry.ReplicaName=slave_1 #6
IceGrid.Registry.PermissionsVerifier=YunIceGrid/NullPermissionsVerifier #7
IceGrid.Registry.AdminPermissionsVerifier=YunIceGrid/NullPermissionsVerifier#8
IceGrid.Registry.SSLPermissionsVerifier=YunIceGrid/NullSSLPermissionsVerifier#9
IceGrid.Registry.AdminSSLPermissionsVerifier=YunIceGrid/NullSSLPermissionsVerifier #10
#
# IceGrid SQLconfiguration if using SQL database.
#
#Ice.Plugin.DB=IceGridSqlDB:createSqlDB #11
#IceGrid.SQL.DatabaseType=QSQLITE #12
#IceGrid.SQL.DatabaseName=register/Registry.db #13
#
#Ice Error andStandard output Set
#
#Ice.StdErr=slave_1/stderr.txt #14
#Ice.StdOut=slave_1/stdout.txt #15
#
#Trace Registryproperties
#
Ice.ProgramName=Slave_1 #16
IceGrid.Registry.Trace.Node=3 #17
IceGrid.Registry.Trace.Replica=3 #18
#
# IceGrid nodeconfiguration.
#
IceGrid.Node.Name=node_2 #19
IceGrid.Node.Endpoints=default #20
IceGrid.Node.Data=node_2 #21
IceGrid.Node.CollocateRegistry=1 #22
#IceGrid.Node.Output=node_2 #23
#IceGrid.Node.RedirectErrToOut=1 #24
# Traceproperties.
#
IceGrid.Node.Trace.Activator=1 #25
#IceGrid.Node.Trace.Adapter=2 #26
#IceGrid.Node.Trace.Server=3 #27
#
# Dummy usernameand password for icegridadmin.
#
IceGridAdmin.Username=mygrid #28
IceGridAdmin.Password=mygrid #29
配置项说明:
其实这个文件和主注册配置文件基本一样,差别只有一点:
1. 没有指定应用实例名,因为在主注册服务中已经有了定义
2. 多了第6行,IceGrid.Registry.ReplicaName=slave_1,指定从注册服务的名称
其它的基本就没有差别了,大部分属性项在config_master.grid里面都有定义,为了方便阅读,下面也将用到的各项给出说明:
# 1 注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到
# 2 客户端访问注册服务器的端点信息
# 3 服务访问注册服务器的端点信息,通常是default
#4 内部访问端点信息,通常是default,节点用这个端口和注册服务通信
# 5 注册服务的数据目录的路径
# 6 指定从注册服务的名称
# 7 设定防火墙安全代理,从而控制客户端访问注册表时可用的权限
#8 设定防火墙安全代理,从而控制注册表管理者可用的权限
# 9 设定SSL安全代理,从而设定客户端访问注册表时的SSL安全访问机制
#10 设定SSL安全代理,从而设定注册表管理者的SSL安全访问机制
# 11 指定Ice对象序列化的机制,如果不设置,默认用Freeze机制
# 12 指定使用数据库的类型
#13 指定使用数据库的名称
#14 指定标准错误输出文件
#15 指定标准输出文件
#16 指定从注册服务运行时程序名称
#17 指定从注册服务跟踪节点信息的级别(0~3),默认为0
#18 指定主/从热备注册服务的跟踪级别(0~3),默认为0
# 19 定义节点的名称,必须唯一
# 20 节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default
# 21 节点的数据目录的路径
# 22 定义节点是否和注册服务并置在一起,设为1时并置,设为0时不并置
# 23 节点标准输出信息重定向蹈的目录路径,会自动生成输出文件
# 24 节点上的服务程序的标准错误重定向到标准输出
# 25 激活器跟踪级别,通常有0,1,2,3级,默认是0
# 26 对象适配器跟踪级别,通常有0,1,2,3级,默认是0
# 27 服务跟踪级别,通常有0,1,2,3级,默认是0
# 28 IceGrid管理器登录该应用的用户名
# 29 IceGrid管理器登录该应用的密码

2.1.3 应用部署配置

app.xml配置文件内容:

1<icegrid>

2 <application name=“RTDSSystem”>

3 <server-template id=“RTDSSystemServer”>

4 <parameter name=“index”/>

5 <server id=“RTDSSystemServer-${index}”exe=Java activation=“on-demand”>

6 <adapter name=“RTDataSysytem” endpoints=“tcp” replica-group=“ReplicatedRTDataSysytemAdp”/>

7 <option>-jar</option>

8 <option>ServerApp.jar</option>

9 </server>

10 </server-template>

11

12 <replica-group id=“ReplicatedRTDataSysytemAdp”>

13 <load-balancing type=“round-robin”/>

14 <object identity=“RTDataSource” type=“::RTDataSystem::RTDataSource”/>

15 </replica-group>

16

17 <node name=“node_1”>

18 <server-instance template=“RTDSSystemServer” index=“1”/>

19 <server-instance template=“RTDSSystemServer” index=“11”/>

20 <server-instance template=“RTDSSystemServer” index=“111”/>

21 </node>

22 <node name=“node_2”>

23 <server-instance template=“RTDSSystemServer” index=“2”/>

24 <!–server-instancetemplate=”RTDSSystemServer” index=”22″/–>

25 <!–server-instancetemplate=”RTDSSystemServer” index=”222″/–>

26 </node>

27 <node name=“node_3”>

28 <server-instance template=“RTDSSystemServer” index=“3”/>

29 <!–server-instancetemplate=”RTDSSystemServer” index=”33″/–>

30 <!–server-instancetemplate=”RTDSSystemServer” index=”333″/–>

31 </node>

32 </application>

33</icegrid>

配置文件结构分析:

IceGrid里,部署是一个在注册服务中表述一个应用(Application)的过程,而部署配置文件就是来描述这些配置信息的文件,这个配置文件是用xml标记性语言来描述的。通常一个部署应该包含如下信息:

1. 应用标签(application),name属性定义这个应用的名字

2. 服务(server), 一个逻辑上的服务器,能够通过exe命令而启动的一个服务程序。activation属性,是设置服务的启动方式,on-demand是最常用的方式,另外还有always等启动方式;option标签是exe执行命令命令行的参数;

3. 适配器(adpter),定义服务器端的适配器。

name属性唯一标志这个适配器;

endpoints属性指定端点信息;

replica-group属性标示该适配器是个可复制组集群,并指定这个可复制组的名称;

register-process属性定义了是否这个节点是否可以被icegrid关闭;

4. 节点(node),它应该代表了一个物理上的节点。

name属性指定节点的名字,并且是唯一的。

5. 可复制组(replica-group),一组对象适配器的集合。

id属性唯一标识一个可复制组;

load-balancing子项中type属性指定负载均衡策略,icegrid提供了四种负载均衡策略: Random (随机方式)

Adaptive(适配方式)

Round Robin(最近最少使用)

Ordered(顺序方式)

object子项定义适配器绑定的服务对象信息。其中identity属性指定对象的标识,type属性指定了对象的层次结构类型。这两个属性都可以唯一的标识一个服务对象。

6. 服务模板(server-temple),服务模板是对服务的一个抽象,避免了重复定义。这样,在节点中描述服务时只需要实例化它的服务模板就可以了。

id属性唯一标识一个服务模板;

parameter子项定义服务模板的参数,可包含多个,主要实例化服务时用;

server子项就是上面2中的服务定义;

另外还有一些特殊的服务模板,比如:icebox服务模板,它的定义和通用的服务模板的定义不太一样。

解析app.xml文件:

通过对配置文件结构的分析,来解析一下app.xml。

第1行,标识这是一个icegrid的配置文件;

第2行,标识应用的名称为RTDSSystem,这个名称是唯一的;

第3~10行,定义了一个服务模板RTDSSystemServer,并有一个参数index;

其中5~9定义了这个模板包含的服务定义,第6行是这个服务包含的对象适配器

的定义;

第12~15行,是对可复制组的定义,包括服务对象的定义和负载均衡策略;

第17~21行,是对节点node_1的定义,指定了节点的名称,包含的服务(3个服务);

第22~26行,是对节点node_2的定义

第27~31行,是对节点node_3的定义

最后两行是闭合标签,至此一个icegrid的分布式部署配置文件就完成了。

部署配置文件的扩展:

app.xml中对服务模板、适配器、服务对象等的配置都是一个,事实上这些可以在文件中定义多个,比如可以有多个服务模板,一个服务里可以有多个适配器,可以有多个可复制组,一个节点里可以有多个不同类型的服务等。

另外,app.xml可以包含其它的xml。

2.1.4 节点配置

config.grid文件的内容:

# The IceGridlocator proxy.
#
Ice.Default.Locator=YunIceGrid/Locator:default-h 10.0.2.241 -p 4061:default -h 10.0.2.242-p 4061 #1
#
# IceGrid nodeconfiguration.
#
IceGrid.Node.Name=node_2 #2
IceGrid.Node.Endpoints=default #3
IceGrid.Node.Data=node_2 #4
IceGrid.Node.Output=node_2 #5
IceGrid.Node.RedirectErrToOut=1 #6
# Trace properties.
#
IceGrid.Node.Trace.Activator=1 #7
#IceGrid.Node.Trace.Adapter=2 #8
#IceGrid.Node.Trace.Server=3 #9

配置项说明:
事实上,这个文件里面的配置项,在config_slave.grid中都有描述,但这里也列出来,方便阅读。
#1 注册服务的端点信息(主注册服务和所有的从注册服务),节点注册时要用到
#2 定义节点的名称,必须唯一
#3 节点被访问的端口信息,注册服务使用这个端点和节点通信,通常设为default
#4 节点的数据目录的路径
#5 节点标准输出信息重定向的目录路径,会自动生成输出文件
#6 节点上的服务程序的标准错误重定向到标准输出
#7 激活器跟踪级别,通常有0,1,2,3级,默认是0
#8 对象适配器跟踪级别,通常有0,1,2,3级,默认是0
#9 服务跟踪级别,通常有0,1,2,3级,默认是0

2.2 客户端配置

客户端的配置很简单,和分布式相关的配置就一项,添加如下:
#
# The IceGridlocator proxy.
#注册服务的端点信息(主注册服务和所有的从注册服务),用于定位
Ice.Default.Locator=YunIceGrid/Locator:default-h 10.0.2.241 -p 4061:default -h 10.0.2.242-p 4061

3. 结果验证

3.1 程序方式

1. 启动服务器
1) icegridnode–Ice.Config=config_master.grid 启动主注册服务和节点1
2) icegridnode–Ice.Config=config_slave.grid 启动从注册服务和节点2
3) icegridadmin–Ice.Config=config_master.grid -e “application add app.xml” 部署分布式服务
4) icegridnode–Ice.Config=config.node 启动节点3
2. 启动客户端,进行多次远程调用,根据执行情况就可以判断服务器端是否配置成功。

3.2 工具方式

用Ice官方提供的可视化管理工具IceGridGUI.jar来验证和管理icegrid的部署。
打开dos窗口,在命令行下进入C:\Program Files\ZeroC\Ice-3.4.1\bin目录下,然后运行“java –jar IceGridGUI.jar”,弹出IceGrid Admin的主界面

1. 高级应用配置

4.1 集成IceBox

在文档《IceBox开发和配置》(当前是1.0版)中,介绍了一个IceBox服务程序的开发方法和单独应用中配置和管理的过程。在实际的应用中,IceBox服务通常集成到IceGrid中,并通过IceGrid进行激活和部署。
本章节中IceBox服务是集成在IceGrid中,并通过IceGrid进行部署,所以IceBox服务的配置信息不再同《IceBox开发和配置》中一样在config.icebox中描述,而是直接配置在部署文件app.xml中。那也就是说,IceGrid集成IceBox服务,只需要在app.xml文件中添加Icebox服务相关的配置信息就可以了。事实上,有关Ice所有的配置信息(除IceGrid自身的配置信息),都可以添加到app.xml中,并通过icegrid部署后生效。
下面各节详细描述IceBox服务的集成过程。

4.1.1 IceBox服务程序编写

请参考文档《IceBox开发和配置》,这里不再详述。由于IceBox服务相关的配置信息都放在了app.xml中,并且服务是通过IceGrid按需激活的,因此这里程序代码略有调整。下面列出IceBox服务的实现代码:
文件名:ServerService.java

import main.java.DataSource;

import IceBox.Service;

public class ServerService implements IceBox.Service {

/**

* @param name 配置文件中的service名称

* @param communicator对象,由IceBox.ServiceManager负责创建和销毁。

* 可能同时被其他服务共享使用(由配置文件决定),object Adapter的名

* 称必须是唯一的;

* @param args 配置文件中的参数列表

* @Override

**/

public void start(String name,Ice.Communicator communicator,

String[] args){

//创建objectAdapter,名称有配置文件决定

Adapter =communicator.createObjectAdapter(

“RTDataSystem-“+name);

//创建servant

StringRTDataSourceIdentity = communicator.getProperties().

getProperty(“RTDataSource.Identity”);

DataSourceobjDataSrc = new DataSource(“dataSource”);

Adapter.add(objDataSrc,

communicator.stringToIdentity(RTDataSourceIdentity));

Adapter.activate();

}

/**

*

* @param args

* @Override

*

**/

public void stop()

{

Adapter.destroy();

}

private Ice.ObjectAdapter Adapter;

}

4.1.2 IceGrid集成IceBox服务

IceGrid集成IceBox只和部署文件(app.xml)有关,IceBox服务(service)的粒度和普通的server是一样的,因此IceBoxservice的部署和普通的server非常类似,它同样有模板、服务(service)和实例化的概念,可以将IceBox service理解为一个特殊的server。
为了能更清楚的描述这个集成配置的过程,在IceGrid配置的基础上,添加IceBox服务。具体目标如下:
1. 集成ServerService服务(service),并且ServerService服务(service)使用的服务对象和之前server的服务对象使用同一个(type–::RTDataSystem::RTDataSource)
2. 在节点1(node_1)上添加IceBox服务功能(IceBox-Node1),这个IceBox服务包含了5个ServerService服务;同样的在节点2(node_2)上也添加一个IceBox服务功能(IceBox-Node2),也包含了5个ServerService服务
3. 这些IceBox服务中分布的多个服务(service)和之前已经存在的服务(server)一起通过IceGrid实现负载均衡
为了实现上述的功能,需要添加IceBox服务的相关配置,首先看一下此时app.xml的变化,变化和添加部分用浅灰阴影标出。
app.xml
<?xml version=”1.0″encoding=”UTF-8″ ?>
<icegrid>
<applicationname=”RTDSSystem“>
<server-templateid=”RTDSSystemServer“>
<parameter name=”index“/>
<server id=”RTDSSystemServer-${index}” exe=”java“activation=”on-demand“>
<adapter name=”RTDataSysytem“endpoints=”tcp
replica-group=”RTDataSystemGroup“/>
<option>jar</option>
<option>ServerApp.jar</option>
</server>
</server-template>
<!— begin服务模板定义–>
1 <service-templateid=”RTDSystemService“>
2 <parameter name=”name“/>
3 <service name=”${name}” entry=”ServerService“>
4 <description>A simple service named after ${name}</description>
5 <properties>
6 <property name=”RTDataSource.Identity” value=”RTDataSource“/>
7 </properties>
8 <adapter name=”RTDataSystem-${name}” endpoints=”tcp
id=”RTDataSystem-${name}” replica-group=”RTDataSystemGroup
server-lifetime=”false“/>
11 </service>
12 </service-template>
<!– end服务模板定义–>
<replica-groupid=”RTDataSystemGroup“>
<load-balancingtype=”round-robin“/>
<!–load-balancingtype=”ordered” /–>
<!–load-balancingtype=”adaptive” /–>
<!–load-balancingtype=”random” n-replicas=”0″/–>
<object identity=”RTDataSource” type=”::RTDataSystem::RTDataSource“/>
</replica-group>
<node name=”node_1“>
<server-instancetemplate=”RTDSSystemServer” index=”1“/>
<server-instancetemplate=”RTDSSystemServer” index=”11“/>
<server-instancetemplate=”RTDSSystemServer” index=”111“/>
<!— begin IceBox服务配置 IceBox-Node1–>
1 <icebox id=”IceBox-Node1” activation=”on-demand“exe=”java”>
2 <description>Asample IceBox server IceBox-Node1</description>
3 <option>IceBox.Server</option>
4 <properties>
5 <property name=”IceBox.InstanceName” value=”${server}“/>
6 <property name=”Ice.Admin.Endpoints” value=”tcp -h 10.0.2.241“/>
7 <property name=”IceBox.Trace.ServiceObserver” value=”1“/>
8 </properties>
9 <service-instance template=”RTDSystemService” name=”one“/>
10 <service-instancetemplate=”RTDSystemService” name=”two“/>
11 <service-instancetemplate=”RTDSystemService” name=”three“/>
12 <service-instancetemplate=”RTDSystemService” name=”four“/>
13 <service-instancetemplate=”RTDSystemService” name=”five“/>
14 </icebox>
<!— end IceBox服务配置 IceBox-Node1–>
</node>
<node name=”node_2“>
<server-instancetemplate=”RTDSSystemServer” index=”2“/>
<server-instancetemplate=”RTDSSystemServer” index=”22“/>
<server-instancetemplate=”RTDSSystemServer” index=”222“/>
<!— begin IceBox服务配置 IceBox-Node2–>
1 <icebox id=”IceBox-Node2” activation=”on-demand“exe=”java“>
2 <description>Asample IceBox server IceBox-Node2</description>
3 <option>IceBox.Server</option>
4 <properties>
5 <property name=”IceBox.InstanceName” value=”${server}“/>
6 <property name=”Ice.Admin.Endpoints” value=”tcp -h 10.0.2.242“/>
7 <property name=”IceBox.Trace.ServiceObserver” value=”1“/>
8 </properties>
9 <service-instancetemplate=”RTDSystemService” name=”2-one”/>
10 <service-instancetemplate=”RTDSystemService” name=”2-two“/>
11 <service-instancetemplate=”RTDSystemService” name=”2-three“/>
12 <service-instancetemplate=”RTDSystemService” name=”2-four“/>
13 <service-instancetemplate=”RTDSystemService” name=”2-five“/>
14 </icebox>
<!— begin IceBox服务配置 IceBox-Node2–>
</node>
<node name=”node_3“>
<server-instancetemplate=”RTDSSystemServer” index=”3“/>
</node>
</application>
</icegrid>
app.xml中增加的IceBox服务相关的配置部分如下:
n 服务摸板(Service Template):
可以对比一下servertemplate的定义,两者基本上没有什么区别,最大的不同是
Server template中server是指定一个可执行的程序,而service中指定的是动态加载
的组件入口。以下解释上述配置中的服务模板的定义:
第1行指定定义模板的id,唯一标志一个服务模板,第12是闭合标签;
第2行定义了一个参数name,默认值是“name”;
第3~11行定义了模板中使用的服务(service),并在该service中指定了名称、
入口、描述信息、配置属性,定义了一个对象适配器;
第4行,是该服务的描述信息;
第5~7行,是属性定义列表,这里定义了一个属性RTDataSource.Identity,并
指定其值为RTDataSource;
第8行,定义了一个对象适配器,指定了其name、endpoints、id、replica-group
等属性信息,这个基本上和server中adapter的定义没有什么区别
以上内容就是service模板的定义。
n IceBox服务(IceBox-Node1):
icebox服务的定义被包含在分布的服务器节点中,主要包括三部分的信息:
1. IceBox服务的启动配置信息
2. IceBox的属性配置信息
3. Service服务实例化列表
下面解释这块内容:
第1~3行,指定了IceBox服务的名称,启动方式,启动执行程序等
第4~8行,指定了IceBox服务的属性配置列表,这里定义了IceBox服务的实
例名称、管理器访问端点以及service被跟踪的级别
第9~13行,实例化了5个service服务
至此,一个包含了5个serverservice服务的IceBox服务被集成在node1中。
n IceBox服务(IceBox-Node2)
同IceBox服务(IceBox-Node1)中描述,只是具体value有所不同,这里不再解释。

4.1.3 测试验证

验证方式同第3章,这里不再赘述。部署完成后,就可以通过IceGridGUI.jar程序来进行管理
参考来源:http://blog.csdn.net/educast/article/details/9414789

优秀程序员眼中的整洁代码[转]

有多少程序员,就有多少定义。所以我只询问了一些非常知名且经验丰富的程序员。

image.php_-57.gif

Bjarne Stroustrup,C++语言发明者,C++ Programming Language(中译版《C++程序设计语言》)一书作者。

我喜欢优雅和高效的代码。代码逻辑应当直截了当,叫缺陷难以隐藏;尽量减少依赖关系,使之便于维护;依据某种分层战略完善错误处理代码;性能调至最优,省得引诱别人做没规矩的优化,搞出一堆混乱来。整洁的代码只做好一件事。

Bjarne用了“优雅”一词。说得好!我MacBook上的词典提供了如下定义:外表或举止上令人愉悦的优美和雅观;令人愉悦的精致和简单。注意对“愉悦”一词的强调。Bjarne显然认为整洁的代码读起来令人愉悦。读这种代码,就像见到手工精美的音乐盒或者设计精良的汽车一般,让你会心一笑。

Bjarne也提到效率——而且两次提及。这话出自C++发明者之口,或许并不出奇;不过我认为并非是在单纯追求速度。被浪费掉的运算周期并不雅观,并不令人愉悦。留意Bjarne怎么描述那种不雅观的结果。他用了“引诱”这个词。诚哉斯言。糟糕的代码引发混乱!别人修改糟糕的代码时,往往会越改越烂。

务实的Dave Thomas和Andy Hunt从另一角度阐述了这种情况。他们提到破窗理论4。窗户破损了的建筑让人觉得似乎无人照管。于是别人也再不关心。他们放任窗户继续破损。最终自己也参加破坏活动,在外墙上涂鸦,任垃圾堆积。一扇破损的窗户开辟了大厦走向倾颓的道路。

Bjarne也提到完善错误处理代码。往深处说就是在细节上花心思。敷衍了事的错误处理代码只是程序员忽视细节的一种表现。此外还有内存泄漏,还有竞态条件代码。还有前后不一致的命名方式。结果就是凸现出整洁代码对细节的重视。

Bjarne以“整洁的代码只做好一件事”结束论断。毋庸置疑,软件设计的许多原则最终都会归结为这句警语。有那么多人发表过类似的言论。糟糕的代码想做太多事,它意图混乱、目的含混。整洁的代码力求集中。每个函数、每个类和每个模块都全神贯注于一事,完全不受四周细节的干扰和污染。

image.php_-58.gif

Grady Booch,Object Oriented Analysis and Design with Applications(中译版《面向对象分析与设计》)一书作者。

整洁的代码简单直接。整洁的代码如同优美的散文。整洁的代码从不隐藏设计者的意图,充满了干净利落的抽象和直截了当的控制语句。

Grady的观点与Bjarne的观点有类似之处,但他从可读性的角度来定义。我特别喜欢“整洁的代码如同优美的散文”这种看法。想想你读过的某本好书。回忆一下,那些文字是如何在脑中形成影像!就像是看了场电影,对吧?还不止!你还看到那些人物,听到那些声音,体验到那些喜怒哀乐。

阅读整洁的代码和阅读Lord of the Rings(中译版《指环王》)自然不同。不过,仍有可类比之处。如同一本好的小说般,整洁的代码应当明确地展现出要解决问题的张力。它应当将这种张力推至高潮,以某种显而易见的方案解决问题和张力,使读者发出“啊哈!本当如此!”的感叹。

窃以为Grady所谓“干净利落的抽象”(crisp abstraction),乃是绝妙的矛盾修辞法。毕竟crisp几乎就是“具体”(concrete)的同义词。我MacBook上的词典这样定义crisp一词:果断决绝,就事论事,没有犹豫或不必要的细节。尽管有两种不同的定义,该词还是承载了有力的信息。代码应当讲述事实,不引人猜测。它只该包含必需之物。读者应当感受到我们的果断决绝。

image.php_-59.gif

“老大”Dave Thomas,OTI公司创始人,Eclipse战略教父

整洁的代码应可由作者之外的开发者阅读和增补。它应当有单元测试和验收测试。它使用有意义的命名。它只提供一种而非多种做一件事的途径。它只有尽量少的依赖关系,而且要明确地定义和提供清晰、尽量少的API。代码应通过其字面表达含义,因为不同的语言导致并非所有必需信息均可通过代码自身清晰表达。

Dave老大在可读性上和Grady持相同观点,但有一个重要的不同之处。Dave断言,整洁的代码便于其他人加以增补。这看似显而易见,但亦不可过分强调。毕竟易读的代码和易修改的代码之间还是有区别的。

Dave将整洁系于测试之上!要在十年之前,这会让人大跌眼镜。但测试驱动开发(Test Driven Development)已在行业中造成了深远影响,成为基础规程之一。Dave说得对。没有测试的代码不干净。不管它有多优雅,不管有多可读、多易理解,微乎测试,其不洁亦可知也。

Dave两次提及“尽量少”。显然,他推崇小块的代码。实际上,从有软件起人们就在反复强调这一点。越小越好。

Dave也提到,代码应在字面上表达其含义。这一观点源自Knuth的“字面编程”(literate programming)5。结论就是应当用人类可读的方式来写代码。

image.php_-60.gif

Michael Feathers,Working Effectively with Legacy Code(中译版《修改代码的艺术》)一书作者。

我可以列出我留意到的整洁代码的所有特点,但其中有一条是根本性的。整洁的代码总是看起来像是某位特别在意它的人写的。几乎没有改进的余地。代码作者什么都想到了,如果你企图改进它,总会回到原点,赞叹某人留给你的代码——全心投入的某人留下的代码。

一言以蔽之:在意。这就是本书的题旨所在。或许该加个副标题,如何在意代码。

Michael一针见血。整洁代码就是作者着力照料的代码。有人曾花时间让它保持简单有序。他们适当地关注到了细节。他们在意过。

image.php_-61.gif

Ron Jeffries,Extreme Programming Installed(中译版《极限编程实施》)以及Extreme Programming Adventures in C#(中译版《C#极限编程探险》)作者。

Ron初入行就在战略空军司令部(Strategic Air Command)编写Fortran程序,此后几乎在每种机器上编写过每种语言的代码。他的言论值得咀嚼。

近年来,我开始研究贝克的简单代码规则,差不多也都琢磨透了。简单代码,依其重要顺序:

能通过所有测试;

没有重复代码;

体现系统中的全部设计理念;

包括尽量少的实体,比如类、方法、函数等。

在以上诸项中,我最在意代码重复。如果同一段代码反复出现,就表示某种想法未在代码中得到良好的体现。我尽力去找出到底那是什么,然后再尽力更清晰地表达出来。

在我看来,有意义的命名是体现表达力的一种方式,我往往会修改好几次才会定下名字来。借助Eclipse这样的现代编码工具,重命名代价极低,所以我无所顾忌。然而,表达力还不只体现在命名上。我也会检查对象或方法是否想做的事太多。如果对象功能太多,最好是切分为两个或多个对象。如果方法功能太多,我总是使用抽取手段(Extract Method)重构之,从而得到一个能较为清晰地说明自身功能的方法,以及另外数个说明如何实现这些功能的方法。

消除重复和提高表达力让我在整洁代码方面获益良多,只要铭记这两点,改进脏代码时就会大有不同。不过,我时常关注的另一规则就不太好解释了。

这么多年下来,我发现所有程序都由极为相似的元素构成。例如“在集合中查找某物”。不管是雇员记录数据库还是名-值对哈希表,或者某类条目的数组,我们都会发现自己想要从集合中找到某一特定条目。一旦出现这种情况,我通常会把实现手段封装到更抽象的方法或类中。这样做好处多多。

可以先用某种简单的手段,比如哈希表来实现这一功能,由于对搜索功能的引用指向了我那个小小的抽象,就能随需应变,修改实现手段。这样就既能快速前进,又能为未来的修改预留余地。

另外,该集合抽象常常提醒我留意“真正”在发生的事,避免随意实现集合行为,因为我真正需要的不过是某种简单的查找手段。

减少重复代码,提高表达力,提早构建简单抽象。这就是我写整洁代码的方法。

Ron以寥寥数段文字概括了本书的全部内容。不要重复代码,只做一件事,表达力,小规模抽象。该有的都有了。

image.php_-62.gif

Ward Cunningham,Wiki发明者,eXtreme Programming(极限编程)的创始人之一,Smalltalk语言和面向对象的思想领袖。所有在意代码者的教父。

如果每个例程都让你感到深合己意,那就是整洁代码。如果代码让编程语言看起来像是专为解决那个问题而存在,就可以称之为漂亮的代码。

这种说法很Ward。它教你听了之后就点头,然后继续听下去。如此在理,如此浅显,绝不故作高深。你大概以为此言深合己意吧。再走近点看看。

“……深合己意”。你最近一次看到深合己意的模块是什么时候?模块多半都繁复难解吧?难道没有触犯规则吗?你不是也曾挣扎着想抓住些从整个系统中散落而出的线索,编织进你在读的那个模块吗?你最近一次读到某段代码、并且如同对Ward的说法点头一般对这段代码点头,是什么时候的事了?

Ward期望你不会为整洁代码所震惊。你无需花太多力气。那代码就是深合你意。它明确、简单、有力。每个模块都为下一个模块做好准备。每个模块都告诉你下一个模块会是怎样的。整洁的程序好到你根本不会注意到它。设计者把它做得像一切其他设计般简单。

那Ward有关“美”的说法又如何呢?我们都曾面临语言不是为要解决的问题所设计的困境。但Ward的说法又把球踢回我们这边。他说,漂亮的代码让编程语言像是专为解决那个问题而存在!所以,让语言变得简单的责任就在我们身上了!当心,语言是冥顽不化的!是程序员让语言显得简单。

稿源:代码湾

转自:https://www.oschina.net/news/87473/good-programmers-clean-code