Think-Aloud 可用性测试介绍

中文是指出声思考:出声思考。可用性测试中常用也很有用的一个数据收集方法,来改善产品。要求被测试者把在测试过程中即时的把自己的想法大声说出来。比如,你说我不知道干什么,这个好像有点问题,等等。然后有人来记录。 SSD4给出的具体步骤翻译添加解释如下: Define the study’s framework, 定义该测试报告的框架。比如系统准备解决什么问题,适合什么类型的用户,希望评估首次使用还是其他什么,希望最终的目标是什么,比如希望90%的用户可以初次顺利使用。 Choose what to observe, 选择打算观察测试者的什么行为,比如用户如何打开,先干了什么 Prepare for the think-aloud usability test, 为测试做准备,比如模拟真实情景,写个流程。开个会,招募实验人员。 Introduce the participants to the observation procedure, 给实验人员介绍步骤。抚慰一下他们的情绪。告诉他们目的,并且希望他们think aloud。 Conduct the observation, 进行观察 Analyze the observation, 分析观察结果 。 Find possible redesigns, 找到可能需要进行重新设计的地方 Write a report. 写个总结报告出来。完成 这不也就这样嘛。

2012-05-29 · 1 min · bystander

UAR报告的简单说明

UAR报告由以下几个部分构成。就这个例子简单说一下。 Example UAR — Time Zone ListBox Is Not Good //标题 UAR Identifier //问题编号,从1开始,每个问题都这样的格式来说明,就构成了UAR报告 HE18—Problem //后面这个problem表示有问题,也可以是Good,表示这部分很好。没问题。 Succinct description: //简短的描述 Time Zone pull-down ListBox provides too much irrelevant information. Evidence for the aspect: //违反了哪条规则,共有十条规则。 Heuristic: Aesthetics and minimalist design **Interface aspect: ** The pull-down ListBox has 50 lines of information—in very small font. There are many competing items of information to visually search, the vast majority of which are irrelevant to any one user’s particular task of finding a single desired time zone [![](/images/ "uar")](http://seqcc.icarnegie.com/content/SSD/SSD4/3.1/normal/pg-creatng-evaltng-interfaces/pg-crt-eval-list-combo/pg-he-clean-beauty/Ex5.png)In addition, the information is structured as follows:The string "[GMT " begins each line (which means Greenwich Mean Time). If the time zone is behind GMT, then a "-" indicates this fact, which is followed by the number of hours and minutes the time zone is behind GMT. If the time zone is ahead of GMT, a "+" is used instead. Finally, some words follow the GMT offset, which are either city or country names, or the names of regions.  The presentation of this structured information violates the aesthetics and minimalist design heuristic because the structure is not preserved visually from item to item. For example, the words are not always lined up vertically; see the entries for: ...

2012-05-29 · 3 min · bystander

10条可用性准则(Heuristics)

SSD4第二单元其实就讲了这么一点东西,包括一点VB的控件常识 可用性测试(Usability testing),是一项通过用户的使用来评估产品的技术,由于它反应了用户的真实使用经验,所以可以视为一种不可或缺的可用性检验过程[1]。也就是说,可用性测试是指让用户使用产品(服务)的设计原型或者成品,通过观察,记录和分析用户的行为和感受,以改善产品(服务)可用性的一系列方法。它适用于产品(服务)前期设计开发,中期改进和后期维护完善的各个阶段,是用户中心设计的思想的重要体现。 10条可用性准则(Heuristics) These are ten general principles for user interface design. They are called “heuristics” because they are more in the nature of rules of thumb than specific usability guidelines. 1.Visibility of system status——系统状态的可见性 The system should always keep users informed about what is going on, through appropriate feedback within reasonable time. 系统应该始终在合理的时间以适当的反馈信息让用户知道系统正在做什么。 2.Match between system and the real world——系统和现实世界之间的吻合 The system should speak the users’ language, with words, phrases and concepts familiar to the user, rather than system-oriented terms. Follow real-world conventions, making information appear in a natural and logical order. 系统应该用用户熟悉的词,短语和概念来说用户的语言,而不是用面向系统的术语。遵循现实世界中的惯例,让信息以自然的合乎逻辑的次序展现在用户面前。 3.User control and freedom——用户控制和自由 Users often choose system functions by mistake and will need a clearly marked “emergency exit” to leave the unwanted state without having to go through an extended dialogue. Support undo and redo. 用户经常错误地选择系统功能,所以在不需要查看由于误操作而延伸出来地对话的情况下有一个明显地标志为“紧急退出”的操作来离开不想要的状态。另外,系统需要支持“撤销操作”和“重做”的功能。 4.Consistency and standards——一致性和标准 Users should not have to wonder whether different words, situations, or actions mean the same thing. Follow platform conventions. ...

