威尼斯网址开户网站【编程好习于旧贯】屏蔽编制程序语言特色

定义数组是做软件开发经常需要用到的最基本的编程语言功能之一,下面示例了采用数组保存一个会话ID的一段简化代码。

利用编程语言的特性不但能简化程序,而且还能提高程序的执行效率。先看一个使用sizeof()提高程序效率的例子程序,图1是没有使用sizeof()之前的代码,其背景信息需要在此做一个交代。其中,alarm_string变量是定义为长度是255的char数组,而tail_msg定义的是一个指向字符串“,List
NOT
Complete”的指针。space是为了得到在alarm_string中除去tail_msg所指向字符串的长度后,有多少空间可以用来存放其它的内容,这是因为在某种情况下,需要将tail_msg所指向的字符串拷贝到alarm_string数组的末尾。另外,tail_msg所指向的字符串其内容是不会被更改的。

每种语言都有自己的独到之处,或奇特的语法,或不常见的函数,或非标准的执行方式。因此,不论新丁还是老手,看着某个特性会突然醉了。文中总结了10个经常被提及的“奇异”特性。

SQL编程的一些良好好习惯,SQL编程良好好习惯

|转载自:cnblog

|原文链接:

 

 我们做软件开发的,大部分人都离不开跟数据库打交道,特别是erp开发的,跟数据库打交道更是频繁,存储过程动不动就是上千行,如果数据量大,人员流动大,那么我们还能保证下一段时间系统还能流畅的运行吗?我们还能保证下一个人能看懂我们的存储过程吗?那么我结合公司平时的培训和平时个人工作经验和大家分享一下,希望对大家有帮助。

 

要知道sql语句,我想我们有必要知道sqlserver查询分析器怎么执行我么sql语句的,我们很多人会看执行计划,或者用profile来监视和调优查询语句或者存储过程慢的原因,但是如果我们知道查询分析器的执行逻辑顺序,下手的时候就胸有成竹,那么下手是不是有把握点呢?

 以下是个人认为的SQL编程的一些良好习惯:

 

  机房收费系统第二版做完将近二十多天了,这几天开始挨个检查验收,昨天终于轮到我了,本身第二版自我感觉就不怎么样,存在很多的不合理性,不过昨天给我找出来的这几个问题反倒不是我之前所关心的问题,而是作为一个程序员最根本也是最重要的东西。

#define SESSION_ID_LEN_MIN  1
#define SESSION_ID_LEN_MAX  256

example.c
00070: #define
MAX_STRING_TXT         255
00071: char alarm_string [MAX_STRING_TXT];
00072:
00073: char *tail_msg = “, List NOT Complete”;
00074: char space = MAX_STRING_TXT – strlen (tail_msg) – 1;
图1

1. Javascript: + 是一个连接符

一:查询的逻辑执行顺序

 

(1) FROM < left_table> 

 

(3) < join_type>  JOIN < right_table>   (2) ON <
join_condition> 

 

(4) WHERE < where_condition> 

 

(5) GROUP BY < group_by_list> 

 

(6) WITH {cube | rollup}

 

(7) HAVING < having_condition> 

 

(8) SELECT  (9) DISTINCT (11) < top_specification>  <
select_list> 

 

(10) ORDER BY < order_by_list> 

 

标准的SQL 的解析顺序为:

 

(1).FROM 子句 组装来自不同数据源的数据

 

(2).WHERE 子句 基于指定的条件对记录进行筛选

 

(3).GROUP BY 子句 将数据划分为多个分组

 

(4).使用聚合函数进行计算

 

(5).使用HAVING子句筛选分组

 

(6).计算所有的表达式

 

(7).使用ORDER BY对结果集进行排序

 

  1.注释过少和不规范化

  刚开始做的时候还比较有精力,基本上在每个方法都写注释,参数返回值都写的比较清楚,随着到后面的进行,类越来越多,方法也随之

增加,总感觉到写注释是一件累人的活儿,而且参数返回值什么的用自己的名称就已经表达的很清楚,所以就节省了这一步。

  正确写注释的方式其实微软已经为你提供了,你所要做的只是在键盘上敲击三下注释键后填充就可以了。

  如上图这样注释有很多的好处,一是便于自己和用户阅读,二是便于追踪问题,三是能直接生成文档。

  很多人不写注释主要原因就是为了节省时间,但是相比程序员的打字速度写个小小的注释是不需要多长时间的,而是主观上想不想写,

