2010年12月24日

Exception VS Control Flow

每当提到Exeption就会有人跳出来说“Exception not use for flow control”,那到底是什么意思呢?什么情况下Exception就算控制流程了,什么时候就该抛出Exception了呢?

首先什么是Exception?

Definition: 

An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.


再看什么是“流程”?如果流程是指程序的每一步执行,那异常就是控制流程的,它就是用来区分程序的正常流程和非正常流程的,从上面异常的定义就可以看出。因此为了明确我们应该说”不要用异常控制程序的正常流程“。如何定义正常流程和非正常流程很难,这是一个主观的决定,没有一个统一的标准,只能根据实际情况。网上找个例子:
bool isDouble(string someString) {
    
try {
        
double d = Convert.ParseInt32(someString);
    } 
catch(FormatException e) {
        
return false;
    }
    
return true;
}
这个程序其实不是想convert数字,而是想知道一个字符串是否包含一个数字,通过判断是不是有异常的方式来决定返回true还是false,这是个Smell,这种应该算”异常控制了正常流程“。我们可以通过正则表达式或其他方式来判断。

另外Clean Code上一个例子:
    try {  
        MealExpenses expenses 
= expenseReportDAO.getMeals(employee.getID());  
        m_total 
+= expenses.getTotal();  
    } 
catch(MealExpensesNotFound e) {  
        m_total 
+= getMealPerDiem();  
    } 
MealExpensesNotFound异常影响了正常的计算m_total的业务逻辑。对于这种情况可以通过一下方式改进
    public class PerDiemMealExpenses implements MealExpenses {  
        
public int getTotal() {  
            
// return the per diem default  
        }  
    } 

以上两个例子是比较明显的异常控制正常流程,Smell很明显,不会有很大争议,但是实际情况中可能有很多例子没有这么明显,因为都是主观判定的。比如一下代码,算不算异常控制正常流程?

public int doSomething()
{
    doA();
    
try {
        doB();
    } 
catch (MyException e) {
        
return ERROR;
    }
    doC();
    
return SUCCESS;
}

看到这样一段程序,如果没有上下文,我们无法判断。但是如果doSomething是想让我们回答yes or no,success or error,我们不应该通过有无异常来判断yes or no,success or error,应该有个单独的方法来判断,这个方法就只做这一件事情。如果doSometing是执行一个操作,那么在这个过程中我们假定是不会出现问题的,否则抛出异常是比较合理的。






posted @ 2012-10-30 17:03 *** 阅读(225) | 评论 (0)编辑 收藏

ClassLoader 加载机制

1. Java Class Loading Mechanism

首先当编译一个Java文件时,编译器就会在生成的字节码中内置一个public,static,final的class字段,该字段属于java.lang.Class类型,该class字段使用点来访问,所以可以有:
java.lang.Class clazz = MyClass.class

当class被JVM加载,就不再加载相同的class。class在JVM中通过(ClassLoader,Package,ClassName)来唯一决定。ClassLoader指定了一个class的scope,这意味着如果两个相同的包下面的class被不同的ClassLoader加载,它们是不一样的,并且不是type-compatible的。

JVM中所有的ClassLoader(bootstrap ClassLoader除外)都是直接或间接继承于java.lang.ClassLoader抽象类,并且人为逻辑上指定了parent-child关系,实现上child不一定继承于parent,我们也可以通过继承它来实现自己的ClassLoader。

JVM ClassLoder架构,从上到下依次为parent-child关系:
  • Bootstrap ClassLoader - 启动类加载器,主要负责加载核心Java类如java.lang.Object和其他运行时所需class,位于JRE/lib目录下或-Xbootclasspath指定的目录。我们不知道过多的关于Bootstrap ClassLoader的细节,因为它是一个native的实现,不是Java实现,所以不同JVMs的Bootstrap ClassLoader的行为也不尽相同。调用java.lang.String.getClassLoder() 返回null。
  • sun.misc.ExtClassLoader - 扩展类加载器,负责加载JRE/lib/ext目录及-Djava.ext.dirs指定目录。
  • sun.misc.AppClassLoader - 应用类加载器,负责加载java.class.path目录
  • 另外,还有一些其他的ClassLoader如:java.net.URLClassLoader,java.security.SecureClassLoader,java.rmi.server.RMIClassLoader,sun.applet.AppletClassLoader
  • 用户还可以自己继承java.lang.ClassLoader来实现自己的ClassLoader,用来动态加载class文件。
ClassLoader特性
  • 每个ClassLoader维护一份自己的命名空间,同一个ClassLoader命名空间不能加载两个同名的类。
  • 为实现Java安全沙箱模型,默认采用parent-child加载链结构,除Bootstrap ClassLoader没有parent外,每个ClassLoader都有一个逻辑上的parent,就是加载这个ClassLoader的ClassLoader,因为ClassLoader本身也是一个类,直接或间接的继承java.lang.ClassLoader抽象类。
java.lang.Thread中包含一个public的方法public ClassLoader getContextClassLoader(),它返回某一线程相关的ClassLoader,该ClassLoader是线程的创建者提供的用来加载线程中运行的classes和资源的。如果没有显式的设置其ClassLoader,默认是parent线程的Context ClassLoader。Java默认的线程上下文加载器是AppClassLoader。

ClassLoader工作原理:

了解ClassLoader工作原理,先来看一个ClassLoader类简化版的loadClass()方法源码
 1 protected Class<?> loadClass(String name, boolean resolve)
 2         throws ClassNotFoundException
 3     {
 4         synchronized (getClassLoadingLock(name)) {
 5             // First, check if the class has already been loaded
 6             Class c = findLoadedClass(name);
 7             if (c == null) {
 8                 long t0 = System.nanoTime();
 9                 try {
10                     if (parent != null) {
11                         c = parent.loadClass(name, false);
12                     } else {
13                         c = findBootstrapClassOrNull(name);
14                     }
15                 } catch (ClassNotFoundException e) {
16                     // ClassNotFoundException thrown if class not found
17                     // from the non-null parent class loader
18                 }
19 
20                 if (c == null) {
21                     // If still not found, then invoke findClass in order
22                     // to find the class.
24                     c = findClass(name);
25                 }
26             }
27             if (resolve) {
28                 resolveClass(c);
29             }
30             return c;
31         }
32     }

