qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

修复bug的12个关键步骤

boss:那么,你需要多长时间来修复这个bug?
  没有经验的程序员:给我一个小时?最多两个小时?我能马上搞定它!
  有经验的程序员:这么说吧,钓到一条鱼要多久我就要多久?!
  要多少时间才能修复bug,事先是很难知道的,特别是如果你和这些代码还素不相识的话,情况就更加扑朔迷离了。James Shore在《The Art of Agile 》一书中,明确指出要想修复问题得先知道问题的所在。而我们之所以无法准确估计时间是因为我们不知道需要多久才能发现症结的所在,只有清楚这一点,我们才能合理估计修复bug所需要花费的时间。不过,这个时候恐怕黄花菜都凉了。 Steve McConnell曾说过:
  “发现问题—理解问题—这就是程序员90%的工作。”
  很多bug都只需改动某一行代码即可。但是需要投入大量时间的是,后面还得指出怎么样才是正确的——就像我们在钓鱼的时候,得知道往哪里下诱饵,什么时候鱼儿容易上钩等等。话说bug有四种类型:第一种易寻易修复,第二种难寻易修复,第三种易寻难修复,第四种难寻难修复。最悲剧的就是最后一型的,不但“寻寻觅觅,凄凄凉凉戚戚”,哪怕终于千辛万苦滴水穿石,也只能在那边不由自主地抓耳挠腮,无奈叹一句“路漫漫其修远兮”。可以这么说,除非是新鲜出炉的代码,不然让你找bug就跟瞎子摸象一样——糊里糊涂,不知道归属于哪种bug类型。
  查找和修复bug
  你知道“查找和修复bug”意味着什么吗?没错,就是调试!不断的调试,无数次的调试!Paul Butcher通过大量工作,总结出以下结构化的步骤:
  1.明确目的。仔细查阅异常报告,确定是否是个bug,找出各种有用的信息发现问题的症结,予以重现。再次检查是否与报告发生重复。如果发生重复,那看看曾经的相关人员是如何处理的。
  2.准备工作——找出正确的代码,用排除法清理工作区域。
  3.匹配测试环境。如果客户正在操作计算机配置,那么此过程可以跳跃。
  4.明确代码的用途,确保现有测试工具一切正常。
  5.好了,现在可以出发钓鱼去咯——重现和诊断错误。如果你不能做到重现,那你就不能证明你已经完成修复工作。
  6.编写测试案例,或者通过现成的测试案例来捕获bug。
  7.进入修复模式——请务必确保不会影响到其他任何部分。但是,在开展修复工作之前,可能你还要包揽重构工作,因为只有这样,你才能无所顾忌地捣鼓代码。而且事后回归测试,还能确保你不会加入任何新的bug。
  8.整理代码。通过一步一步重构,让你的代码更易于理解,更安全。
  9.找别人来审查一下,当局者迷旁观者清。
  10.再次检查此修复过程。
  11.试着不从主线出发,以检查这些bug是否会影响其他支线。合并这些变化,处理代码中的差异,回顾所有的审查和测试等工作。
  12.思考。好好想一想哪里错了以及为什么错了?为什么你的修复会起效?这种类型的bug还会出现在哪里?在《 The Pragmatic Programmer》一书中,Andy Hunt 和Dave Thomas也如是指出“如果一个bug需要耗费你很多时间,那么一定要好好弄清楚原因”。此外,还需要思考的是,怎么做才能吸取经验教训,将来在类似的问题上不再栽跟头?以及,我们采用的方法、使用的工具是否还有可以改进的地方?以及这些bug的影响和严重程度。
  找到bug,还是修复bug,哪个需要更多时间?
  或许建立一个测试环境、重现问题和测试bug所需的时间,要远远多于找到bug和修复bug的时间。不过对于一小部分显而易见的bug,找到它们很简单——不过修复起来可能就不尽如人意了。
  在《Making Software》一书中,有一章主要是探讨“大部分的软件漏洞的来源”,Dewayne Perry分析认为,相较于修复,发现bug(包括理解bug和重现bug)所需时间更长。有研究表明,大多数的bug(差不多有3/4)既易于发现又易于修复:5天或许更少(这是基于大规模实时系统通过重量级SDLC、大量审查和测试得出的数据)。但是也有很恶心的bug,即便你可以轻轻松松揪到它,还是还得“呕心沥血”才能修复好。
  发现/修复修复时间<=5天修复时间>5天
  能重现问题72.5%18.4%
  难以重现或根本没法重现5.9%3.2%
  所以如果你打赌说你能很快修复bug,大多数情况下你还真没说错。不过当你打赌输了的时候,那么,嘿嘿,就意味着你有大麻烦了。
  所以,下次,boss再问什么时候能修复bug,别再傻乎乎地回答“马上就能搞定”了。

posted @ 2014-11-21 10:50 顺其自然EVO 阅读(195) | 评论 (0)编辑 收藏

TP框架集成支付宝,中转页变成gbk编码

 tp框架中集成支付宝的功能,将支付宝的demo例子存在到下图位置\Extend\Vendor\Alipay
  生成支付订单