想不想养成一个良好的习惯,让别人拿到你的代码是在赏心悦目,而不是紧锁眉头骂你写的烂代码;说小了这是在未别人为自己以后看代码

提供方便,说大了这是在为中国软件业得发展添砖加瓦,为自己将来很好的发展埋下伏笔。




  2.画UML图的艺术

  先来看第一张图:

  再来看第二张图:

  两张图所要表达的意思是完全相同的,但他们里面包含的讯息却是不同的,第二张图看起来貌似更简洁一些,它将业务的主线一目了然的

展现开发人员的眼前,也从另一个侧面说明了画图人心里非常清楚业务的主线和副线,思路非常明确;让其他看图的人也能随着架构者的思路

向下发展,从图里读出架构者的用意,省去了很多不必要的时间和语言交流。

  第二张图没有画依赖实体类(Entity)的连线,并不是说这条线不存在,而是这条线在心中,这里面包含一个哲学----“有既无,无既有”,

放在本例中就是说:既然下面每个包(Factory包下面)都和Entity这个类存在依赖关系,那么这就不需要展现出来了,放在心中即可,画出来反

倒添乱;但是如果其中一个包(如CashStrategy)和Entity没有任何关系,则需要把其他包和Entity包之间的依赖关系画出来,来表明两个包之

间(CashStrategy和Entity)是没有关系的。

    举个简单的例子,比如现在扩招之风吹遍祖国大地,等将来有一天人人都是大学生、研究生,那么在填写简历的时候就没必要写自己是大

学生或研究生了;相反,如果你不是,那你还真得在简历中写明自己不是大学生。

  3.写程序要严格按照图中引用关系 

  图既然是按照世界统一的UML来画的,那么程序中要严格按照图来引用各程序集(包)之间的关系,因为这就是国际认可的,大家都以这

个为标准,切不可为了一些其他原因乱引用关系。在做收费系统的过程中,用到反射时出现了一个“未能加载或找到程序集Dal····”的

错误,上网一搜看大家的解决方案是直接让UI层引用Dal层,很多网友还在博客中记录下了这个过程,但这里要问的是:如果UI层直接Dal层,

那Bll层、工厂、接口等这几层要它还干什么?这又不是返回原始社会了么,耦合性又加大了。综上所述,引用关系很重要,切不可乱用!

  收获很多,需要一言一行中去消化。

char g_SessionId
[SESSION_ID_LEN_MAX];

在图1中,为了计算space的值,需要用到strlen()函数以得到tail_msg所指向字符串的长度,由于strlen()并不将字符串的结束符‘\0’计算在内,所以space的最后面还得减一。由于strlen()是一个函数,所以图1的这短代码在被执行时,strlen()也会每次都被调用,这显然需要耗费一定的处理器时间,更好的方案如图2所示。

问题描述:

二 执行顺序:

 

1.FROM:对FROM子句中前两个表执行笛卡尔积生成虚拟表vt1

 

2.ON:对vt1表应用ON筛选器只有满足< join_condition>
为真的行才被插入vt2

 

3.OUTER(join):如果指定了OUTER JOIN保留表(preserved
table)中未找到的行将行作为外部行添加到vt2
生成t3如果from包含两个以上表则对上一个联结生成的结果表和下一个表重复执行步骤和步骤直接结束

 

4.WHERE:对vt3应为WHERE筛选器只有使< where_condition>
为true的行才被插入vt4

 

5.GROUP BY:按GROUP BY子句中的列列表对vt4中的行分组生成vt5

 

6.CUBE|ROLLUP:把超组(supergroups)插入vt6 生成vt6

 

7.HAVING:对vt6应用HAVING筛选器只有使< having_condition>
为true的组才插入vt7

 

8.SELECT:处理select列表产生vt8

 

9.DISTINCT:将重复的行从vt8中去除产生vt9

 

10.ORDER BY:将vt9的行按order by子句中的列列表排序生成一个游标vc10

 

11.TOP:从vc10的开始处选择指定数量或比例的行生成vt11 并返回调用者

 

