微软资深软件工程师:阅读代码真的很难
“不喜欢豆角”通过精心收集,向本站投稿了4篇微软资深软件工程师:阅读代码真的很难,以下是小编帮大家整理后的微软资深软件工程师:阅读代码真的很难,欢迎大家收藏分享。
篇1:微软资深软件工程师:阅读代码真的很难
Escalation的工程师JeremyK在他博客中问到:
你是怎么教人们快速深入挖掘不熟悉的代码(不是自己所写的)?我学习如何编程的方法很传统 —— 自己动手编码。但我现在很纠结:到底是集中精神阅读源码,还是自己编写。对我而言,似乎唯一有效的方法就是自己写过。
不是和Jeremy开玩笑,写代码的确没有读代码难。
首先,我同意你的看法,几乎很少有人能读代码但不会写代码。这不像自然书面语或口语,理解他人的意思并不需要去理解他们为什么要那样说。比如,如果我说:
“写代码有两种方式:一种严格且详细,另一种模糊且草率。前者生成简洁分层的婚礼蛋糕,后者却是意大利面条。”
上面这句话产生一个平衡且幽默的效果,但即使听众和读者不理解我使用“零照应”和“并列句”这样的文字技巧,也会理解我要说的意思。但是说到代码,既要从代码本身中理解代码作者的意图,又要理解代码产生的预计效果,这两者都极为重要。
Eric Lippert因此,我又回到那个问题了,有些人需要快速切入代码,但不需要动手写代码,那我们如何编写适合这些人的代码?
下面是我在编写代码时,尽力去做的事,目的就是使其他人能轻松阅读:
1. 使代码遵从工具。Object Browsers和Intellisense虽然很好,但我告诉你,我是守旧派。如果找不到我想要的,我会不高兴。什么使得代码成为可查询的呢?
像”i”这样的变量名不好。如果没有明确的错误提示,你就无法轻易查找代码。
避免使用是其他名字前缀的名字。比如,在代码中有个“perfExecuteManifest”,如果再有一个“perfExecuteManifestInitialize”,这就会让我抓狂,因为每次在源码中查询前者时,我不得不费力地过滤掉后者所有的实例。
“临时传递数据”(tramp data)应使用相同的名字。所谓“临时传递数据”(tramp data),就是指那些传递给方法A的变量,还要传给方法B的变量。这两类变量实际上是相同的,所以如果它们有着相同的名字,则更好。
别用宏来重命名东西。如果有个方法叫get_MousePosition,那别这样GETTER(MousePosition)来声明该方法。因为我会找不到实际的方法名。
Shadowing会引起很多问题,请不要用它。
2. 坚持使用一种命名模式。如果你打算用匈牙利命名法,那就坚持并广泛使用,否则将适得其反。使用匈牙利命名法来记录数据,而不是存储类型;记录普遍事实,而不是临时条件。
3. 使用断言来记录先决条件(preconditions)和后置条件(postconditions)。
4. 别缩写英文单词。确切来说,别缩写成稀奇古怪的形式。在脚本引擎中,有个变量名叫“NME”,这让我非常抓狂!它应当叫“VariableName”。
5. C语言标准运行时库的设计不是很优秀。别去效仿它。
6. 别写“聪明”的代码;当代码出现问题,维护代码的程序员没时间去理解你的聪慧。(编注:这条建议即为:编写可维护的代码,详情可参见《明星软件工程师的10种特质》中的第8点。)
7. 理解编程语言特性的设计初衷,使用这些特性去做它们适合完成的工作,而不是它们能做到的工作。例如:别把异常当做一般的流控制机制来使用(即便你能做到),而应该用它们来报告错误。别强制把接口指针转换成类指针,即便你知道这样没问题。
8. 按功能单元划分源码树,而不是按组织结构。比如:我目前所在团队中,有2个根子目录的名字是“Frameworks”和“Integration”,这是两个团队的名字,
不巧的是,Frameworks团队名下有一个叫“Adaptor”的子目录,而“Adaptor”却是Integration的子目录,这就非常令人迷惑。同理,(如果)有着相同子目录的不同的子树,有些是客户端的组件,有些是服务端的组件;有些是管理组件,有些是非管理组件;有些是处理型组件,有些是非处理型组件;有些是零售组件,有些内部测试工具。这就会乱七八糟的。
当然,我实际上根本没有回答Jeremy的问题——如何调试不是我写的代码?
这取决于我的目的。如果我只是因为一个bug,而深挖一段具体的代码,我会在调试器中逐步跟踪所有代码,写下我“走过”的调用分支,记录下哪些方法是特定数据结构的“生产者”,哪些方法是“消费者”;我也会仔细盯着输出窗口,查看出现的有用信息;还要打开异常捕捉器,因为异常通常是问题所在。设置断点;我会记录所有和我上面建议相反的地方,因为这些东西很可能误导了我。
如果我想在理解一段代码后修改它,我通常是从代码头部开始,或者先查找公共方法。我要知道类是如何实现的,它是如何扩展的,它的作用,它是如何嵌入整个代码中的?我会尽力理解这些东西后,才去了解这些特定部分(代码)是如何实现的。这耗时虽更长些,但如果你准备改动复杂代码,你应当那样做。
昨天,我对于这个问题思考了好一会,还跟Larry Osterman进行了讨论,终于想出了一些也许会在阅读和调试别人的代码时有用的建议。
首先,你正在调试的机器代码,很有可能会与源代码不匹配,或者只是因为你得到的源代码不是最新的,或者是因为代码被过度优化以至于源代码和二进制文件之间的关系变得不够明显——像瑞士乳酪那样松散,又或者是因为你遇到符号表错误等等。我当然不是个汇编程序员,但我了解必要的汇编知识和调用规则,这样我可以试着调试那些源代码和二进制之间不是那么同步的代码。即使知道“‘this”指针很有可能在ECX寄存器中”可以对正在进行的调试会话大有帮助。
第二,你还记得那部卡通片Calvin and Hobbes中Calvin偷偷溜到Hobbes的身后吓他,然后学到了吓一只正在睡觉的老虎并不明智吗?Calvin喃喃自语道:“我得开始聆听那没有声音却不停冒出的疑问才行。”
那部卡通片改变了我的生活。我意识到自己常常会犯一个错误,在回顾之前我应该能够提前意识到,但不知因为什么,我却不顾没有声音却不停冒出的疑问而执意地冒失地继续下去。我决定绝不让自己的墓碑上写着“此人死于愚蠢的但本可以完全避免的事情上。”
相信你的头脑。是的,预感有可能是错的,但当它真的是错误的时候,发现它是错的并不需要很大的代价。而如果它是对的,你可以省很多时间。当我在调试我不知道的代码时,我试着去聆听那些没有声音却不停冒出的疑问。在内存显示窗口有一个字节瞬间变成了红色,表明它已经改变了。嗯。在这次函数调用中我是否期望内存发生改变?其自身拥有的内存是改变了,还是只是堆栈错误?嗯,这个局部变量突然变值—这是不是个符号错误?这个变量是否是shadow变量而我则刚刚离开了内部作用域?顺着这类的线索追踪下去。
译者注:shadow变量:当一个变量所在的作用域之外还有一个同名的变量,称为shadow变量;shadow变量只在自己的作用域有效,详细解释和示例参见variable shadowing.
最近我凭直觉在Excel中找到了一个极不起眼的漏洞—我有发现有一个数位的堆分配的缓冲器通过了一个函数但其长度没有通过。嗯。可疑!果真,只要你追踪所有的逻辑,你就会发现更深十级的函数对于缓冲范围作了错误的假设并且造成了一个错误。幸好这个假设十分保守,受到了许多限制,所以没有造成缓冲溢出的后果。还有,幸好这个漏洞极不起眼—一般用户都不会马上就陷入其中。
那么我的第三个建议又会是什么呢?昨天我说过,你需要知道代码是干什么的和开发者为什么要让它干这些。但你还需要知道更多信息—你还要知道代码是怎样随着时间的流逝而在发生改变的。显然在这个漏洞中,程序一开始占用一小块固定大小的缓冲。有人修改了缓冲区分配代码以分配可变范围的缓冲区,但却忘记了这代码所表示的程序是写来假定一个固定的小范围缓冲的。漏洞的发生通常由于在其它合理的代码重整中发生的极小的错误。明显地,没有人会把这样的漏洞写进从一开始就已经有了可变范围的缓冲区代码的代码。当你在阅读一片段的代码时,试着了解不变量将会是什么,然后想想那些情况会违反常量的假定。
当然,要想知道那些没有声音却不停冒出的疑问来自哪里是很困难的,而且可能教也教不来。不管你怎样试图克服它,它都会很困难。
篇2:微软改变态度提高软件代码安全性
在“BlackHat”安全会议上被弄得灰头土脸后,微软用了年半的时间努力将其设计文化转向使安全成为其最优先的任务,
最近,有一些 因利用微软软件中的缺陷兴风作浪而遭到逮捕。但据许多计算机安全专家和客户称,更重要的是,去年,微软在改进代码质量方面取得了重大进展。这在客观上提高了犯罪分子利用微软软件中的缺陷兴风作浪的门槛。现在,微软似乎有理由举杯庆祝了。
在上周四、五,微软在其总部举行了“BlueHat”会议,邀请独立的安全研究人员参加。在会议的第一天,研究人员向微软的一些高级官员展示了他们的研究成果。在第二天,微软约9000名编程人员中的500多人参加了会议。
互联网安全系统公司的入侵探测专家梅诺首先赞扬了微软在解决传统计算机威胁方面的成就。但他列举了Windows操作系统处理外设方式中的一个基本错误,从理论上来说,通过将便携式设备插入计算机端口中, 能够在个人电脑中注入恶意软件。他还指出,Xbox60游戏机的安全也存在问题。
研究人员的演示表明,在提高软件安全性方面,微软还有许多工作要做。但是,与会者也都一致认为,在放慢病毒、蠕虫、垃圾邮件、间谍件的传播速度方面,微软已经取得了一些进展。
独立计算机安全研究人员卡明斯基说,微软做得并非至善至美,但与竞争对手相比,它已经取得了重大进展。
微软与其批评者的接触表明了它在计算机安全方面态度的变化。这种转变是在年前开始的,当时,微软负责安全事务的资深官员乔治参加了“BlackHat”会议。
尽管在会上发现微软受到了广泛攻击,乔治第二年又参加了这一会议,并开始赞助一次聚会,与安全研究人员开始接触。后来,他又了新的想法。
他对另一名微软高官说,我们在干什么?这将酿成一场灾难。今年,微软走得更远,它邀请外界的计算机安全研究人员到其总部为编程人员布道,
以前,微软对安全研究人员一直奉行“不接触”的政策。微软的态度在00、发生了变化,当时,利用微软软件中缺陷的Blaster和Slammer蠕虫在全球范围内疯狂传播,并威胁到了它与消费者和企业客户的关系。
当时,情况非常严重,微软不得不将其开发活动中止了二个月,对开发人员进行安全编程方面的培训。
卡明斯基表示,微软的这些变化是绝对必要的。他说,安全问题会扼杀Windows。微软愿意与其安全批评者直接接触给他们留下了深刻印象。
计算机安全研究人员斯普尔曼说,战舰正在开始转向。我在这里这件事儿就表明,微软已经发生了多么大的变化,它已经开始明白,我们社区与它同样关心安全。
但梅诺警告称,微软正在濒临攻击将更令人烦恼的时代。他指出,移动设备世界将使目前的安全措施完全不适用。这类设备将使远程 能够跳过防火墙,从一个网络跳到另一个网络,访问企业网络。
他说,攻击的性质将不再是Blaster等全球性蠕虫,因为计算机犯罪活动越来越倾向于盈利,一个缺陷能够给计算机地下社会带来多达5万美元的经济回报。有目标的攻击活动越来越多了。
微软的官员和安全研究人员都表示,00年WindowsXP的发布极大地提高了系统的安全性。微软的官员还将发布的安全公告数量的减少作为新设计理念已经产生效果的证据。
微软说,在年半的时间里,针对Windows000Server的安全公告有69个,同期针对WindowsServer00的安全公告有个。
在发布后的59天中,针对00年版OfficeXP的安全公告有个,同期针对Office00的只有6个。在于去年6月份结束的一年中,针对WindowsXP的安全公告有5个,同期内针对WindowsXP的安全公告只有8个。
篇3:摩托罗拉软件工程师笔试真题
摩托罗拉软件工程师笔试真题
题型:选择,程序填空,智力题,编程题
题目主要有:
1.数字电路中的`与非门等问题;
2.网络基本知识;
3.移动通讯网络基本知识;
4.JAVA虚拟机垃圾收信问题;
5.JAVA程序分析题;
6.C/C++基本问题;
7.Little-ending, Big-ending问题, 及Intel和Sun处理器各自采用的ENDING问题;
8.指针, 数组问题;
9.逻辑/离散题;
11.程序填空题(C/C++)
12.智力题;
13.C/C++编程题
A. 输出19行的棱形
B. 查找字符串
篇4:思迁数码科技Java软件工程师笔试真题
思迁数码科技Java软件工程师笔试真题
选择题
1:Which statements about Java code security are not true?
A.The bytecode verifier loads all classes needed for the execution of a program.
B.Executing code is performed by the runtime interpreter.
C.At runtime the bytecodes are loaded, checked and run in an interpreter.
D.The class loader adds security by separating the namespaces for the classes of the local file system from those imported from network sources.
2:What is the result when you compile and run the following code?
public class Test
{
public void method()
{
for(int i = 0; i < 3; i++)
{
System.out.print(i);
}
System.out.print(i);
}
}
Choices:
What is the result when you compile and run the following code?
public class Test
{
public void method()
{
for(int i = 0; i < 3; i++)
{
System.out.print(i);
}
System.out.print(i);
}
}
Choices:
A.0122
B.0123
C.Compilation error
D.None of these
3:
Give the following code:
public class Example{
public static void main(String args[] ){
int l=0;
do{
System.out.println(“Doing it for l is:”+l);
}while(--l>0)
System.out.println(“Finish”);
}
}
Which well be output:
Give the following code:
public class Example{
public static void main(String args[] ){
int l=0;
do{
System.out.println(“Doing it for l is:”+l);
}while(--l>0)
System.out.println(“Finish”);
}
}
Which well be output:
A.Doing it for l is 3
B.Doing it for l is 1
C.Doing it for l is 2
D.Doing it for l is 0
4:Math.round(11.5)等於多少?
A.11
B.12
C.11.5
D.none
5:
What will happen when you attempt to compile and run the following code?
int Output = 10;
boolean b1 = false;
if((b1 == true) && ((Output += 10) == 20))
{
System.out.println(“We are equal ” + Output);
}
else
{
System.out.println(“Not equal! ” + Output);
}
Choices:
What will happen when you attempt to compile and run the following code?
int Output = 10;
boolean b1 = false;
if((b1 == true) && ((Output += 10) == 20))
{
System.out.println(“We are equal ” + Output);
}
else
{
System.out.println(“Not equal! ” + Output);
}
Choices:
A.Compilation error, attempting to perform binary comparison on logical data type
B.Compilation and output of “We are equal 10”.
C.Compilation and output of “Not equal! 20”.
D.Compilation and output of “Not equal! 10”.
6:
What will happen when you attempt to compile and run the following code?
(Assume that the code is compiled and run with assertions enabled.)
public class AssertTest{
public void methodA(int i){
assert i >= 0 : methodB();
System.out.println(i);
}
public void methodB(){
System.out.println(“The value must not be negative”);
}
public static void main(String args[]){
AssertTest test = new AssertTest();
test.methodA(-10);
}
}
What will happen when you attempt to compile and run the following code?
(Assume that the code is compiled and run with assertions enabled.)
public class AssertTest{
public void methodA(int i){
assert i >= 0 : methodB();
System.out.println(i);
}
public void methodB(){
System.out.println(“The value must not be negative”);
}
public static void main(String args[]){
AssertTest test = new AssertTest();
test.methodA(-10);
}
}
A.it will print -10
B.it will result in AssertionError showing the message-“the value must not be negative”.
【微软资深软件工程师:阅读代码真的很难】相关文章:
1.软件工程师论文
2.软件工程师简历
3.软件工程师求职信
4.软件工程师面试题
10.软件工程师的工资待遇






文档为doc格式