2012-05-29 · 2 min · bystander

VS2010 编译安装boost库

实践是最好的办法。。学习C++,想试试线程,然后打算用boost库,结果boost库编译差点吓到我。。没看到比较完整的安装教程。。一直耽搁。今天动手。完成了。方法记录如下: 1.下载boost 从boost官网( http://www.boost.org )上下载最新的boost版本,现在最新是1.49版本,解压到自定义目录(我解压到了D:/program files,最终的目录结构是D:\Program Files\boost_1_49_0) 2.编译安装 在D:\Program Files\boost_1_49_0的目录下,有一个bootstrap.bat文件,直接双击运行。就会在同目录生成b2.exe;bjam.exe两个文件。 3.设定编译环境 修改user-config.jam (D:\Program Files\boost_1_49_0\tools\build\v2\user-config.jam) 的MSVC configuration MSVC configuration Configure msvc (default version, searched for in standard locations and PATH). using msvc ; 在上面这段的下面直接添加如下的文字。 using msvc : 10.0 : :/wd4819/D_CRT_SECURE_NO_DEPRECATE/D_SCL_SECURE_NO_DEPRECATE/D_SECURE_SCL=0 ; 保存关闭。 4.开始编译 点击开始->所有程序->“Microsoft Visual Studio 2010”,指向“Visual Studio tools(工具)”,然后单击“Visual Studio 2010 command prompt(命令提示)” 使用cd切换到D:\Program Files\boost_1_49_0目录。这个就不说了 然后输入如下的代码: b2 toolset=msvc-10.0 architecture=x86 instruction-set=i686 address-model=32 link=static variant=debug,release threading=multi runtime-link=shared --without-python --without-mpi --without-wave --without-graph --without-math --without-serialization stage 解释一下命令的意思: 1.toolset:表示编译器工具,我安装的是VS2010,所以是msvc-10(如果你是VS2005,可以使用msvc-8.0 VS2008是msvc-9.0) 2.architecture:表示架构,也就是你的CPU架构,x86,x64,因为我安装的是win7 32位,所以使用了x86的架构 3.instruction-set:表示指令集,依然是8086指令集 4.address-model:表示地址长度为32位 5.link:表示生成动态/静态链接库,动态链接库是shared,静态链接库是static,一般都会编译成静态库,因为给出程序的时候打包boost的库会非常庞大 6.variant:表示生成的Debug或者release版本,一般情况下会两种版本都会编译出来的 7.threading:表示单/多线程编译,一般我们的程序都会用到多线程,所以选择了multi 8.runtime-link:表示动态/静态链接C/C++运行时库(C/C++ Runtime),我们选择了动态链接 9.without/with:表示不需要编译/需要编译哪些库,一些自己不用的库可以无需编译 10.stage/install:stage表示只生成库文件(DLL和Lib),install还会生成包含头文件的include目录,推荐使用stage,因为boost_1_49\boost中就是boost库完整的头文件,所以无需再拷贝一份出来。编译出来的库会放在stage文件夹中 这样一份完整的boost库就生成了,剩下就是直接使用到项目中了。 其实编译的具体命令都是可以自己写的。如果你需要编译所有。只需要使用下面的这行代码 b2 –toolset=msvc-10.0 –build-type=complete 就可以了。 不出问题的话。就开始编译了。。登个半个多小时吧。就会完成了。 5.设置vs 打开vs,新建一个工程。然后工程属性。配置属性->C/C++ ,附加包含目录 填上 D:\Program Files\boost_1_49_0;%(AdditionalIncludeDirectories) 这个是最终的结果,你也可以手动添加 在左侧选择链接器->附加库目录,填上 D:\Program Files\boost_1_49_0\stage\lib;%(AdditionalLibraryDirectories) 就可以了。 6.测试 在你新建的工程里输入如下的代码。运行成功就说明可以了 #include <boost/thread/thread.hpp> #include <iostream> void hello() { std::cout << "Hello world, I'm a thread!" << std::endl; } int main(int argc, char* argv[]) { boost::thread thrd(&hello); thrd.join(); return 0; } 参考: http://www.cppfans.org/1317.html http://www.cnblogs.com/ComputerG/archive/2011/03/10/1979730.html http://www.cppblog.com/shaker/archive/2011/11/30/33583.html

2012-05-24 · 1 min · bystander

C++ 独立引用,为什么?

问题: I read in some good C++ tutorial that independent references do exist, and act like aliasing. 我读了一些好的C++文章,发现独立引用确实存在,并且很像别名。 But… I wonder what it is made for. 但是,,,我想知道他适用于什么情况。 Why should one want to use aliasing.Besides, some piece of code that is not clear to me: 为什么有人想使用别名呢,另外,下面这段代码我不太清楚。 int a; int &ref = a; // independent reference int b = 19; ref = b; cout << a << " " << ref << "\n"; ref--; cout << a << " " << ref << "\n"; First, ref is a ‘reference’ to a.I understand from second line of code that address for ref (hence the ampershead) is 首先,ref是一个对a的引用,从第二行代码那我认为ref的地址也就是a,(括号里面不清楚什么意思。貌似是作者写错了) a. Then, integer ref is assigned the value of b (19). First cout returns a and ref, both equal to 19. 然后呢,整数ref被b(19)被赋值,第一次输出a和ref,都是19, Why? Isn’t integer a the address for ref? Then, decrements ref, and last cout gives two times 18. a and ref where decremented. 为什么,难道整数a不是给ref的地址?然后ref自减,最后输出了2个18,a和ref都减少了。 ...

2012-05-23 · 2 min · bystander

c & c++中sizeof返回值不同?

问题: A character array is defined globally and a structure with same name is defined within a function. 一个字符数组被定义为全局变量,一个相同名字的结构体被定义在一个函数内部。 Why sizeof operator returns different values for c & c++ ? 为什么sizeof操作符对于C和C++返回了不同的值呢? char S[13]; void fun() { struct S { int v; }; int v1 = sizeof(S); } // returns 4 in C++ and 13 in C 答案: Because in C++, the struct you defined is named S, while in C, 因为在C++中,你定义的结构体的名称是S,而在C中, it’s named struct S (which is why you often see typedef struct used in C code). 他叫做struct S(这也是为什么我们可以经常看到typedef struct 被用在C代码中)。 In C, to refer to the struct type, you need to say struct S. Therefore, sizeof(S) refers to the array. 在C中,引用一个结构类型的时候,你必须说struct S,因此,sizeof(S)调用的是数组S。 In C++, struct is unnecessary. So the local S hides the global S. 在C++中,struct这个字不是必需的,所以局部变量S隐藏了全局变量S。 If you were to change the code to the following, you would get the expected results: 如果你把代码改成下面的样子,你就能得到你期望的结果了。 ...

2012-05-22 · 1 min · bystander

为什么sizeof(str.substr(0,3).c_str())=8?

问题: string str = "abcdefgdcb"; cout &lt; &lt; sizeof(str.substr(0,3).c_str()); For some reason, the above string is giving me 8. I assumed c_str() returns a null string, 由于某些原因,上面的这个字符串得到的结果是8,我估计c_str()返回了一个null, and sizeof uses the null to determine the size of the string. 并且sizeof函数使用这个null来定义这个字符串的大小。 答案: Because sizeof doesn’t give you the length of a string, 因为sizeof给你的不是一个字符串的长度, it gives you the size of the type (const char * in this case). Try strlen. 他给你的是这个类型的大小(这种情况下的类型是c_str()返回的const char*类型),想要得到正确的结果,试试strlen函数吧。 On your system, sizeof (const char ) == 8, like any other pointer. 在你的系统上,sizeof(const char)=8,和其他所有的指针类型一样。 8 is the size of a pointer on your machine (64-bit) 8是在你的64位电脑上一个指针的大小 There’s your problem. sizeof tells you the size of a variable, 别乱假设,sizeof告诉你一个变量的大小, which has nothing to do with the value inside the variable, ever. 他不会进入变量里面对变量做任何改变的。。永远不会。 问题:http://stackoverflow.com/q/10668764/764869

2012-05-21 · 1 min · bystander

快速排序算法

#include using namespace std; //化分区间,找到最后元素的排序位置。并返回分隔的点(即最后一数据排序的位置)。 //划分的区间是[nBegin, nEnd). pData是保存数据的指针 int Partition(int* pData, int nBeging, int nEnd) { int i = nBeging - 1; //分隔符号,最后nD保存在这里 --nEnd; int nD = pData[nEnd]; //比较的数据。 int nTemp; // 交换用的临时数据 //遍历数据比较,找到nD的位置,这里注意,比较结果是, //i的左边是小于等于nD的,i的右边是大于nD的 for (int j = nBeging; j < nEnd; ++j) { if (pData[j] <= nD) //如果数据比要比较的小,则在该数据的左边,与i+1交换 { ++i; //小于nD的数据多一个,所以要加1,i的左边数据都比nD小 nTemp = pData[i]; //交换数据 pData[i] = pData[j]; pData[j] = nTemp; } } //最后不要忘了吧nD和i+1交换,因为这里就是nD的位置咯。 ++i; pData[nEnd] = pData[i]; pData[i] = nD; return i; //返回nD的位置,就是分割的位置。 } //排序的递归调用。 int QuickSortRecursion(int* pData, int nBeging, int nEnd) { if (nBeging >= nEnd -1) //如果区域不存在或只有一个数据则不递归排序 { return 1; } //这里因为分割的时候,分割点处的数据就是排序中他的位置。 //也就是说他的左边的数据都小于等于他,他右边的数据都大于他。 //所以他不在递归调用的数据中。 int i = Partition(pData, nBeging, nEnd); //找到分割点 QuickSortRecursion(pData, nBeging, i); //递归左边的排序 QuickSortRecursion(pData, i + 1, nEnd); //递归右边的排序 return 1; } //快速排序 int QuickSort(int* pData, int nLen) { //递归调用,快速排序。 QuickSortRecursion(pData, 0, nLen); return 1; } int main() { int nData[10] = {5,9,3,2,1,6,20,45,88,75}; //测试数据 QuickSort(nData, 10); //调用快速排序 for (int i = 0; i < 10; ++i) //输出结果 { cout<

2012-05-19 · 1 min · bystander

对象数组的Xml序列化和反序列化

使用Serialization来进行序列化和反序列化,因此需要引入System.Xml.Serialization;命名空间。 为什么要做序列化和反序列化? .Net程序执行时,对象都驻留在内存中;内存中的对象如果需要传递给其他系统使用;或者在关机时需要保存下来以便下次再次启动程序使用就需要序列化和反序列化。 本文的原始例子在参考文中,但是参考文中没有给出反序列化的例子,且xml文件不清晰。于是修改了代码,同时实现对象数组序列化和反序列化。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; using System.IO; namespace UseXmlSerialization { class Program { static void Main(string[] args) { //声明一个猫对象 var cWhite = new Cat { Color = "White", Speed = 10, Saying = "I am a good WHITE cat" }; var cBlack = new Cat { Color = "Black", Speed = 10, Saying = "I am a good BLACK cat" }; CatCollection cc = new CatCollection { Cats = new Cat[] { cWhite, cBlack } }; //序列化这个对象 XmlSerializer serializer = new XmlSerializer(typeof(CatCollection)); StringWriter sw = new StringWriter(); serializer.Serialize(sw, cc); //序列化到StringWriter对象sw里 string strXml = sw.ToString(); Console.WriteLine("对象数组序列化后:"); Console.WriteLine(strXml); Console.WriteLine("xml反序列化后:"); StringReader sr = new StringReader(strXml); CatCollection c2 = serializer.Deserialize(sr) as CatCollection; for (int i = 0; i < 2; i++) //验证xml文件是否已经被反序列化为对象数组 { Console.WriteLine("I am Cat " + i); Console.WriteLine(c2.Cats[i].Color); Console.WriteLine(c2.Cats[i].Saying); Console.WriteLine(); } } } //以下为类定义 [XmlRoot("Cats")] public class CatCollection { [XmlElement("Cat")] public Cat[] Cats { get; set; } } public class Cat { //定义Color属性的序列化为cat节点的属性 [XmlAttribute("color")] public string Color { get; set; } //要求不序列化Speed属性 [XmlIgnore] public int Speed { get; set; } //设置Saying属性序列化为Xml子元素 [XmlElement("saying")] public string Saying { get; set; } } } 参考: http://www.cnblogs.com/yukaizhao/archive/2011/07/22/xml-serialization.html

2012-05-18 · 1 min · bystander

从hash函数到王小云的MD5破解

 以前一直纳闷不是说md5是不可逆的吗,那王小云怎么能破解呢。看到此文,豁然开朗,所谓的破解只是可以获得一个碰撞,使得两个文件的md5值一样。并不是说给定一个md5,能够得到原文。 密码学是理论计算机的一个很大的方向。之前准备先写密码学概论再提在hash函数破解上做出重大贡献的王小云教授的工作,不过前两天王小云获得求是杰出科学家奖以及100万奖金,在媒体上又掀起了一轮宣传狂潮,但是有些报道极端弱智,错误百出,所以我趁机纠正一下,并介绍密码学的一个组成部分——hash函数,以及王小云在这上面的工作。 王小云的主要工作是关于hash函数的破解工作。她在2005一个密码学会议上宣布破解了SHA-1,震惊了全世界。所以要介绍和理解她的工作,先看一下hash函数具体是怎么回事。 简单的说,hash函数就是把任意长的输入字符串变化成固定长的输出字符串的一种函数。通俗得说,hash函数用来生成信息的摘要。输出字符串的长度称为hash函数的位数。 目前应用最为广泛的hash函数是**SHA-1和MD5**,大多是128位和更长。 hash函数在现实生活中应用十分广泛。很多下载网站都提供下载文件的MD5码校验,可以用来判别文件是否完整。另外,比如在WordPress的数据库,所有密码都是保存的MD5码,这样即使数据库的管理员也无法知道用户的原始密码,避免隐私泄露(很多人在不同地方都是用的同一个密码)。 如果两个输入串的hash函数的值一样,则称这两个串是一个碰撞(Collision)。既然是把任意长度的字符串变成固定长度的字符串,所以,必有一个输出串对应无穷多个输入串,碰撞是必然存在的。 一个“优良”的hash函数 _f _应当满足以下三个条件: 1.任意y,找x,使得f(x)=y,非常困难。 2.给定x1,找x2,使得f(x1)=f(x2),非常困难。 3.找x1,x2,使得f(x1)=f(x2),非常困难。 上面的“非常困难”的意思是除了枚举外不可能有别的更快的方法。比如第3条,根据生日定理,要想找到这样的x1,x2,理论上需要大约2^(n/2)的枚举次数。 几乎所有的hash函数的破解,都是指的破坏上面的第三条性质,即找到一个碰撞(前两条都能被破坏的hash函数也太弱了点,早就被人抛弃了)。在密码学上还有一个概念是理论破解,指的是提出一个算法,使得可以用低于理论值得枚举次数找到碰撞。 王小云的主要工作是给出了MD5,SHA-0的碰撞,以及SHA-1的理论破解,她证明了160位SHA-1,只需要大约2^69次计算就能找出来,而理论值是2^80次。她的寻找MD5碰撞的方法是极端高效的。传说王小云当时在会议上把碰撞写出来,结果被下面的人验证发现不对,原来她把MD5算法的一个步骤弄错了。但是她立马联系她的当时留在中国的学生,修正算法,并找到一个新的碰撞。这一个是对的。 看到这里,那些认为中国国安局应该将这些结果封存作为秘密武器甚至幻想用这些成果来袭击美国之徒可以停住你们的YY了。这种形式上的破解,在大多数情况下没有实际性的作用。更别提MD5早就被美国人抛弃了。 但是,说这种破解一点实际意义都没有,那就侮辱了广大密码学家的智商,密码学家不会无缘无故的弄出碰撞这么一个概念来。下面简单的介绍一下在特定情况下,怎么利用给定的碰撞来做坏事(翻译自Attacking Hash Functions): Caesar给实习生Alice叫写了一封推荐信(letter)。同一天,Alice叫Caesar在推荐信上数字签名,并提供了一份推荐信的电子板。Caesar打开文件,发现和原件一模一样。所以他在文件上签了名。 几个月后,Caesar发现他的秘密文件被非法察看。这到底是怎么回事呢? a25f7f0b 29ee0b39 68c86073 8533a4b9 事实上,Alice要求Caesar签名的文件letter已经被Alice做了手脚,准确地说,Alice还准备了另外一个文件order,它们的MD5码完全一致。而Caesar的数字签名还依赖于MD5算法,所以Alice用order文件替换Letter文件之后,Caesar的数字签名依然有效。那封order给Alice提供了察看秘密文件的权限。 具体的实现方法可见Hash Functions and the Blind Passenger Attack。我在这里简单的解释一下(只是大致思路,具体实现方式,需要对文件结构信息有所了解): letter文件的内容是: if(x1==x1) show “letter” else show “order” order文件的内容是: if(x2==x1) show “letter” else show “order” 其中字符串"letter"和"order"代表两封信实际显示的内容。x1,x2是一个MD5的碰撞。 上面的方法,只供参考和学术用途,实际使用所引起的后果概不负责。 参考: 1.Attacking Hash Functions by Poisoned Messages “The Story of Alice and her Boss” 2.Hash function, wikipedia 3.SHA, wikipedia 4.Interview with Yiqun Lisa Yin concerning the attack on SHA-1 原文来自:http://zhiqiang.org

2012-05-15 · 1 min · bystander