看到这里,那么用过linqtosql的语法有点相似啊?如果我们我们了解了sqlserver执行顺序,那么我们就接下来进一步养成日常sql好习惯,也就是在实现功能同时有考虑性能的思想,数据库是能进行集合运算的工具,我们应该尽量的利用这个工具,所谓集合运算实际就是批量运算,就是尽量减少在客户端进行大数据量的循环操作,而用SQL语句或者存储过程代替。

 

int save_session_id (char *_session_id, int _length)
{
if (_length <
SESSION_ID_LEN_MIN ||
       _length > SESSION_ID_LEN_MAX) {
return ERROR;
   }

example.c
00070: #define
MAX_STRING_TXT         255
00071: char alarm_string [MAX_STRING_TXT];
00072:
00073: static const char tail_msg [] = “, List NOT Complete”;
00074: char space = MAX_STRING_TXT – sizeof
(tail_msg);
图2

在JS中,+
号用在数字间,可以用作常规加法;但如果遇上字符,又可作为字符连接符。例如:’1’+
1的结果是11。

三、只返回需要的数据

 

返回数据到客户端至少需要数据库提取数据、网络传输数据、客户端接收数据以及客户端处理数据等环节,如果返回不需要的数据,就会增加服务器、网络和客户端的无效劳动,其害处是显而易见的,避免这类事件需要注意:

 

A、横向来看

 

(1)不要写SELECT *的语句,而是选择你需要的字段。

 

(2)当在SQL语句中连接多个表时,
请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误。

 

如有表table1(ID,col1)和table2 (ID,col2)

 

 Select A.ID, A.col1, B.col2

 

 — Select A.ID, col1, col2 –不要这么写,不利于将来程序扩展

 

from table1 A inner join table2 B on A.ID=B.ID Where …

 

 B、纵向来看:

 

(1)合理写WHERE子句,不要写没有WHERE的SQL语句。

 

(2) SELECT TOP N * –没有WHERE条件的用此替代 

 

   memcpy (g_SessionId, _session_id, _length);
   g_SessionId [_length] = ‘\0’;

图2中将tail_msg定义为一个静态数组,且在space变量的计算中使用sizeof()进行替代,注意sizeof()会将字符串的结束符‘\0’计算在内。由于sizeof()的值是在编译时就决定了的,也就是说,对于这里的例子,编译器在编译时就会计算出sizeof(tail_msg)的值应当是20,因此,space在运行时将会被直接斌值为235,而不存在任何的函数调用和数学运算。另外,还需要注意tail_msg需要定义为static和const,否则编译器会生成一段代码,每次这段程序被执行时都会对位于栈上的tail_msg数组进行初始化。将tail_msg定义为static和const就会造成其内存分配在.rodata段参见《程序中的段》)上,而不是栈上,从而避免多次的初始化操作。

成因分析:

四 :尽量少做重复的工作

 

A、控制同一语句的多次执行,特别是一些基础数据的多次执行是很多程序员很少注意的。

 

B、减少多次的数据转换,也许需要数据转换是设计的问题,但是减少次数是程序员可以做到的。

 

C、杜绝不必要的子查询和连接表,子查询在执行计划一般解释成外连接,多余的连接表带来额外的开销。

 

D、合并对同一表同一条件的多次UPDATE,比如

 

UPDATE EMPLOYEE SET FNAME=’HAIWER’

WHERE EMP_ID=’ VPA30890F’ UPDATE EMPLOYEE SET LNAME=’YANG’

WHERE EMP_ID=’ VPA30890F’

 

这两个语句应该合并成以下一个语句

 

UPDATE EMPLOYEE SET FNAME=’HAIWER’,LNAME=’YANG’  WHERE EMP_ID=’
VPA30890F’

 

E、UPDATE操作不要拆成DELETE操作+INSERT操作的形式,虽然功能相同,但是性能差别是很大的。

 

return SUCCESS;
}

下面再看另一个使用编程语言特性的例子,原始的例子如图3所示。在143行调用memset()对局部数组变量temp进行置零初始化,显然,由于memset()函数的存在,这段代码每次运行时都得进行memset()函数调用,更好的解决方案如图4所示。