/**
*支付订单
*/
publicfunctionpay(){
header("Content-Type:text/html;charset=utf-8");
$id=I('post.oid','','htmlspecialchars');
$DAO=M('order');
$order=$DAO->where("id=".$id)->find();
$error="";
if(!isset($order)){
$error="订单不存在";
}elseif($order['PaymentStatus']==1){
$error="此订单已经完成,无需再次支付!";
}elseif($order['PaymentStatus']==2){
$error="此订单已经取消,无法支付,请重新下单!";
}
if($error!=""){
$this->_FAIL("系统错误",$error,$this->getErrorLinks());
return;
}
$payType=I('post.payType','','htmlspecialchars');
#支付宝
if($payType=='alipay'){
$this->payWithAlipay($order);
}
}
 支付订单提交
/**
*以支付宝形式支付
*@paramunknown_type$order
*/
privatefunctionpayWithAlipay($order){
//引入支付宝相关的文件
require_once(VENDOR_PATH."Alipay/alipay.config.php");
require_once(VENDOR_PATH."Alipay/lib/alipay_submit.class.php");
//支付类型
$payment_type="1";
//必填,不能修改
//服务器异步通知页面路径
$notify_url=C("HOST")."index.php/Alipay/notifyOnAlipay";
//页面跳转同步通知页面路径
$return_url=C("HOST")."index.php/Pay/ok";
//卖家支付宝帐户
$seller_email=$alipay_config['seller_email'];
//必填
//商户订单号,从订单对象中获取
$out_trade_no=$order['OrderNum'];
//商户网站订单系统中唯一订单号,必填
//订单名称
$subject="物流服务";
//必填
//付款金额
#正常金额
$price=$order['Price'];
#测试金额
#$price=0.1;
//必填
$body=$subject;
//商品展示地址
$show_url=C('HOST');
//构造要请求的参数数组,无需改动
$parameter=array(
"service"=>"create_direct_pay_by_user",
"partner"=>trim($alipay_config['partner']),
"payment_type"=>$payment_type,
"notify_url"=>$notify_url,
"return_url"=>$return_url,
"seller_email"=>$seller_email,
"out_trade_no"=>$out_trade_no,
"subject"=>$subject,
"total_fee"=>$price,
"body"=>$body,
"show_url"=>$show_url,
"_input_charset"=>trim(strtolower($alipay_config['input_charset']))
);
Log::write('支付宝订单参数:'.var_export($parameter,true),Log::DEBUG);
//建立请求
$alipaySubmit=newAlipaySubmit($alipay_config);
$html_text=$alipaySubmit->buildRequestForm($parameter,"get","去支付");
echo$html_text;
}
支付宝回调接口
<?php
/**
*支付宝回调接口
*/
classAlipayActionextendsAction{
/**
*支付宝异步通知
*/
publicfunctionnotifyOnAlipay(){
Log::write("notify:".print_r($_REQUEST,true),Log::DEBUG);
require_once(VENDOR_PATH."Alipay/alipay.config.php");
require_once(VENDOR_PATH."Alipay/lib/alipay_notify.class.php");
$orderLogDao=M('orderlog');
//计算得出通知验证结果
$alipayNotify=newAlipayNotify($alipay_config);
$verify_result=$alipayNotify->verifyNotify();
Log::write('verify_result:'.var_export($verify_result,true),Log::DEBUG);
if($verify_result){//验证成功
//商户订单号
$out_trade_no=$_POST['out_trade_no'];
//支付宝交易号
$trade_no=$_POST['trade_no'];
//根据订单号获取订单
$DAO=M('order');
$order=$DAO->where("OrderNum='".$out_trade_no."'")->find();
//如果订单不存在,设置为0
if(!isset($order)){
$orderId=0;
}
else{
$orderId=$order['id'];
}
//交易状态
$trade_status=$_POST['trade_status'];
$log="notifyfromAlipay,trade_status=".$trade_status."alipaysign=".$_POST['sign'].'price='.$_POST['total_fee'];
$orderLog['o_id']=$orderId;
if($_POST['trade_status']=='TRADE_FINISHED'||$_POST['trade_status']=='TRADE_SUCCESS'){
#修改订单状态
if((float)$order['Price']!=(float)$_POST['total_fee']){
$data['PaymentStatus']='2';
}else{
$data['PaymentStatus']='1';
}
$DAO->where('id='.$orderId)->save($data);
}
$orderLog['pay_id']=$trade_no;
$orderLog['pay_log']=$log;
$orderLog['pay_type']='alipay';
$orderLog['pay_result']='success';
$orderLogDao->add($orderLog);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
echo"success";//返回成功标记给支付宝
}
else{
//验证不通过时,也记录下来
$orderLog['pay_log']="notifyfromAlipay,但是验证不通过,sign=".$_POST['sign'];
$orderLog['o_id']=-1;
$orderLog['pay_type']='alipay';
$orderLog['pay_result']='fail';
$orderLogDao->add($orderLog);
//验证失败
echo"fail";
}
}
}
?>
  今天在tp框架中集成支付宝功能,跳转支付宝的时候出现乱码错误。
  需要设定header("Content-Type:text/html;charset=utf-8");
  如果还有乱码查看日志信息是否出现
  NOTIC:[2]Cannotmodifyheaderinformation-headersalreadysentby(outputstartedat
  上面错误,删除错误文件开始的空格
  <emid="__mceDel"></em>

posted @ 2014-11-21 10:50 顺其自然EVO 阅读(513) | 评论 (0)编辑 收藏

测试计划与测试方案的区别

  计划:属于组织管理层面的文档,从组织管理的角度对测试活动进行规划; 方案:属于技术层面的文档,从技术的角度对测试活动进行规划。
  测试计划:
  对测试全过程的组织、资源、原则等进行规定和约束,并制定测试全过程各个阶段的任务分配以及时间进度安排,并提出对各项任务的评估,风险分析和管理需求。
  测试方案:
  描述需要测试的特性,测试的方法,测试环境的规划,测试工具的设计和选择,测试用例的设计方法,测试代码的设计方案。
  测试方案需要在测试计划的指导下进行,测试计划提出“做什么”,而测试方案明确“如何做”
  软件测试用例包括软件测试用例设计和写作。
  软件测试用例设计是从设计层面考虑,比如从功能性、可用性、安全性等方面考虑设计测试用例。
  软件测试用例写作是指软件测试用例的写作规范,包括写作格式、标识的命名规范等。 软件测试用例设计得出软件测试用例的内容,然后,按照软件测试写作方法,落实到文档中,两者是形式和内容的关系。 测试用例格式的八个基本项是:测试用例编号、测试项目、测试标题、重要级别、预置条件、输入、操作步骤、预期输出。
  一、什么是测试计划?
  所谓测试计划是指描述了要进行的测试活动的范围、方法、资源和进度的文档。它主要包括测试项、被测特性、测试任务、谁执行任务和风险控制等。
  二、什么是测试方案?
  所谓测试方案是指描述需要测试的特性、测试的方法、测试环境的规划、测试工具的设计和选择、测试用例的设计方法、测试代码的设计方案。
  三、测试计划与测试方案区别

posted @ 2014-11-21 10:43 顺其自然EVO 阅读(234) | 评论 (0)编辑 收藏

IOS开发之视图和视图控制器

 视图(View), 视图控制器(ViewController)是IOS开发UI部分比较重要的东西。在学习视图这一块的东西的时候,感觉和Java Swing中的Panel差不多。在UIKit框架中都有一个UIWindow来容纳我们的View。应用程序中几乎全部的可视控件都是UIView以及UIView的子类的实例,并且UIWindow也是UIView的子类。UIWindow可以不借助于父类视图显示在屏幕上,其余的视图都需要添加到父视图中才能显示。窗口是用来显示视图的,下面我们将会结合着实例来具体的学习一下IOS中的View和ViewController
  1.首先我们需要建一个EmptyProject来测试我们的View和ViewController. 我们空工程的文件结构如下,我们只需在AppDelegate.m中添加我们的视图,还是那句话为了更好的理解我们的视图,所有视图的创建和配置我们都用代码编写。
  2.在学习UIView之前我们先在我们的EmptyProject中添加一个视图,看一下效果,上面的代码是为我们的EmptyProject添加一个UIWindow,是系统为我们创建的,我们接下来要放置的UIIView都是放在Window中,一般每个应用都只有一个Window,当然有的游戏会有多个应用窗口。下面的一段代码是往我们Window上添加一个主视图,通过CGRectMake来给我们新添的View定位。 CGRectMake(x, y, width, height);  配置背景颜色为greenColor,最后添加到我们的window上。
  3.界面都是视图对象,即在UIView类的实例中进行布局,UIView表示屏幕上的一块矩形区域,负责渲染矩形区域中的内容,并且响应该区域内发生的触摸事件。我们还可以把视图看做是一个视图容器,视图上面还可以添加一个子视图。往父视图中添加的SubView会被放在一个数组中。往我们SuperView中添加的SubView的坐标和index都是相对于我们的父视图来配置的。我们为上面的视图在添加一个subView,代码如下:
  运行效果如下:
  下面是iOS提供的一些管理子视图的方法,常用方法如下:
  (1) initWithFrame : 通过frame初始化视图,参数为CGRectMake(x, y, width, height);
  (2) insertSubView: atIndex: 往指定层上插入视图,哪个View调用该方法,index就是相对于谁。
  (3) insertSubView: aboveSubView: 在某个视图上插入子视图。
  (4) insertSubView: belowSubView: 在某个子视图的后面添加一个新的视图
  (5) bringSubViewToFront: 把子视图放到最前
  (6) sendSubViewToBack: 把子视图放到最后
  (7) exchangeSubviewAtIndex: withSubviewAtIndex: 交换两个视图的前后顺序
  (8) removeFromSuperview: 从父视图中移除view
  (9) -(void) addSubview: (UIView *) view 添加一个视图
  视图的层次用index来区分,这个值从0开始以步长1依次增加,index为0的时候代表视图层次的最底层,下面是苹果官方文档对Views的介绍的截图:
  视图层大致分为下面的几类
  1.容器视图
  容器视图用于增强其他视图的功能,或者为视图内容提供额外的视觉分隔,比如UIScorllView类用于显示因内容太大而无法显示在一个屏幕上的视图,也就是自动添加滚动条,入下面第一个图。UITableView类是UIScrollView类的子类,用于管理数据列表,如图二,还有其他的容器视图在这就不一一列举啦。
  2.控件
  控件用于创建大多数应用程序的用户界面。控件是一种特殊类型的视图,继承子UIControl超类,通常要绑定回调方法(比如Target-Action回调和委托回调),用于用户交互。控件包括按键,文本框,滑块,和切换开关。部分控件如下所示:
  3.显示视图
  控件和很多其他类型的视图都提供了交互行为,而另外一些视图则只是用于简单的显示信息。具有这种行为的UIKit类包括 UIImageView, UILabel, UIProgressView, UIActivityIndicatorView;下面是UIProgressView显示视图
  4.文本和Web视图
  文本和web视图为应用程序提供更为高级的显示多行文本的方法。UITextView类支持在滚动区域内显示和编辑多行文本;而UIWebView类则提供显示HTML内容的方法
  5.警告视图和动作表单
  警告视图和动作表单用于即刻取得用户的注意。 UIAlertView类在屏幕上弹出一个蓝色的警告框,而UIActionSheet类则从屏幕的底部划出动作框

 6.导航视图
  页签条和导航条和视图控制器结合使用,为用户提供从一个屏幕到另一个屏幕的导航工具。在使用是,你通常不必直接UITableBar和UINavigationBar的项,而是通过恰当的控制器接口或Interface Builder来对其进行配置,Table Bar 和 Navigation Bar如下:
  上面视图部分先就说这么多吧,那么我们的视图控制器应如何使用呢? 在本文刚开始的时候我们加入的view的代码都是在AppDelegate.m的文件里加的,其实没没那么做的,如果我们一直在上面的文件中实例化我们的各种控件,我们的应用程序代码会非常难维护。那么我们如何给一个EmptyProject添加一个视图控制器呢?上面贴啦这么的多的图片啦,接下来让我们上点代码吧!
  1.我们在一个空工程中新建一个视图控制器的类MainViewController, 让MainViewController继承于UIViewController, MainViewController.h文件的内容如下:
  #import <UIKit/UIKit.h>
  @interface MainViewController : UIViewController
  @end
  2.我们在MainViewController.m中进行我们的视图声明和实例化,代码如下:
#import "MainViewController.h"
//用延展隐藏我们的组件
@interface MainViewController ()
@property (nonatomic, strong) UIView *subView;
@end
//-------实现部分-----------
@implementation MainViewController
//主视图加载后要做的事情
-(void)viewDidLoad
{
//实例化view并添加到mainView
self.subView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 150)];
self.subView.backgroundColor = [UIColor brownColor];
[self.view addSubview:self.subView];
}
@end
  3.我们需要把我们新建的视图控制器和我们的窗口关联,在AppDelegate.m中实例化MainViewController并添加到window中,代码如下:
  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  // Override point for customization after application launch.
  self.window.backgroundColor = [UIColor whiteColor];
  [self.window makeKeyAndVisible];
  //实例化MainViewController,并添加到window
  MainViewController * mianViewController = [[MainViewController alloc] init];
  [self.window addSubview:mianViewController.view];
  return YES;
  }
  先暂且这么理解着视图和视图控制器,随着以后的深入的学习会随时更新和修改博客的。