首先查看该class是否已被加载,如果已被加载则直接返回,否则调用parent的loadClass来加载,如果parent是null代表是Bootstrap ClassLoader,则有Bootstrap ClassLoader来加载,如果都未加载成功,最后由该ClassLoader自己加载。这种parent-child委派模型,保证了恶意的替换Java核心类不会发生,因为如果定义了一个恶意java.lang.String,它首先会被JVM的Bootstrap ClassLoader加载自己JRE/lib下的,而不会加载恶意的。另外,Java允许同一package下的类可以访问受保护成员的访问权限,如定义一个java.lang.Bad,但是因为java.lang.String由Bootstrap ClassLoader加载而java.lang.Bad由AppClassLoader加载,不是同一ClassLoader加载,仍不能访问。

2. Hotswap - 热部署

即不重启JVM,直接替换class。因为ClassLoader特性,同一个ClassLoader命名空间不能加载两个同名的类,所以在不重启JVM的情况下,只能通过新的ClassLoader来重新load新的class。

 1  public static void main(String[] args) throws InterruptedException, MalformedURLException {
 2         IExample oldExample = new Example();
 3         oldExample.plus();
 4         System.out.println(oldExample.getCount());
 5 
 6         Hotswap hotswap = new Hotswap();
 7         while (true) {
 8             IExample newExample = hotswap.swap(oldExample);
 9             String message = newExample.message();
10             int count = newExample.plus();
11             System.out.println(message.concat(" : " + count));
12             oldExample = newExample;
13             Thread.sleep(5000);
14         }
15     }
16 
利用hotswap替换就的Example,每5秒钟轮询一次,swap方法实现如下:
 1  private IExample swap(IExample old) {
 2         try {
 3             String sourceFile = srcPath().concat("Example.java");
 4             if (isChanged(sourceFile)) {
 5                 comiple(sourceFile, classPath());
 6                 MyClassLoader classLoader = new MyClassLoader(new URL[]{new URL("file:"+classPath())});
 7                 Class<?> clazz = classLoader.loadClass("Example");
 8                 System.out.println(IExample.class.getClassLoader());
 9                 IExample exampleInstance = ((IExample) clazz.newInstance()).copy(old);
10                 System.out.println(exampleInstance.getClass().getClassLoader());
11                 return exampleInstance;
12             }
13         } catch ...
24         return old;
25     }
这里必须将exampleInstance转型为IExample接口而不是Exmaple,否则会抛出ClassCastExecption,这是因为swap方法所在类Hotswap是有AppClassLoader加载的,而且加载Hotswap的同时会加载该类引用的Exmaple的symbol link,而Example是MyClassLoader加载的,不同的ClassLoader加载的类之间直接用会抛出ClassCastException, 在本例中ClassLoader实现如下:
 1 public class MyClassLoader extends URLClassLoader {
 2 
 3     public MyClassLoader(URL[] urls) {
 4         super(urls);
 5     }
 6 
 7     @Override
 8     public Class<?> loadClass(String name) throws ClassNotFoundException {
 9         if ("Example".equals(name)) {
10             return findClass(name);
11         }
12         return super.loadClass(name);
13     }
14 }
而对IExample我们还是调用super的loadClass方法,该方法实现仍是JVM的parent-child委派方式,因此最终由AppClassLoader加载,加载Hotswap时加载的symbol link也是由AppClassLoader加载的,因此能够成功。

此外再热部署时,被替换的类的所有引用及状态都要迁移到新的类上,本例中只是很简单的调用copy函数迁移了count的状态。

Tomcat的jsp热部署机制就是基于ClassLoader实现的,对于其类的热部署机制是通过修改内存中的class字节码实现的。

Resource:
Reloading Java Classes 101: Objects, Classes and ClassLoaders
Internals of Java Class Loading

posted @ 2012-09-08 17:58 *** 阅读(613) | 评论 (0)编辑 收藏

Java Runtime exec问题

1. java.lang.IllegalThreadStateException: process hasn't exited

1 public static void main(String[] args) {
2         try {
3             Process process = Runtime.getRuntime().exec("javac");
4             System.out.println(process.exitValue());
5         } catch (IOException e) {
6             e.printStackTrace();
7         }
8     }

exec方法创建了一个native的进程,并返回该process的对象,如果进程还没有返回,调用exitValue方法就会出现此异常,因为该方法没有阻塞,其实现如下:
1 public synchronized int exitValue() {
2         if (!hasExited) {
3             throw new IllegalThreadStateException("process hasn't exited");
4         }
5         return exitcode;
6     }

2. waitFor方法

 1 public static void main(String[] args) {
 2         try {
 3             Process process = Runtime.getRuntime().exec("javac");
 4             int result = process.waitFor();
 5             System.out.println(result);
 6         } catch (IOException e) {
 7             e.printStackTrace();
 8         } catch (InterruptedException e) {
 9             e.printStackTrace();
10         }
11     }

waitFor方法会一直阻塞直到native进程完成,并返回native进程的执行结果。如果native进程无法执行完成,waitFor方法将一直阻塞下去,其实现如下:
1 public synchronized int waitFor() throws InterruptedException {
2         while (!hasExited) {
3             wait();
4         }
5         return exitcode;
6     }