根本性原因是JS属于弱类型语言。比方说Python,同样地使用+
号作为字符连接符,但由于它是强类型语言,一旦发现一个字符与一个整数进行相加,它会提示这是个错误操作。

五、注意临时表和表变量的用法

 

在复杂系统中,临时表和表变量很难避免,关于临时表和表变量的用法,需要注意:

 

A、如果语句很复杂,连接太多,可以考虑用临时表和表变量分步完成。

 

B、如果需要多次用到一个大表的同一部分数据,考虑用临时表和表变量暂存这部分数据。

 

C、如果需要综合多个表的数据,形成一个结果,可以考虑用临时表和表变量分步汇总这多个表的数据。

 

D、其他情况下,应该控制临时表和表变量的使用。

 

E、关于临时表和表变量的选择,很多说法是表变量在内存,速度快,应该首选表变量,但是在实际使用中发现,

 

(1)主要考虑需要放在临时表的数据量,在数据量较多的情况下,临时表的速度反而更快。

 

(2)执行时间段与预计执行时间(多长)

 

F、关于临时表产生使用SELECT INTO和CREATE TABLE + INSERT
INTO的选择,一般情况下,

 

SELECT INTO会比CREATE TABLE + INSERT INTO的方法快很多,

 

但是SELECT
INTO会锁定TEMPDB的系统表SYSOBJECTS、SYSINDEXES、SYSCOLUMNS,在多用户并发环境下,容易阻塞其他进程,

 

所以我的建议是,在并发系统中,尽量使用CREATE TABLE + INSERT
INTO,而大数据量的单个语句使用中,使用SELECT INTO。

 

如果仔细观察将能发现上面的示例代码中存在的一个bug,这个bug是当_length的值的大小刚好是SESSION_ID_LEN_MAX,即246时,就会造成数组写越界。为了修复这一bug,可能会采用以下的方法。其中改动的出发点是判断当_length的大小为SESSION_ID_LEN_MAX时,让程序返回错误。

example.c
00141: #define
MAX_MSK_OCTET_LEN         64
00142: char temp[MAX_MSK_OCTET_LEN];
00143: memset(temp, 0, sizeof(temp));
图3

网友们的看法:

六、子查询的用法(1)

 

子查询是一个 SELECT 查询,它嵌套在 SELECT、INSERT、UPDATE、DELETE
语句或其它子查询中。

 

任何允许使用表达式的地方都可以使用子查询,子查询可以使我们的编程灵活多样,可以用来实现一些特殊的功能。但是在性能上,

 

往往一个不合适的子查询用法会形成一个性能瓶颈。如果子查询的条件中使用了其外层的表的字段,这种子查询就叫作相关子查询。

 

相关子查询可以用IN、NOT IN、EXISTS、NOT EXISTS引入。
关于相关子查询,应该注意:

 

(1)

 

A、NOT IN、NOT EXISTS的相关子查询可以改用LEFT JOIN代替写法。比如:
SELECT PUB_NAME FROM PUBLISHERS WHERE PUB_ID NOT IN (SELECT PUB_ID
FROM TITLES WHERE TYPE = ‘BUSINESS’) 可以改写成: SELECT A.PUB_NAME
FROM PUBLISHERS A LEFT JOIN TITLES B ON B.TYPE = ‘BUSINESS’ AND
A.PUB_ID=B. PUB_ID WHERE B.PUB_ID IS NULL

 

(2)

 

SELECT TITLE FROM TITLES 

WHERE NOT EXISTS 

 (SELECT TITLE_ID FROM SALES 

WHERE TITLE_ID = TITLES.TITLE_ID)

 

可以改写成:

 

SELECT TITLE 

FROM TITLES LEFT JOIN SALES 

ON SALES.TITLE_ID = TITLES.TITLE_ID 

WHERE SALES.TITLE_ID IS NULL

 

B、 如果保证子查询没有重复 ,IN、EXISTS的相关子查询可以用INNER JOIN
代替。比如:

 

SELECT PUB_NAME 

FROM PUBLISHERS 

WHERE PUB_ID IN

 (SELECT PUB_ID 

 FROM TITLES 

 WHERE TYPE = ‘BUSINESS’)

 

可以改写成:

 

SELECT A.PUB_NAME –SELECT DISTINCT A.PUB_NAME 