posted @ 2014-11-21 09:38 顺其自然EVO 阅读(190) | 评论 (0)编辑 收藏

IOS开发之视图和视图控制器

 视图(View), 视图控制器(ViewController)是IOS开发UI部分比较重要的东西。在学习视图这一块的东西的时候,感觉和Java Swing中的Panel差不多。在UIKit框架中都有一个UIWindow来容纳我们的View。应用程序中几乎全部的可视控件都是UIView以及UIView的子类的实例,并且UIWindow也是UIView的子类。UIWindow可以不借助于父类视图显示在屏幕上,其余的视图都需要添加到父视图中才能显示。窗口是用来显示视图的,下面我们将会结合着实例来具体的学习一下IOS中的View和ViewController
  1.首先我们需要建一个EmptyProject来测试我们的View和ViewController. 我们空工程的文件结构如下,我们只需在AppDelegate.m中添加我们的视图,还是那句话为了更好的理解我们的视图,所有视图的创建和配置我们都用代码编写。
  2.在学习UIView之前我们先在我们的EmptyProject中添加一个视图,看一下效果,上面的代码是为我们的EmptyProject添加一个UIWindow,是系统为我们创建的,我们接下来要放置的UIIView都是放在Window中,一般每个应用都只有一个Window,当然有的游戏会有多个应用窗口。下面的一段代码是往我们Window上添加一个主视图,通过CGRectMake来给我们新添的View定位。 CGRectMake(x, y, width, height);  配置背景颜色为greenColor,最后添加到我们的window上。
  3.界面都是视图对象,即在UIView类的实例中进行布局,UIView表示屏幕上的一块矩形区域,负责渲染矩形区域中的内容,并且响应该区域内发生的触摸事件。我们还可以把视图看做是一个视图容器,视图上面还可以添加一个子视图。往父视图中添加的SubView会被放在一个数组中。往我们SuperView中添加的SubView的坐标和index都是相对于我们的父视图来配置的。我们为上面的视图在添加一个subView,代码如下:
  运行效果如下:
  下面是iOS提供的一些管理子视图的方法,常用方法如下:
  (1) initWithFrame : 通过frame初始化视图,参数为CGRectMake(x, y, width, height);
  (2) insertSubView: atIndex: 往指定层上插入视图,哪个View调用该方法,index就是相对于谁。
  (3) insertSubView: aboveSubView: 在某个视图上插入子视图。
  (4) insertSubView: belowSubView: 在某个子视图的后面添加一个新的视图
  (5) bringSubViewToFront: 把子视图放到最前
  (6) sendSubViewToBack: 把子视图放到最后
  (7) exchangeSubviewAtIndex: withSubviewAtIndex: 交换两个视图的前后顺序
  (8) removeFromSuperview: 从父视图中移除view
  (9) -(void) addSubview: (UIView *) view 添加一个视图
  视图的层次用index来区分,这个值从0开始以步长1依次增加,index为0的时候代表视图层次的最底层,下面是苹果官方文档对Views的介绍的截图:
  视图层大致分为下面的几类
  1.容器视图
  容器视图用于增强其他视图的功能,或者为视图内容提供额外的视觉分隔,比如UIScorllView类用于显示因内容太大而无法显示在一个屏幕上的视图,也就是自动添加滚动条,入下面第一个图。UITableView类是UIScrollView类的子类,用于管理数据列表,如图二,还有其他的容器视图在这就不一一列举啦。
  2.控件
  控件用于创建大多数应用程序的用户界面。控件是一种特殊类型的视图,继承子UIControl超类,通常要绑定回调方法(比如Target-Action回调和委托回调),用于用户交互。控件包括按键,文本框,滑块,和切换开关。部分控件如下所示:
  3.显示视图
  控件和很多其他类型的视图都提供了交互行为,而另外一些视图则只是用于简单的显示信息。具有这种行为的UIKit类包括 UIImageView, UILabel, UIProgressView, UIActivityIndicatorView;下面是UIProgressView显示视图
  4.文本和Web视图
  文本和web视图为应用程序提供更为高级的显示多行文本的方法。UITextView类支持在滚动区域内显示和编辑多行文本;而UIWebView类则提供显示HTML内容的方法
  5.警告视图和动作表单
  警告视图和动作表单用于即刻取得用户的注意。 UIAlertView类在屏幕上弹出一个蓝色的警告框,而UIActionSheet类则从屏幕的底部划出动作框

 6.导航视图
  页签条和导航条和视图控制器结合使用,为用户提供从一个屏幕到另一个屏幕的导航工具。在使用是,你通常不必直接UITableBar和UINavigationBar的项,而是通过恰当的控制器接口或Interface Builder来对其进行配置,Table Bar 和 Navigation Bar如下:
  上面视图部分先就说这么多吧,那么我们的视图控制器应如何使用呢? 在本文刚开始的时候我们加入的view的代码都是在AppDelegate.m的文件里加的,其实没没那么做的,如果我们一直在上面的文件中实例化我们的各种控件,我们的应用程序代码会非常难维护。那么我们如何给一个EmptyProject添加一个视图控制器呢?上面贴啦这么的多的图片啦,接下来让我们上点代码吧!
  1.我们在一个空工程中新建一个视图控制器的类MainViewController, 让MainViewController继承于UIViewController, MainViewController.h文件的内容如下:
  #import <UIKit/UIKit.h>
  @interface MainViewController : UIViewController
  @end
  2.我们在MainViewController.m中进行我们的视图声明和实例化,代码如下:
#import "MainViewController.h"
//用延展隐藏我们的组件
@interface MainViewController ()
@property (nonatomic, strong) UIView *subView;
@end
//-------实现部分-----------
@implementation MainViewController
//主视图加载后要做的事情
-(void)viewDidLoad
{
//实例化view并添加到mainView
self.subView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 100, 150)];
self.subView.backgroundColor = [UIColor brownColor];
[self.view addSubview:self.subView];
}
@end
  3.我们需要把我们新建的视图控制器和我们的窗口关联,在AppDelegate.m中实例化MainViewController并添加到window中,代码如下:
  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  // Override point for customization after application launch.
  self.window.backgroundColor = [UIColor whiteColor];
  [self.window makeKeyAndVisible];
  //实例化MainViewController,并添加到window
  MainViewController * mianViewController = [[MainViewController alloc] init];
  [self.window addSubview:mianViewController.view];
  return YES;
  }
  先暂且这么理解着视图和视图控制器,随着以后的深入的学习会随时更新和修改博客的。

posted @ 2014-11-21 09:38 顺其自然EVO 阅读(139) | 评论 (0)编辑 收藏

MySQL数据库优化技术之数据库表的设计

三范式介绍
  表的范式:只有符合的第一范式,才能满足第二范式,进一步才能满足第三范式。
  1、第一范式:
  表的列具有原子性,不可再分解。只要是关系型数据库都自动满足第一范式。
  数据库的分类:
  关系型数据库:MySQL/ORACLE/Sql Server/DB2等
  非关系型数据库:特点是面向对象或者集合
  nosql数据库:MongoDB(特点是面向文档)
  2、第二范式:
  表中的记录是唯一的,就满足第二范式。通常我们设计一个主键来实现。
  主键一般不含业务逻辑,一般是自增的;
  3、第三范式:
  表中不要有冗余数据,即如果表中的信息能够被推导出来就不应该单独的设计一个字段来存放;对字段冗余性的约束,要求字段没有冗余。
  如下表所示,符合三范式要求:
  student表
  class表
  如下表所示,不符合三范式要求:
  student表
  class表
  反三范式案例:
  一个相册下有多个图片,每个图片有各自的浏览次数,相册有总的浏览次数。
  相册浏览表
  图片表:
  如果相册浏览表没有适当的冗余,效率有影响。
  冗余比较可以得出一个结论:1对N时,冗余应当发生在1的一端。