该程序在jdk1.7 windows下测试工作正常,返回2; 但是jdk1.4 windows下测试出现hang。JDK documention的解释是
The methods that create processes may not work well for special processes on certain native platforms,
such as 
native windowing processes, daemon processes, Win16/DOS processes on Microsoft Windows,or shell scripts.
The created subprocess does not have its own terminal or console. All its standard io (i.e. stdin, stdout, stderr)
operations will be redirected to the parent process through three streams (getOutputStream(), getInputStream(),
getErrorStream()). The parent process uses these streams to feed input to and get output from the subprocess. Because some 
native platforms only provide limited buffer size for standard input and output streams,
failure to promptly write the input stream or read the output stream of the subprocess may cause
the subprocess to block, and even deadlock.

所以,出现hang时,及时的flush标准输入输出或者错误流能够消除hang,如上面的javac,我们知道redirect到stderr中,所以解决hang后的代码
 1 public static void main(String[] args) {
 2         try {
 3             Process process = Runtime.getRuntime().exec("echo 'abc'>b.txt");
 4             BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
 5             String line;
 6             while((line=reader.readLine())!=null){
 7                 System.out.println(line);
 8             }
 9             int result = process.waitFor();
10             System.out.println(result);
11         } catch (IOException e) {
12             e.printStackTrace();
13         } catch (InterruptedException e) {
14             e.printStackTrace();
15         }
16     }


3. exec() is not a command line 并不是所有的command line命令都可以用exec

 1  public static void main(String[] args) {
 2         try {
 3             Process process = Runtime.getRuntime().exec("echo 'abc'>a.txt");
 4             BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
 5             String line;
 6             while((line=reader.readLine())!=null){
 7                 System.out.println(line);
 8             }
 9             int result = process.waitFor();
10             System.out.println(result);
11         } catch (IOException e) {
12             e.printStackTrace();
13         } catch (InterruptedException e) {
14             e.printStackTrace();
15         }
16     }
结果为:
1 'abc'>a.txt
2 0
并没有将创建a.txt,而从命令行执行"echo 'abc'>a.txt"却正确创建了a.txt

posted @ 2012-09-05 22:43 *** 阅读(5030) | 评论 (0)编辑 收藏

Practices of Extreme Programming - XP

Extreme programming is a set of simple and concrete practices than combine into an agile development process.
  1. Whole Team - Cutomers, managers and developers work closely with one another. So they are all aware of one another's problem and are collaborating to solve the problem. The customers can be a group of BAs, QAs or marketing persons in the same company as developers. The customers can be the paying customer. But in an XP project, the customer, however defined, is the member of and available to the team.
  2. User Stories - In order to plan a project, we must know something about the requirement, but we don't need to know very much. We need to know only enough about a requirement to estimate it. You may think that in order to estimate the requirement, you need to know all the details. That's not quite true. You have to know that there are details and you have to know roughly the kinds of details, but you don't have to know the sepecifics. Since the sepecific details of the requirements are likely to change with time, especially once the customers begin to see the system together. So when talking about requirements with the customer, we write some key words on a card to remind us of the conversation. A user story is memonic token of an ongoing conversation about a requirement. Every user story should have an estimation.
  3. Short Cycles - An XP project delivers working software every iteration - one or two weeks. At the end of each iteration, the sytem is demonstrated to the customer or the stakeholder in order to get their feedbacks. Every release there is a major delivery that can be put into production.
  4. The Planning Game - The customers decide how important a feature is and the developers decide how much effort the feature will cost to implement. So the customers will select a collection of stories based on the priority and the previous iterations' velocity.
    1. The Iteration Plan - Once an iteration has been started, the business agrees not to change the definition or priority of the stories in that iteration. The order of the stories within the iteration is a technical decision. The developers may work on the stories serially or concurrently. It depends but it's a technical decision.
    2. The Release Plan - A release is usually three months. Similarly, the business or customer selecte collections of user stories and determines the priority based on their buget. But release are not cast in stone. The business can change or reorder at any time. They can write new stories, cancel stroies or change the priority. However, the business should not to change an interation that has been started.
  5. Acceptance Tests - The detail about the user stories are captured in the form of acceptance tests specified by the customer. The acceptance tests are written by BAs and QAs immediately before or concurrently with the implementation of that story. They are written in a scripting form that allow them to be run automatically and repeatlly. These tests should be easy to read and understand for customers and business people. These tests become the true requirement document of the project. Once the acceptance test passes, it will be added the body of passing acceptance tests and is never allowed to fail. So the system is migrated from one working state to another.
  6. Pair Programming - One memeber of each pair drives the keyboard and types the code. The other member of the pair watches the code being typed, finding errors and improvements.
    1. The roles change frequently. If the driver gets tired or stuck, the pair grabs the keyboard and starts to drive. The keybord will move back and forth between them serval times in one hour. The resulting code is designed and authored by both memebers.
    2. Pair memebership changes frequently. A reasonable goal is to change pair partner at least once per day. They should have worked on about everything that was going on in this iteration. Also it is very good for knowledge transfer.
  7. Collective Ownership - A pair has right to check out any module and imporve it. No particular pair or developer are individually responsible for one particular module. Every developer of the project has fully responsible for each line of the code. So don't complain about the code may be written by the other pair. Let's try to improve it. Since it is our code.
  8. Open Workspace - The team works together at one table or in one room. Each pair is within earshot of every other pair. Each has the opportunity to hear when another pair is in trouble. Each konws the state of the other. The sound in this room is a buzz of conversation. One might think that this would be a noise and distracting envrionment. But study suggested, working in a "war room" envrionment may increase productivity.
  9. Simple Design - An XP team makes its designs as simple and expressive as they can be. Furthermore, the team narrows its focus to consider only the stories that are planned for the current iteration, not worrying about stories to come. The team migrates the design of the system from iteration to iteration to be the best design for the stories that the system currently implements.
    1. consider the simplest thing that could possibly work. - XP teams always try to find the simplest possible design option fot the current batch of stories.
    2. You aren't going to need it. - That means an XP team introduces one technology or one infrastructure before it is strictly needed. Yeah, but we know we are going to need that database one day. We are going to have to support multiple threads one day. So don't we need to put the hooks in for those things? The team puts the technology or infrastucture in only if it has proof or at least very compelling evidence. that putting it in now will be more cost-effective than waiting.
    3. Once and only once. XPers don't tolerate duplication of code. Wherever they find it. they remove it. The best way to remove redundancy is to create abstractions. After all, if two things are similar, some abstraction can be from them.
  10. Continuous Integration
  11. Sustainable Pace
  12. Test-Driven Development
  13. Refactoring
  14. Metaphor