FROM PUBLISHERS A INNER JOIN TITLES B 

ON        B.TYPE = ‘BUSINESS’ AND

A.PUB_ID=B. PUB_ID

 

(3)

 

C、 IN的相关子查询用EXISTS代替,比如

 

SELECT PUB_NAME FROM PUBLISHERS 

WHERE PUB_ID IN

(SELECT PUB_ID FROM TITLES WHERE TYPE = ‘BUSINESS’)

 

可以用下面语句代替:

 

SELECT PUB_NAME FROM PUBLISHERS WHERE EXISTS 

(SELECT 1 FROM TITLES WHERE TYPE = ‘BUSINESS’ AND

PUB_ID= PUBLISHERS.PUB_ID)

 

D、不要用COUNT(*)的子查询判断是否存在记录,最好用LEFT
JOIN或者EXISTS,比如有人写这样的语句:

 

SELECT JOB_DESC FROM JOBS 

WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID)=0

 

应该改成:

 

SELECT JOBS.JOB_DESC FROM JOBS LEFT JOIN EMPLOYEE  

ON EMPLOYEE.JOB_ID=JOBS.JOB_ID 

WHERE EMPLOYEE.EMP_ID IS NULL

  

SELECT JOB_DESC FROM JOBS 

WHERE (SELECT COUNT(*) FROM EMPLOYEE WHERE
JOB_ID=JOBS.JOB_ID)<>0

 

应该改成:

 

SELECT JOB_DESC FROM JOBS 

WHERE EXISTS (SELECT 1 FROM EMPLOYEE WHERE JOB_ID=JOBS.JOB_ID) 

 

#define SESSION_ID_LEN_MIN    1
#define SESSION_ID_LEN_MAX    256

在图4中,只是在temp变量的最后加上一个初始化为零的斌值,当编译器看到这段代码时,会生成代码对temp所指向的全部内存即64个字节)进行置零初始化。如此一来就省去了对memset()函数的调用,从而达到提高效率的目的。

“问题在于这是个无法预料的强制性静默转换,很容易就忽略了。”匿名

七:尽量使用索引

 

建立索引后,并不是每个查询都会使用索引,在使用索引的情况下,索引的使用效率也会有很大的差别。只要我们在查询语句中没有强制指定索引,

 

索引的选择和使用方法是SQLSERVER的优化器自动作的选择,而它选择的根据是查询语句的条件以及相关表的统计信息,这就要求我们在写SQL

 

语句的时候尽量使得优化器可以使用索引。为了使得优化器能高效使用索引,写语句的时候应该注意:

 

(1)

 

A、不要对索引字段进行运算,而要想办法做变换,比如

 

SELECT ID FROM T WHERE NUM/2=100

 

应改为:

SELECT ID FROM T WHERE NUM=100*2

 

SELECT ID FROM T WHERE NUM/2=NUM1

 

如果NUM有索引应改为:

SELECT ID FROM T WHERE NUM=NUM1*2

 

如果NUM1有索引则不应该改。

 

(2)

 

发现过这样的语句:

 

SELECT 年,月,金额 FROM 结余表  WHERE 100*年+月=2010*100+10

 

应该改为:

SELECT 年,月,金额 FROM 结余表 WHERE 年=2010 AND月=10

 

B、 不要对索引字段进行格式转换

 

日期字段的例子:

 

WHERE CONVERT(VARCHAR(10), 日期字段,120)=’2010-07-15′

 

应该改为

 

WHERE日期字段〉=’2010-07-15′   AND   日期字段<‘2010-07-16’

 

ISNULL转换的例子:

 

WHERE ISNULL(字段,”)<>”应改为:WHERE字段<>”

WHERE ISNULL(字段,”)=”不应修改

WHERE ISNULL(字段,’F’) =’T’应改为: WHERE字段=’T’

WHERE ISNULL(字段,’F’)<>’T’不应修改

 

(3)

 

C、 不要对索引字段使用函数

 

WHERE LEFT(NAME, 3)=’ABC’ 或者WHERE SUBSTRING(NAME,1, 3)=’ABC’

 

应改为: WHERE NAME LIKE ‘ABC%’

 

日期查询的例子:

 