posted @ 2014-11-21 09:26 顺其自然EVO 阅读(625) | 评论 (0)编辑 收藏

Java跳出多重嵌套循环

  在java里面,我们知道有goto这个关键字,但是实际却没有啥作用,这就让我们不像在c/c++里面能够随便让程序跳到那去执行,而break只能跳出当前的一个循环语句,如果要跳出多个循环体那么该怎么办呢。
  我们可以这样解决:
  我们可以在循环体开头设置一个标志位,也就是设置一个标记,然后使用带此标号的break语句跳出多重循环。
public class BreaklFor {
public static void main(String args[]){
OK:                    //设置一个标记 使用带此标记的break语句跳出多重循环体
for(int i=1;i<100;i++){   //让i循环99次
for(int j=1;j<=i;j++){
if(i==10){
break OK ;
}
System.out.print(i + "*" + j + "=" + i*j) ;
System.out.print(" ") ;
}
System.out.println() ;
}
}
}
  运行结果当然是打印九九乘法表。当i=10时跳出了循环。
  当然还有另外一种方法,这也是设置一个boolean值的标记位,在for循环中使用判断是否继续循环来达到目的。
public class BreaklFor {
public static void main(String args[]) {
int array[][] = { { 5, 7, 6, 4, 9 }, { 1, 2, 8, 3, 2 } };
boolean flag = false;
for (int i = 0; i < array.length && !flag; i++) {  //当flag为true时跳出循环
for (int j = 0; j < array[i].length; j++) {
if (array[i][j] == 8) {
flag = true;
break;
}
}
}
System.out.println(flag);
}
}
  通过设置标志位,实现里成的代码控制外层的的循环条件。