posted @ 2011-11-03 21:44 *** 阅读(235) | 评论 (0)编辑 收藏

数据库范式

  1. 第一范式 - 列的原子性,数据库表中的每一列都是不可再分的基本数据项
    1. 单一字段有多个有意义的值:比如 (people,address)其中address包括street,city,country,以逗号分割。想要查询住在某一city的people很不容易
    2. 用很多字段来表示同一事实:比如(people,address1,address2,address3),就算我们假设每个people最多有三个地址,当想要查询住在同一地址的people时也很不容易,因为有可能people1的address1与people2的address2相同,每一次都要比较3*3次组合
  2. 第二范式 - 符合第一范式;且表中的属性必须完全依赖于全部主键,消除非主属性对主键的部分依赖
    1. 比如(组件ID,供应商ID,供应商姓名,价格),组件ID+供应商ID为主键,价格完全依赖于全部主键,因为不同组件不同供应商具有不同价格,但是对于供应商姓名,则只依赖于供应商ID,会造成对同一供应商ID,名字数据重复,而且如果供应商改名,需要修改全部数据。因此需要单独一个表(供应商ID,供应商姓名),(组件ID,供应商ID,价格)
  3. 第三范式 - 非主属性之间不能有依赖关系,必须都直接依赖于主属性,消除传递依赖
    1. 比如(组件ID,制造商姓名,制造商地址),其中组件ID为主键,而制造商地址依赖于制造商姓名,需要(组件ID,制造商姓名)和新表(制造商姓名,制造商地址)其中姓名是主键
    2. 比如(订单ID,组件ID,单价,数量,总价),其中总价=单价*数量,总价依赖于单价和数量,需要去掉总价栏
  4. BC范式 - 任何属性(包括非主属性和主属性)不能被非主属性所决定。第三范式强调非主属性不能依赖于其他非主属性,BC范式是第三范式的加强,强调“任何属性”。因此如果满足第三范式,并且只有一个主键,则一定满足BC范式

一般,范式越高,表越多,数据库操作时需要表关联,增加了查询的复杂性,降低了查询性能。因此并不是范式越高越好,要根据需要进行权衡,第三范式已经消除了大部分的数据冗余,插入异常,更新异常和删除异常。

posted @ 2011-10-30 22:27 *** 阅读(226) | 评论 (0)编辑 收藏

Page Object Patter For Functional Test


Why?
Functional test characteristic
  1. The number of tests is mostly large.
  2. Page structure and elements may be changed frequently.

If our tests interact directly with the test driver (selenium,etc).
  1. UI element locators(Xpath, CSS, element Ids, names, etc) are copuled and repeat throughout the tests logic. It is hard to maintain, refactor and change especially when we change the page structure.
  2. The fine-grained UI operations hide our actual test intention. After some time we can not easily to identify what we want to do before.

What?
A Page Object models the UI elements that your tests interact with as objects within the test code. It decouples the test logic from the fine-grained details of the UI page.

Test -> Page Object -> Test Driver

The driver is the actual executor of browser action, like click, select, type etc. The page object has knowledage of the HTML structure.


Advantages
  1. When UI changes, only responding page object need to be changed. The tests logic will not be affected.
  2. It makes our tests logic simpler and more readable. Since the tests logic can only focus on its test secinaro rather than the structure of HTML page. As an example, think of login function, it only needs username and password, then do login action. How these are implemented shouldn't matter to the test. We don't care about that it uses a button or link to login.
  3. Complex interactions can be modeled as methods on the page object, which can be used in multiple times.

Best Practices

  1. Public methods represent the services that the page offers
  2. Try not to expose the internals of the page. Like OO programming, object just expose the behaviour and hide its internal details.
  3. Generally don't make assertions, but it is better to do some kind of check to ensure the browser is actually on the page it should be. Since our following tests are all base on the assumption. It can be done by checking something simple like title.
  4. Methods return other page object. This means that we can effectively model the user's journey through our application.
  5. Don't need to represent the entire page. It can be just a tab or a navigation bar that your test interacts with.
  6. Only one place knows the HTML structure of a particular page. UI changes, the fix need only be applied in one place.
  7. Different results for the same action are modeled as different methods. Since the test knows the expected state.

 

posted @ 2011-10-18 21:57 *** 阅读(220) | 评论 (0)编辑 收藏

Function - Clean Code

1. Small and the indent level should not be greater than one or two.
2. Do One Thing - Functions should do one thing. They should do it well. They should do it only.
    Steps of function are one level of abstraction below the name of the function. Then the function is doing one thing.
    Another way to know function is doing more than one thing is if you can extract another function from it.
3. One level of abstraction per function
    The stepdown rule - reading code from top to bottom.
    switch
4. Use Descriptive Names
    Don't be afraid to make a name long.
    A long descriptive name is better than a short magic name.
    A long descriptive name is better than a long descriptive comment.
    Dont't be afraid to spend time choosing a name.
    Be consistent in your names.
5. Function Arguments
    The ideal number of arguments for a function is zero.
    Three arguments should be avoided.
    Flag Arguments - can be split into two function.
    Aruments Objects - group the variables and abstract concept if possible.
    Verbs and keywords - function and argument should form a very nice verb/noun pair.
6. Have no side effects
7. Command Query Separation - Functions should either do something or answer something, but not both.
8. Prefer Exceptions to returning error codes.
    Extract try/catch blocks, error handling is one thing.