WHERE DATEDIFF(DAY, 日期,’2010-06-30′)=0

应改为:WHERE 日期>=’2010-06-30′ AND 日期 <‘2010-07-01’

 

WHERE DATEDIFF(DAY, 日期,’2010-06-30′)>0

应改为:WHERE 日期 <‘2010-06-30’

 

WHERE DATEDIFF(DAY, 日期,’2010-06-30′)>=0

应改为:WHERE 日期 <‘2010-07-01’

 

WHERE DATEDIFF(DAY, 日期,’2010-06-30′)<0

应改为:WHERE 日期>=’2010-07-01′

 

WHERE DATEDIFF(DAY, 日期,’2010-06-30′)<=0

应改为:WHERE 日期>=’2010-06-30′

 

D、不要对索引字段进行多字段连接

 

比如:

WHERE FAME+ ‘. ‘+LNAME=’HAIWEI.YANG’

 

应改为:

WHERE FNAME=’HAIWEI’ AND LNAME=’YANG’

 

char g_SessionId [SESSION_ID_LEN_MAX];

example.c
00141: #define MAX_MSK_OCTET_LEN         64
00142: char temp[MAX_MSK_OCTET_LEN] = {0};
图4

“JS应该就该情况作异常抛出处理。” crgwbr

八. 多表连接条件与索引选择

 

A、多表连接的时候,连接条件必须写全,宁可重复,不要缺漏。

 

B、连接条件尽量使用聚集索引

 

C、注意ON、WHERE和HAVING部分条件的区别

 

ON是最先执行,
WHERE次之,HAVING最后,因为ON是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,WHERE也应该比
HAVING快点的,因为它过滤数据后才进行SUM,在两个表联接时才用ON的,所以在一个表的时候,就剩下WHERE跟HAVING比较了

 

考虑联接优先顺序:

 

(1)INNER JOIN

(2)LEFT JOIN (注:RIGHT JOIN 用 LEFT JOIN 替代)

(3)CROSS JOIN

 

int save_session_id (char
*_session_id, int _length)
{
if (_length <
SESSION_ID_LEN_MIN ||
       _length >=
SESSION_ID_LEN_MAX) {
return ERROR;
   }

显然,要运用好编程语言的特性,需要对编程语言有更为深入的理解,而不能只是局限于一些入门书籍中所介绍的知识。尽管,运用编程语言的特性所带来的效率接高对于现在强大的处理器而言可以忽略不计,但它更提体现了我们的专业性
—— 对于编程语言的娴熟驾驭!

“用+来进行字符连接简直是个噩梦。” Matteo Riva

九. 其它

 

A、在IN后面值的列表中,将出现最频繁的值放在最前面,出现得最少的放在最后面,减少判断的次数

 

B、注意UNION和UNION ALL的区别。–允许重复数据用UNION ALL好  

 

C、注意使用DISTINCT,在没有必要时不要用

 

 D、TRUNCATE TABLE 与 DELETE 区别

 

 E、减少访问数据库的次数

 

还有就是我们写存储过程,如果比较长的话,最后用标记符标开,因为这样可读性很好,即使语句写的不怎么样但是语句工整,C#
有region

 

sql我比较喜欢用的就是

 

–startof  查询在职人数

     sql语句

  –end of

      

正式机器上我们一般不能随便调试程序,但是很多时候程序在我们本机上没问题,但是进正式系统就有问题,但是我们又不能随便在正式机器上操作,那么怎么办呢?我们可以用回滚来调试我们的存储过程或者是sql语句,从而排错。

 

BEGIN TRAN

 UPDATE a SET 字段=”

ROLLBACK

       

作业存储过程我一般会加上下面这段,这样检查错误可以放在存储过程,如果执行错误回滚操作,但是如果程序里面已经有了事务回滚,那么存储过程就不要写事务了,这样会导致事务回滚嵌套降低执行效率,但是我们很多时候可以把检查放在存储过程里,这样有利于我们解读这个存储过程,和排错。

 

BEGIN TRANSACTION  

–事务回滚开始       

 

–检查报错

 IF ( @@ERROR > 0 )     

        BEGIN   

    

–回滚操作

ROLLBACK TRANSACTION       

RAISERROR(‘删除工作报告错误’, 16, 3)        

     RETURN         

      END         

 

–结束事务

  COMMIT TRANSACTION     

        

好久没有写博文了,工作项目一个接一个,再加上公司人员流动,新人很多事情接不下来,加班成了家常便饭,仓促写下这些希望对大家有帮助,不对的也欢迎指点,交流互相提高。

 

有错误的地方欢迎大家拍砖,希望交流和共享。

|转载自:cnblog
|原文链接:
我们做软件开发的…

   memcpy (g_SessionId, _session_id, _length);
   g_SessionId [_length] = ‘\0’;

本文出自 “至简李云”
博客,请务必保留此出处

2. Perl:模块必须返回TRUE值

return SUCCESS;
}