posted @ 2014-11-21 09:25 顺其自然EVO 阅读(192) | 评论 (0)编辑 收藏

一步步学敏捷开发—如何做需求分析

 刚开始写就忙着搬家,这次没有找搬家公司,蚂蚁搬家真是太麻烦,以后搬家还是要找搬家公司。
  需求分析
  在敏捷开发中需求分析需要全体成员参与,体现了敏捷开发的“ 个体和互动 高于 流程和工具”的价值观。让全体成员参与有几点好处:有助于及时发现团队成员对同一个需求理解不一致的问题;有助于规避人力风险,当一个需求分析者突然请假其他人可以马上顶替他;也有助于全体成员能力的提升。但是,开发人员和测试人员们在能力和经验方便,不足以胜任需求分析工作。这意味着还需要一个商务分析师这个角色,他带领全体成员去进行有效的需求分析。商务分析师最重要的职责就是与客户交谈,了解和分析需求。搞清楚客户到底需要什么,到底为什么需要这些东西。商业价值是商务分析师关注的最终目标。
  软件开发所要解决的问题就是将用户需求转换为可运行的代码。需求反映的是"什么"(What)的问题,从问题解决的角度来看,要解决一个问题首先要弄清楚的是"问题"究竟是什么。而开发人员在需求分析时往往易犯的一个问题是急于考虑"怎么"(How)的问题,这是设计所要解决的问题。
  头脑风暴 + 原型设计
  我们在做项目需求分析时,通过与真实用户的交流,和用户一起进行头脑风暴,并将讨论结果使用头脑风暴软件(比如:MindMapper)整理出类似如下的头脑风暴图。
  头脑风暴图
  与用户讨论结束后,回去再通过GUI Design将头脑风暴里的内容快速做出一个原型,下次再找用户确认,经过几次反复确认修改基本可以确定一个版本。但这并不是最终的,用户的想法随时还会变,即使到开发阶段用户的需求一样会有变化,请参考敏捷原则第2条。
  原型图
  还可以使用纸质原型,这也是一种精益设计思考。

posted @ 2014-11-21 09:24 顺其自然EVO 阅读(223) | 评论 (0)编辑 收藏