9. DRY - don't repeat yourself - especially the duplicated logic.

posted @ 2011-08-25 08:45 *** 阅读(302) | 评论 (0)编辑 收藏

JavaScript中存在问题但却难以避免的功能特性

一,全局变量
1.全局变量可以被任何部分在任意时间改变,复杂化,降低可靠性
2.可能与子程序变量名相同,冲突可能导致程序无法运行,难以调试

三种声明全局变量模式
1.脱离任何函数的var foo = value
2.直接添加属性至全局对象,全局对象是所有全局变量的容器,在web浏览器中全局对象名为window,window.foo = value
3.直接未经声明的变量 - 隐式的全局变量 foo = value

二,没有块作用域,有函数作用域

函数中定义的参数和变量在函数外部不可见,而在一个函数中任何位置的定义的变量在该函数的任何地方可见。

function f1(){
    var a=1;
    function f2(){
        if(false){
            var a=2;    //变量基于函数,而非基于语句块,没有块作用域
        }
        console.log(a); //undefined 未定义
    }
    f2();
    console.log(a);//1
}
f1();

大多数语言中,一般声明变量都是在第一次用到它的地方,在javascript中是一个坏习惯,因为没有块作用域,更好的是在每个函数开头声明所有变量。

三,return语句返回一个值,值表达式必须和return在同一行上

return {
    status:true
};

返回包含status成员元素的对象。

如果用

return
{
    status:true
};

会返回undefined。

四,保留字不能用来命名变量或函数,当保留字被用作对象字面量的键值时,必须用引号,而且不能用点表示法,必须使用括号表示法。

var object = {case:value}; //非法
var object = {'case':value}; //ok
object.case = value;       //非法
object['case'] = value;    //ok

各浏览器对保留字使用限制上实现不同,以上语法在FF中合法,但其他浏览器不合法;再有不同的保留字行为也不相同。类似int/long/float等保留字在各浏览器中都可以做变量名及对象字面量的键值。但不建议使用任何保留字。

五,typeof - 识别运算数类型的字符串

但typeof null返回'object',更好的检测null的方法: my_value === null

对于正则表达式 typeof /a/,一些浏览器返回'object',另一些返回'function'

六,parseInt - 将字符串转换为整数

1.此函数遇到非数字时就停止解析,即parseInt('16')和parseInt('16 abc')产生结果相同,都是16.
2.如果字符串第一个字符是0,则基于八进制解析,而不是十进制。八进制中没有8,9数字,所以parseInt('08')和parseInt('09')结果为0。此函数可以接收一个基数作为参数,parseInt('08',10)结果为8。

七,浮点数

0.1+0.2不等于0.3

八,NaN

function isNumber(value){
    return typeof value === 'number' && isFinite(value);
}

isFinite筛调NaN和Infinity,但是isFinite会试图把它的运算数转换为一个数字,如果运算数事实上不是一个数字,就会报错,所以加上typeof value === 'number'。

九,假值

0,NaN,'',false,null,undefined全部等于假,但它们是不可互换的。

posted @ 2011-07-18 20:09 *** 阅读(192) | 评论 (0)编辑 收藏

罗伯特议事规则

印象中美国人追求自由,但他们开会时却是严肃认真,说到开会,他们有一本厚厚的开会规则-罗伯特议事规则。作者亨利.马丁.罗伯特毕业于西点军校,有一次奉命主持一个地方教会的会议,结果人们争个不亦乐乎,什么结论都没有,搞砸啦。于是罗伯特研究出了一些规则,最初只有四五条,放在钱包里,开会时遵守这些规则,就能顺利成功。后来1876年罗伯特写了《通用议事规则》。至今发行五百万册,罗伯特议事规则已取得最广泛的认可和应用,它的根本意图在于使一个会议能以尽可能最有效的方式达到它的目的。

话说罗伯特议事规则初现中国是在组织农村开会时,当时会议及其混乱,表现为:
一,你说周杰伦,我引出周润发,东一榔头西一棒子,最后忘了开会的目的是啥,还可能对于已经讨论表决的问题,又重新拿来说,反反复复,归结起来就是跑题;
二,领导或者权威讲个不停,下面人睡着啦,归结为一家言;
三,争论起来,互相指责,甚至人身攻击,归结为野蛮争论。

其实这三条也是我们日常会议经常出现的问题。

首先说野蛮争论问题,很容易解决,罗伯特议事规则限制只对会议讨论的问题发言,不允许评议个人,发言时对主持人进行陈述,而非辩论对方。总结起来,用中国言语来说就是“对事不对人”,因为指责个人并不能解决问题,不允许指责一个会员的动机,动机很难衡量,但可以用强烈的语言谴责一个议案的性质或后果。

第二对于一家言问题,罗伯特议事规则限制每个人发言的次数和时间用以避免一家言问题。其实这是个人智慧和经验与集体合作的关系,仍用中国言语来说“三个臭皮匠顶个诸葛亮”。对于睡着问题,可能是由于发言人太爱讲,可以通过前述方法解决,还可能是由于当前话题不感兴趣甚至无关,则可直接离开会议或不参加。

第三对于跑题问题,罗伯特议事规则规定会议讨论的内容应当是一个明确的动议:“动议,动议,就是行动的建议!”动议必须是具体的,明确的,可操作的行动建议,每一个动议都会导致一个action。比如“早上9点上班”,而不是“早上几点上班?”。发言人应首先表明观点,赞成还是反对,并陈述理由。与本次会议动议无关的其他动议,应组织其他会议,即我们常说的“一事一议”。经双方轮流发言后,主持人组织投票。对于已经表决的观点,除非理由充分,并经所有成员2/3同意再议,再组织再次讨论。