问题描述:

这段代码从功能上来说没有任何的问题,但其中存在一个可维护性的问题。这个问题就是改动后的“>=”造成的。

绝大多数情况下,Perl模块在结束时候,都必须以1;语句来结尾,否则,如果最后一条语句的返回值不是TRUE,系统就会报错了。

先抛开编程语言的语法,如果某个数学变量的最大值是Y,那么Y是这个变量的有效值吗?笔者的理解是:这个值应当是变量的有效取值。现在回头看一看前面的改动,其中将最大值当作是一个无效的取值,这显然违背了通常意义上对最大值的理解。

成因分析:

为什么要指出这个“小小”的最大值问题呢?要知道一个好的编程习惯应尽可能地让所编写的程序的语义不会与读者的常识相悖。对于上面更改后的代码,当程序的读者读到“>=”时,很可能停下来思考一下“为什么不能等于最大值呢?”。可以想象到的是,读者得查看一下g_SessionId数组的大小是多少,然后“哦,这是因为数组的大小是SESSION_ID_LEN_MAX,但数组的定义将字符串中的结束符‘\0’也计算在内的,所以_length的大小不能等于SESSION_ID_LEN_MAX,否则,最后的那个结束符没有地方放了”。

Perl模块中包含了初始代码和子程序。当模块文件被载入时,Perl会根据是否返回TRUE来判断代码是否成功执行。即使没有初始代码,Perl仍然期望最后的语句需返回TRUE,否则会报错。

前面的程序所存在的一根本问题是将通常的公共语言与编程语言揉在了一起,从而造成所编写出来的程序不容易理解,进而有可能造成维护上的麻烦。试想想,SESSION_ID_LEN_MAX应当包括最后的那个结束符吗?我认为不应当包括,最后的结束符是从C语言的层面去看而存在的。那如何对程序做进一步的更改,从而提高可读维护)性呢?下面是推荐的更好方法。

网友们的看法:

#define SESSION_ID_LEN_MIN    1
#define SESSION_ID_LEN_MAX    255

“这个通常让我有不安的感觉。” Drew Hall

char g_SessionId [SESSION_ID_LEN_MAX + 1];

“这是最无实用价值的用法了。”Schwern

int save_session_id (char
*_session_id, int _length)
{
if (_length <
SESSION_ID_LEN_MIN ||
       _length > SESSION_ID_LEN_MAX) {
return ERROR;
   }

3. C/C++:三字母词用法

   memcpy (g_SessionId, _session_id, _length);
   g_SessionId [_length] = ‘\0’;

问题描述:

return SUCCESS;
}

举例来说,系统看到??!会把它自动转为|,看到??(会转为[。这很容会引起造成意想不到的结果,并且会大大降低代码的可读性。

这一改动非常的简单,就是在定义g_SessionId数组时,在其大小后面增加一个“+
1”,用于消化掉C语言中的字符串应以‘\0’结束这一特性。另外,让SESSION_ID_LEN_MAX减一以表示不包含字符串中的结束符。这种方法的好处是:
1)没有违背公共语言中对最大值的理解,即最大值是一个可取的有效值。
2)可以采用一致的语义来编写程序,后继的维护人员可以很容易的理解,进而不容易出错。

成因分析:

这一编程习惯给我们的启示是:程序员在编写程序时,应当尽可能站在一个不懂编程语言特性的角度去思考。这种方式就是要求程序员不要将不同的语言编成语言和通用的公共语言)混在一起,从而造成可读维护)性问题。