测试团队管理-第二篇:部门整合(1)

 来到公司后,接手的第一项任务,就是把原有的两个小测试部门整合为一个公司级的大测试部门。公司有两大业务方向,每个业务方向都有一个开发部门和一个测试 部门,每个测试部门的主管都汇报给相应开发部门的主管。公司之所以考虑将测试部门整合起来,原因大致有以下几点。第一,公司治理的需要。测试部门直接受开 发部门管理,将无法有效地行使监督检查和质量保证的职责,裁判员兼任球员,很多问题被捂住,公司层面在一定程度上无法获取到项目的真实质量情况。第二,原 有的两个测试部门主管能力不受认可,一位主管是在老主管离职的情况下临时代理,另外一位主管被公司彻底否定。第三,两个小测试部门规模都不大,分别是20 人左右,各自都有一套自己的测试管理和技术体系,如测试用例、计划、报告模版,Bug库,测试流程,版本控制工具,全都不一样。整合后有利于更充分利用有 限资源,消除不必要冗余。第四,公司两个业务方向产品间的相互依赖调用和融合越来越多,一个大测试部门更便于产品多个组件间的集成测试和测试人员调配。第五,原有的两个测试主管,一个正在休产假,一个在孕期即将休产假,公司也迫切需要有人能够尽快把管理工作接管过来。
  深入分析已有两个业务方向和两个测试部门的各方面情况足足一个月后,编写出一份《公司级测试部门整合评估报告》。为了写出这份报告,我在两个测试部门各选 了一个代表性测试项目做深入调研,以专题会议、旁听会议、座谈、阅读文档、浏览项目管理系统等各种形式,收集到了大量数据和信息,然后在此基础上做了大量 汇总分析。评估报告涵盖了已有两个部门的现状分析,部门整合的有利因素、不利因素、风险和应对方案,整合方案及整合后新部门的发展路线图。评估报告受到了公司老板较高评价和认可,整合方案也受到大力支持,而我个人却颇感心惊肉跳、如履薄冰,和刚来时的豪情万丈相比,谨小慎微多了。为什么?因为调研后我才发现,这哪里是两个独立的业务方向啊,分明是两个事业部,或者是两家独立的公司。除了财务、人力、行政等职能是公用公司的,其他的产品策划、需求分析、开发、测试、技术支持都各有一套体系,各不相同。一个业务方向以软件产品研发为主,另一个以软件工程项目为主,即使是类似的工作也没有统一术语,各有一套表 述方法,相互沟通起来到处都是障碍。换句化说,这两个业务方向,产品、开发、测试、服务都完全独立,并且差异很大,现在要人为地把测试部门捏到一起,作为 产品或者项目完整生命周期里的其他环节还是分开的,难度可想而知。我强烈地预感到,整合过程绝对不会轻松,整合后想发展好就更加困难重重。

posted @ 2014-11-21 09:24 顺其自然EVO 阅读(256) | 评论 (0)编辑 收藏

项目bug的修正