对于第三条,我觉得首先需要把平时会议划分一下几类:
1.session:做session的人事先准备好内容,并计划和把握session时长,同样中间遇到与session无关的其他问题或者非常detail的问题,做session的人要打断讨论,对于重要问题组织其他session,对于detail问题offline讨论。
2.discussion:如罗伯特议事规则所说,组织discussion的人要有明确的动议,支持方与反对方轮流发言,如果规定时间未达成一致,组织者须组织投票。
3.brainstorm:通过集思广益、发挥集体智慧,迅速地获得大量的新设想与创意,这是一种极为有效的开启创新思维的方法。头脑风暴结束后才开始对观点进行讨论,那针对每一个讨论,又是一个discussion。

另外,并不是所有会议都必须所有人参加,如果感觉对自己影响不大或者有比会议更要紧的事情可以不参加,或中间离席。

posted @ 2011-07-11 08:27 *** 阅读(275) | 评论 (0)编辑 收藏

ORA-00257 archiver error. Connect internal only, until freed

1. Change to oracle user:$su oracle
2. Log in as sys user: $sqlplus sys/password as sysdba
3. Find out flash recovery area usage info, from where we can find the archive log space usage percent: SQL>select * from V$FLASH_RECOVERY_AREA_USAGE;
4. Caculate the space used by flash recovery area:SQL>select sum(percent_space_used)*3/100 from V$FLASH_RECOVERY_AREA_USAGE;
5. Show Archive log location: SQL>show parameter log_archive_dest;
6. Show recovery area location: SQL>show parameter recover;
7. Delete or move some old archive log files: SQL>rm -rf archive_log_2011_06_0*;
Notice: After step 7, we must use RMAN to maintain the control files, otherwise, the deletion changes can not be apply.
8. Log in as RMAN: SQL>rman target sys/password;
9. Find out unused archive log: SQL>crosscheck archive log all;
10. Delete expired archive log files: SQL>delete expired archivelog all;
11. Check the flash recovery area usage info again, make sure archive log files have been deleted: SQL>select * from V$FLASH_RECOVERY_AREA_USAGE;
12. Finally, increase the recovery file destination size: SQL>alter system set db_recovery_file_dest_size=3G scope=both;

posted @ 2011-06-02 22:48 *** 阅读(370) | 评论 (0)编辑 收藏

为什么需要持续集成?

偶尔想起学生时,几个同学一起做项目,虽然不大,但还是分了模块,每个人负责一个或多个模块。每天打开电脑,从版本控制库更新最新代码,运行下程序,回忆昨天完成的并计划今天的任务。突然发现昨天好好的功能,今天突然不work甚至抛出异常,于是大喊一声谁破坏了我的功能?没人回应,只能自己一步一步查看到底那个代码破坏了昨天的功能,然后找到提交的同学,再商量到底该怎么解决。其实当时我们各自实现自己的模块,写(或不写)测试,然后提交代码,各自只关心和测试自己的模块,难免会发生冲突,尤其是两个模块结合的地方,如果被破坏方可能在几个小时,几天甚至更长时间后发觉应用被破坏,或者直到最后项目上线前一分钟才发觉。。。


后来参加工作,知道了持续集成可以解决当时的痛苦,而且可以提供更多。持续集成是XP实践之一,于是,很多人错误认为持续集成是为了实现敏捷编程的。实际上,早于敏捷编程概念的提出,持续集成作为一个best practice就已经被很多公司采用了,只不过作为一个概念,则是由Martin大叔为了推进敏捷所倡导并由此风靡起来。

那么为什么我们需要持续集成或者说持续集成给我带来了什么好处呢?

  • 及早获得系统级的成果或者是可以deploy到production环境的产品。因为代码已经被集成起来了,即使整个系统还不是那么可用,至少比零散的模块让人更有安全感。增强了客户和我们自己的信心。
  • 可以很容易的知道每一个版本之间有什么变化,甚至我们可以很容易的重新build出任何一个时间点上的版本,这点非常重要。工作后第一个项目就遇到了难缠的客户,经常今天告知我们明天需要一个版本部署到生产环境,如果没有持续集成,我们如何得到有信心可以部署到production的build?如果没有持续集成,我们如何提供包含最新功能的可以部署到production的build?偶尔,客户并不需要你提供的最终build,而是包含功能1和2而不包含功能3的build,如果没有频繁的持续集成,我们又怎么快速的得到某一时间的build?
  • 及早的发现和定位错误:比如学生时代的项目,某个人在工作的时候踩进了别人的领域、影响了别人的代码,而被影响的人还不知道发生了什么,于是bug就出现了。这种bug是最难查的,因为问题不是出在某一个人的领域里,而是出在两个人的交流上面。随着时间的推移,问题会逐渐恶化。通常,在集成阶段出现的bug早在几周甚至几个月之前就已经存在了。结果,开发者需要在集成阶段耗费指数倍的时间和精力来寻找这些bug的根源。如果有了持续集成,当持续集成失败了,很容易说明最新加入的代码或者修改的代码引起了错误,当然这需要强大的自动化测试作为后盾。
  • 项目进度的一目了然。频繁的集成使我们可以看到哪些功能可以使用,哪些功能还没有实现。开发人员不用在汇报任务的时候说我完成了多少百分比而烦恼,而PM也不再烦恼程序员说完成了编码的50%到底是个什么概念。

因此引用同事的原话“没有持续集成,说明交付流程是混乱不清晰随机的。”

posted @ 2011-03-31 23:33 *** 阅读(636) | 评论 (1)编辑 收藏

JS-函数读书笔记

1.函数就是对象
函数可以存放变量,数组,对象
函数可以当做参数传递给其他函数
函数可以返回函数
函数可以拥有方法

2.函数的调用
调用运算符是任何一个产生函数值的表达式之后的一对圆括号。
调用一个函数将暂停当前函数的执行,传递控制权和参数给新函数,除了声明时定义的形参,每个函数接收两个附加的参数-this和arguments。
this的值取决于调用的模式:

方法调用模式:函数被保存为对象的一个属性时,称为方法。方法被调用时,this绑定到该对象。
var obj={
    value:0,
    increment:function(){
        this.value+=1;
    }
}
obj.increment();
obj.value;

函数调用模式:当一个函数并非对象的属性时,它被当作一个函数来调用,this绑定到全局对象(Window),因此不能共享外部函数对对象的访问权-语言设计的错误。当内部函数被调用时,this应该仍绑定到外部函数的this变量。
解决方案:定义一个变量并给它赋值为this
var myObj={
    value: 0,
    getValue: function(){
        return this.value;
    }
};
myObj.test=function(){
    var that = this
    var helper=function(){
        that.value+=1;
    }();
}
myObj.test();

构造器调用模式:如果一个函数前面带上new来调用,将会创建一个隐藏连接到该函数的prototype成员的新对象,this将会绑定到新对象上。
var Quo = function(string){
    this.status=string;
}
Quo.prototype.get_status=function(){
    return this.status;
}

var myQuo=new Quo("confused");
myQuo.get_status();

apply调用模式
:apply方法让我们构建一个参数数组并用其去调用函数。该方法允许我们选择this的值,apply方法接收两个参数,第一个就是将被绑定给this的值,如果是null则为Window对象,第二个是参数列表。
var array=[3,4];
var sum=add.apply(null,array);

var Quo = function(string){
    this.status=string;
}
Quo.prototype.get_status=function(){
    return this.status;
}
var statusObj={
    status:"OK"
};
Quo.prototype.get_status.apply(statusObj);

var myObj={
    add:function(a,b){
        //参数为null或#ff0000,this引用为Window, double函数的alert证明了这一点
        alert(this.location.href);
        return a+b;
    }
}
var array=[3,4];
var sum=myObj.add.apply(null,array);

2.给类型增加方法:待续

3.闭包-能够读/写函数内部的某些变量的子函数,并将这些变量保存在内存中.

讨论闭包之前先讨论函数作用域
1)函数内的局部变量在函数外部无法访问。
function f(){
    var n=1;
}
alert(n);//error

2)内部函数可以访问外部函数的局部变量。
function f(){
    var n=1;
    function inner(){
        alert(n);
    }
}
因此只要将inner作为返回值,就可以在f外部读取它的内部变量了。
function f(){
    var n=1;
    function inner(){
        alert(n);
    }
    return inner;
}
f()();
闭包就是将函数内部和函数外部连接起来的一座桥梁。如果把父函数当作对象使用,把闭包当作它的公共函数,把内部变量当作它的私有属性。

理解内部函数能访问外部函数的实际变量而无须复制:
var add_handles=function(nodes){
    for(var i=0;i<nodes.length;i++){
        nodes[i].onclick=function(e){
            alert(i);
        }
    }
}

var add_handles=function(nodes){
    for(var i=0;i<nodes.length;i++){
        nodes[i].onclick=function(i){
            return function(e){
                alert(e);
            }
        }(i);
    }
}


闭包用途:
1)读取函数内部的局部变量
2)将变量的值始终保存在内存中,因为f是inner的父函数,而inner被赋给了一个全局变量,导致inner始终在内存中,而inner的存在依赖于f,因此f也始终在内存中,不会在调用结束后被垃圾回收机制回收。
3)通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)

缺点:闭包使得函数中的变量都被保存在内存中,内存消耗很大,不能滥用闭包。

4.模块
一个定义了私有变量和函数的函数,利用闭包创建可以访问私有变量和函数的特权函数,然后返回这个特权函数。
提供接口却隐藏状态与实现的函数或对象。摒弃了全局变量。


posted @ 2011-02-21 14:38 *** 阅读(344) | 评论 (0)编辑 收藏

重构与设计模式

1. 状态模式
对象行为的行为依赖于它所处的状态,对象的行为随着状态的改变而改变。解决不同状态下,行为不同的问题。

问题:

左边树状结构,选择不同节点,右边Viewer显示该节点下图片;左边树下方search框,右边Viewer显示满足search条件的图片。抽象出Viewer对象,有两个不同状态view和search,不同状态下更新Viewer的方式不同,即
tree.onselect -> state="view"
search -> state="search"

if(state="view"){
  updateView(path,start,limit)
}else if(state="search"){
  updateSearch(path,start,limit,searchCriteria)
}

Viewer, search, tree耦合在一起,需要全局变量state。

解决方案:

抽象两个状态对象
viewAction ->  updateView(path,start,limit)
searchAction -> updateSearch(path,start,limit,searchCriteria)

Viewer对象
变量 updateAction
方法 setUpdateAction(action)
方法 update()调用 -> updateAction()

状态改变时,改变所选的状态对象
tree.onselect -> Viewer.setUpdateAction(viewAction)
search -> Viewer.setUpdateAction(searchAction)

Viewer, search, tree解藕,去除了全局变量state,行为局域化。假如以后加入view,search外的其他状态,只需增加newAction状态对象,并在调用处添加Viewer.setUpdateAction(newAction),便于扩展,无需改变现有代码。

2. 不知道该叫什么模式
 
问题:右键事件
if(action=="addTag"){
  addTag()
}
if(action=="replaceTag"){
replaceTag()
}

if(action=="addSubjectTag"){
addSubjectTag()
}

if(action=="addCredit"){
addCredit()
}

增加新事件需要添加新的if语句

--------------------------->
中间过程
var items={
  "addTag":addTag,
  "replaceTag":replaceTag,
  "addSubjectTag":addSubjectTag,
  "addCredit":addCredit
}

perform(){
 items[action]()
}

--------------------------->
事件注册,提供注册接口
var items = {}

perform(){
 items[action]()
}

register(option){
 items.add(option)
}

增加右键事件时,只需自行注册,事件的执行与事件本身完全解藕,同时新事件加入时,只需注册,无需改变现有代码。
regsiter({"addTag":addTag})
regsiter({"replaceTag":replaceTag})
regsiter({"addSubjectTag":addSubjectTag})
regsiter({"addCredit":addCredit})