早期进行编程时,键盘上还不能直接打出某些特殊字符,例如大括号。因此用了这种间接的方法。

本文出自 “至简李云”
博客,请务必保留此出处

网友们的看法:

#define SESSION_ID…

“博学如谷歌,也一定看不懂什么是??!??!” Isaac

“自1977年有了三字母词,C就变得晦涩难懂了。”Martin Beckett

4. PHP:大小写敏感处理

问题描述:

PHP对大小写处理比较混乱,有些地方区分,有些地方不区分。例如:变量名,常量名区分;函数名,方法名,类名不区分。

成因分析:

很可能是PHP从CGI脚本集发展成成熟编程语言过程中出现的人工产品。

网友们的看法:

“这是为什么PHP程序员习惯用下划线进行函数命名,而不是采取驼峰命名法的原因。”paperstreet7

“在PHP中,一切皆有可能!”Grzechooo

5. Ruby:0作为真值

问题描述:

在Ruby中,0值等同于TRUE值。这对有C,Python基础的程序员来说不可不谓是一场噩梦。

成因分析:

只有布尔值FALSE和nil等价于FALSE,其余的都等同于TRUE。0与1,2,3等都会被相同对待。

网友们的看法:

“这简直是让人抓狂,虽然初衷是善意的。”Chris Lutz

“0==true!我这个C语言脑袋都快崩溃了!”Kenny

6. Python:以空格数进行层次划分

问题描述:

不同于采用关键字或标点符,PY中采用缩进层级来进行层次划分,以明确每一行代码的位置。不正确的空格数(或空格和换位符数不一致)都可能造成程序报错。

成因分析:

PY作者的意图是希望代码更为可读,减少不必要的输入,并希望程序员本身应该承担起维护代码清晰度的责任。

网友们的看法:

“由衷地说,这是使我对PY敬而远之的根本原因。”wazoox

“如果我们真的需要类似的强制机制,我们是不是真的太懒了!”Joris Meys

7. C:数组索引工作模式等同于指针

问题描述:

在C中,a[i]和i[a]是可以互换的,两个写法都能得出一样的结果。

成因分析:

在C中,对内存块而言,数组与指针是无差别的,就是说:

a[i] = *(a + i) = *(i + a) =i[a]。

网友们的看法:

“在C语言混乱代码比赛中,这毫无价值可言。”Confusion

“我想这正正揭露了C语言的核心,指针和更直接地与内存打交道。”Michael Neale

8. Perl’s:预定义变量

问题描述:

Perl有一份很长很长的特殊变量列表,里面的名字都是十分繁杂的(尽管有对应的长英文单词)。因此,除非是Perl资深开发人员,否则反复翻阅Perl文档是常有的事。

成因分析:

这些变量都有不同的含义,例如:进程ID($$),错误信息($@),正则表达式匹配($^R)。

网友们的看法:

“十分令人懊恼!”MatrixFrog

“对精简型开发者可能是福音。”niXar

“这些变量的问题是:无法通过谷歌查找得到!” malvim

9. JavaScript:自动分号插入

问题描述:

JS使用分号作为语句结束的标志,并且会自行插入,即使是代码断行的情况。因此会常常导致错误的出现。

成因分析:

自动化的本意是为了带来便利,特别是对新手来说。

网友们的看法:

“如果我们设计语言的特性时,老把用户看成是傻瓜,那是会出问题的。”Rob Van
Dam

“自动分号插入是JS最让人头疼的地方之一。” fennec

10. Java:自动装箱(autoboxing)与Integer缓存

问题描述:

Java会自动把基础类型数据转为对象(自动装箱),例如把int转为一个Integer对象。同时默认地,缓存Integer对象的取值为-128到127。这样的话,在使用==来比较两个相同取值Integer对象时会出现问题(在-128和127之内是TRUE,其余的是FALSE)

成因分析:

自动装箱机制减少了代码输入量,同时Integer缓存提升了处理速度。

网友们的看法:

“还好我只是一名C#程序员。” Will

“这不算什么错误,反而给了我们一个使用原始类型(如:booleans)进行数字处理的理由。”RaviWallau

您可能感兴趣的文章:

  • 8种类型极品程序员,不知你属于哪一种?
  • 关注程序员健康:程序最需要注意的几件事

相关文章