这几个月来,大部分业余时间,都花在阅读软件工程和编译原理方面的书籍上了。软件工程方面的书,包括软件需求、风险管理、敏捷建模,系统设计,软件项目管理,还有一些类似于的沉思录书籍等。
  在这些书中,都只是讲了如何让项目健康发展,最后成功的提交一个产品。尽管它们都是从不同的角度,用不同的方法去完成同样的事。但它们几乎都支持这样的观点:计划+修正计划(不但设计是迭代的,计划也是迭代的)。用其中一个作者的话说,伤害你的,不是那些你没有考虑完整的,而是你根本没去考虑的事情。
  然而,几乎没有一本书里,讲到关于消防队的事,唉,真是奇怪,老外声称有超过50%的项目是失败的,那么在他们的项目中,失火也是常事,为什么就不谈谈救火的招数呢?难道他们也相信,不叫出魔鬼的名字,魔鬼就不会找上门来吗?
  唯一的解释就是,救火太难了,可能老外的救火能力远不如我们,他们干脆就不谈了。我在上一个项目中牺牲惨重,巨大的压力之下,精神上和身体上都受到极大的伤害,当然,我不是那个项目唯一的牺牲品,很多同事,他们很优秀,也一样的无助。之后,我一直在想,既然有50%的项目会失火,那么救火能力和计划能力至少是等同重要了。我苦苦的思索,回忆上次的经历,查找相关资料,然而收获甚微。
  救火的银弹也许永远不会出现,我把自己一些经验写出来,或许对大家有点帮助,如果能达到抛砖引玉的效果那是更好了:
  1.在FIX BUG过程中,持续进行重构。在设计时没有做好,重做是不太可能的了,但绝望也是没有意义的,我们只能想法去改进它。利用前人一些经验,持续进行重构,每FIX一个BUG,我们让代码更好一点,而不是更坏一点,FIX了一个BUG,代码中就少了一个BUG,而不是引更多的BUG。在实际上,重构最大的困难是没有完整的自动测试程序和测试用例,这使得我们根本不敢去改动代码,或者为了让改动最小,采取一些折中的方法,这都使得代码不断的变臭。在这种情况下,建议是建立自动测试,然后不断完善测试用例,我觉得建立自动测试任何时候都不晚。如果建立自动测试确实比较困难,那就列出所有的测试用例,然后手工测试。这时候,工程师的工作就是:重构à测试àFIX BUGà测试。有人说,我没有时间去重构,没有时间去测试。呵,这会使我想到,一个人围绕着一个小圆圈拼命的奔跑,累得半死的时候,发现在原地,他还在说,我没有时间去看清方向。
  2.关注常用功能。在项目的最后阶段,千万不要被QA牵着走,他们发现一个BUG,我们就FIX它。FIX一个BUG当然好,但是FIX BUG不是免费的,要不但要成本,还有潜在的风险。编译的优化原理是基于:20%的代码花了80%的时间。如果这个原理成立,可以推出:80%的用户实际上只使用20%的功能。QA并不是最终用户,QA和最终用户的不同在于:QA尽力去发现不常见的问题,而最终用户经常使用最常用的功能。这时候我们可以把自己想成最终用户,列出最常用的测试用例,如果不在这些测试用例中的情况,即使BUG的现象很严重,我们也要考虑一下再决定是否修改它。
  3.确定哪些BUG不改同样重要。这一点与2有一定的重复,为了强调有必要单独提出来。在软件需求分析时,分析师们都认为,要确定什么不在系统内和什么在系统内一样重要。程序员对于BUG态度,有时往往走两个极端:一种是老子就不改。一种QA怎么说我就怎么改。前者往往被看着工作态度不端正。而后者呢,却被视为好孩子。其实,在项目的最后阶段,后者未必正确,正如前面所说,FIX BUG不是免费的。这时候建立一个仲裁委员会有必要的,确定哪些BUG不改是他们的职责之一。
  4.BUG分类,明确责任。以前接手别人一个模块,处于Pending状态的BUG已经有110多个了。要把每一个BUG都看一遍就要花几个小时,不看吧,每次改一个BUG时,总有只见树木不见森林的感觉。最初,我很努力的去修改BUG,进展还是甚微。后来我花了几天时间,仔细分析了所有BUG,把它们归纳几类:其它模块引起的BUG; 和其它模块的接口引起的BUG; 超出需求之外的BUG; 完全是本模块内部的BUG。然后把其它模块引起的BUG提交给相关人员,和相关人员确认因接口不统一引起的BUG,把超出需求之外的BUG提交给需求控制委员会,最后剩下本模块的BUG又根据引起BUG的原因分为几类。这样,这些BUG很快被FIX了。
  5.工程师应该积极寻求帮助。有什么自己解决不了问题,应该向知道的人请教,或者向上司寻求帮助,不要出于面子或者其它原因,而花费大量的时间。在项目的最后阶段,每一分钟都很宝贵,不要重新发明轮子,对于有共性的难题也应该由专人解决。
  6.项目经理应该把眼光放在全局上。项目经理应该更多的关注于全局的事务,不要学只想拿大红花的小学生。别只顾修改自己的BUG,你的BUG少,并不能说明你是个好项目经理,在项目失败时,你个人的BUG少,并不能真正减轻你的罪恶感。据说软件团队遵循水桶原则,最低的那块木板才是决定装多少水要素,而不是最高的那块。项目经理应该随时关注哪块是最低的,然后把它补起来,自己成为最高的那块是没有意义的。
  7.Person Review以提高士气。呵,不知道有没有Person Review这个术语,反正我觉得挺好的,在项目的最后阶段,士气是非常宝贵的东西,可以说得士气者得天下。在前一个公司,每周一,老板会把每个工程师叫到他的办公室,一起聊会儿,聊天内容不限,多半是问问你这边工作上存在什么问题,有什么看法,非常坦白的谈一会儿,最后会得到他的鼓励和赞扬,自己感觉这对提高士气很有帮助的,当然老板最好是个好的煽动者。
  8.Bug Review。建立一个Bug Review小组,他们的主要责任是: 发现一些具有共性的BUG,确认哪些BUG需要FIX,哪个BUG不用FIX。有共性的BUG,让专人解决或者督促。不管一个BUG是要FIX还是不用FIX,都要注明足够的理由。
  9.加强QA和RD之间的合作。呵,根据遗传学和适者生存原理可以知道,在最后阶段,BUG的生命力极强,往往花费很长时间才能重现。加上自然语言本身具有的二义性和个人看问题的侧重点不同,QA可能忽略了RD让认为很重要的重现步骤,QA的BUG描述在RD眼中也可能迥然不同。在这个阶段,直接到现场和QA交流一下,可能会节省很多时间。同时也要尊重QA的劳动成果,这样他们才会更积极的配合。
  10.经验积累。每遇到一个BUG,想一想,它为什么会出现,为什么才出现,修改它后会有什么后果。把重要的记录下来,可能对自己和别人都有所启发,以减少犯同样错误的机会。

posted @ 2014-11-21 09:20 顺其自然EVO 阅读(168) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 13 14 15 16 17 18 19 20 21 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