posted @ 2011-01-23 17:52 *** 阅读(261) | 评论 (0)编辑 收藏

读Roy Fielding的REST风格架构笔记

REST顾名思义:Representational State Transfer(表述化状态转移)。 REST两个基本概念:

  1. 资源(Resource):将信息抽象为资源,任何能够命名的信息(包括数据和功能)都能作为一个资源,一张图片,一份文档,一个服务(如上传图片),一个其他资源的集合等。 资源是到一组实体的概念上的映射,而不是在特定时刻与该映射相关联的实体的映射。例如,“最新上传的图片”是一个值经常变化的映射,但是“2011/1/9上传的图片”的映射是静态。它们是截然不同的资源,即使某一时刻它们可能会映射到相同值的集合。
  2. 表述(Representation): 一个资源当前或预期的状态,资源是一个随时间变化的函数,该函数将时间t映射到一个实体或值的集合,集合中的值可能是资源的表述。REST组件通过URI来获得资源的表述并对资源执行动作,并在组件间传递该表述。

举购物网站系统的例子,products通过加入购物车到orders,经过付款订单到purchase,然后到delivery。其中productsorders是资源,可以通过/products?color=green/orders/2007/11表示;而purchasedelivery是资源productsorders某一时间的状态。应用程序如同资源和表述组成的虚拟的状态机,通过不断的获取资源的表述来转变应用程序的状态,即所谓的表述化状态转移。

REST风格架构的约束:

  1. 客户-服务器:分离关注点,将用户接口(如用户界面)和数据存储分离,如果接口不变,组件可独立进化。
  2. 无 状态:从客户端道服务器的每个请求必须包含理解该请求所必需的所有信息,不能利用任何存储在服务器上的上下文。提高了系统的可扩展性,其优点有三:可见 性,监视系统不必为了确定一个请求的性质而去查看请求之外的多个请求;可靠性,减轻了从局部故障恢复的任务量,可以快速定位;可伸缩性,不必在多个请求之 间保存状态,允许服务器快速释放资源,并且服务器不必跨请求管理资源。缺点是,由于不能将状态保存在服务器上的共享上下文中,增加了请求中发送的重复数 据,降低网络性能,因此有了约束三。
  3. 缓存:请求响应中的数据显示或隐式的标记为可缓存的不可缓存的。缓存可以为以后相同的请求重用这个响应的数据。但是缓存管理不好,会降低可靠性,导致缓存中陈旧的数据与直接访问服务器得到的数据差别很大。
  4. 统一接口:组件之间要有统一的接口,是REST风格架构区别其他风格架构的核心特征。REST由四个接口约束定义:资源的识别,web-based系统中资源由URI表示,数据库存储系统中资源还可以是XMLJSON等;通过表述对资源执行的动作:表述中包含操作该资源的信息,如增删改查,映射到HTTP协议的GETPOSTPUTDELETE方法;自描述的消息:消息中包含如何处理该消息的信息,如哪个sevlet处理,响应中包含可不可以被缓存等信息;作为应用状态引擎的超媒体。
  5. 分层系统:通过限制组件的行为,即每个组件只能看到与其交互的紧邻层,将架构分解为若干等级层,提高各层的独立性。
  6. 按需代码:客户端知道如何访问资源,但是不知道如何处理它,向服务器发送对于如何处理资源的代码的请求,接收这些代码,然后在本地执行代码。

 

posted @ 2011-01-09 23:20 *** 阅读(2076) | 评论 (0)编辑 收藏

Groovy"=="陷阱

Groovy与Java同是运行在JVM之上,大多数时候可以把Groovy当做Java来用,但是也存在着陷阱。

例如,想重写对象的equals方法,需如下步骤:
1. 使用==判断参数和自身对象引用是否相等,如果相等直接返回true(此判断可以提高性能);
2. 使用instanceof判断参数类型是否正确,如果不正确直接返回false
3. 将参数转换为正确的类型,步骤2已确保了类型
4. 检查参数与自身对象关键字段是否相等
    1)基本类型(除float和double)运用==比较
    2)对象引用,递归调用equals方法
    3)浮点型float,调用Float.floatToIntBits转化为int,用==比较
    4)浮点型double,调用Double.doubleToLongBits转化为long,用==比较

遵循以上步骤,重写简单Money类的equals方法:
1  public boolean equals(Object another) {
2     if (another == thisreturn true
3     if (another instanceof Money) {
4       Money anotherMoney = (Money) another
5       return amount == anotherMoney.amount
6     }
7     return false
8   }

调用
1 new Money(10).equals(new Money(10))

得到异常
java.lang.StackOverflowError
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
86)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:
234)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:
1049)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:
880)
    at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:
746)
    at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:
729)
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareEqual(DefaultTypeTransformation.java:
620)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareEqual(ScriptBytecodeAdapter.java:
680)
    at Money.equals(Money.groovy:
10)

最终发现罪魁祸首是“==”,Groovy中对于所有类型(基本类型和引用)调用“==”和“equals()”方法相同,当执行“another == this”时,解释器会调用“another.equals(this)”造成死循环。

如果想比较引用相等,Groovy提供了is方法,即
1  public boolean equals(Object another) {
2     if (another.is(this)) return true
3     if (another instanceof Money) {
4       Money anotherMoney = (Money) another
5       return amount == anotherMoney.amount
6     }
7     return false
8   }

posted @ 2010-12-25 00:29 *** 阅读(740) | 评论 (0)编辑 收藏

Christmas Eve, 我正式开博啦

2010.12.24晚,有点浪漫啊

希望今后在匆匆行走的路上,不要迷失了自我,偶尔,停下来,想想。

posted @ 2010-12-24 21:00 *** 阅读(84) | 评论 (0)编辑 收藏

<2010年12月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

导航

统计

常用链接

留言簿

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