在学习《软件工程》前,我个人倒是着实作了点项目,个人做的和团队合作的都有。但无论是个人做或是团队合作,给我印象最深的就是分工不明,虽然这种组织项目开发的方式快速,但与此对应所带来的恶果常常是混乱和持续不断的错误,并使得开发热情迅速消耗殆尽,最后变成了磨洋工。学了《软件工程》之后,觉得自己的思路开阔了不少。不过对于《软件工程》中所说的知易行难,所以结合自己的经验和当前的主流思想,总结了一些自己在做软件项目中所遇到的问题。
在软件项目中经常会遇到以下几个方面的问题:
1. 需求不充分同时经常变更;
2. 缺乏与客户的沟通;
3. 团队内部沟通不畅;
4. 不必要的复杂度;
5. 团队工作缺乏效率;
上面的第1条好理解,因为这是软件项目成败的基础,还软件是用来干什么的都没搞清楚,那么怎么可能指望它能得到客户的满意呢?为什么会出现需求不充分这种情况呢?主要有两点原因:其一是客户常常自己不能明确地了解自已的需求;其二是就算客户有能力了解一个复杂系统需求的所有细节,他也可能不知道如何有效地组织需求文档。同时就算是在项目开发将近结束的时候,仍会发现新的需求或是要进行需求更改。比如随着程序开发过程的深入,客户对亿们需要什么有了更清楚的了解;客户认识到最初的需求无法满足他们的需要;客户在需求阶段可能提出了一些他们并不真正需要的需求,然后在开发过程中又不想要了;客户需求的改变;客户方的职员或经理发生变更,由于想法不一致,导致需求的改变等等。
第2条也比较容易理解,因为要准确定义需求是一项困难的工作,因此,与客户保持开放和有建设性的交流是很重要的,那样做可以确保你所做的工作正是客户想得到的。一定要通过与客户的交互来完成需求分析。另外,每个项目都是从一些不完善的信息开始的,对于项目将如何进展也是处于一系列设想之中的。通常在随着项目进度的展开,这些设想将不得不进行调整,你和客户将分担这些调整所带来的影响,因此交流的结果最终必须达成协议。
第3条主要是当开发人员增多时,每个开发人员也相应地要与更多的人进行同步,根据《人月神话》这本书上所指到的那样,开发人员的增长,会导致团队里用于沟通的信息量呈二次级数增长。不畅的沟通有两种:太少或太多,太少会导致不能消除系统分歧,太多则浪费太多时间在协调而非代码开发上。
第4条的复杂度增加会占用大量资源和时间进行开发、维护和扩展,从而导致团队工作越来越繁杂且收效甚微。当一个程序规模扩大,内部交互增多时,就会使出错的机会增大,且这些漏洞在开发过程中难以发现。同时复杂性还会导致代码的难以理解。一个项目一般包含很多组件,当构件数目增加时,就会增加每个组件与更多组件交互的机会。当交互数量大大增加时,就不太容易理解程序正在做什么,也使得没有人能够修改或扩展这个程序了。
第5条是在开发中很常见的,因为没有哪个程序员是通过培训成为团队成员的,学校里也不会教学生如何参与团队系统的开发。作为团队成员,沟通、协作和建立共识的技能比个人的编程技能要重要得多,这对于学校出来的程序员来说是认识不到的,他们通常认为自己能写出没有毛病的代码,同时觉得别人的代码都不够完美或严谨。沟通、协作和建立共识是花时间且没必要的,他们崇敬的不是杰出的团队成员,也不是什么团队领导,而是个别有创造力的程序员。而结果是他们的代码难以理解并潜伏着错误,同时带来的问题就是开发时间的延长。
之前在古镇工作时,我的老板让我开发一个简单版的搜索引擎,哈哈
说实话当时做的也比较差, 多东西都没有想清楚
只是写了一个基础方向,即,管理员登录,然后选择把要爬抓的网站,把它网站上的页面读取,
然后收到数据库,
客户可以通过类似google的方式对提交查询,
有一些地方现在想起来比较差。
例如不检查页面是否存在
今天看了一下手册发现了下面的函数。速度不错。
get_meta_tags
描述
array get_meta_tags ( string filename [, int use_include_path] )打开 filename 逐行解析文件中的 <meta> 标签。此参数可以是本地文件也可以是一个 URL。解析工作将在 </head> 处停止。
将 use_include_path 设置为 1 将促使 PHP 尝试按照 include_path 标准包含路径中的每个指向去打开文件。这只用于本地文件,不适用于 URL。
返回的关联数组以属性 name 的值作为键,属性 content 的值作为值,所以你可以很容易地使用标准数组函数遍历此关联数组或访问某个值。属性 name 中的特殊字符将使用‘_’替换,而其它字符则转换成小写。如果有两个 meta 标签拥有相同的 name,则只返回最后出现的那一个。
注: 从 PHP 4.0.5 开始,get_meta_tags() 支持没有使用引号括起来的 HTML 属性。
{
$array = preg_split("/(\r\n?)/", $content, 2);
if (!isset($array[1])) $array[1] = null;
return $array;
}
//$url 要读取的地址,$allowExts 如果有跳转,允许跳转后的扩展名
function read($url, $allowExts, $header = true)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, $header);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_USERAGENT, "PHP WORLD Spider - WWW.PHPWORLD.CN");
if ($header == true)
{
$m = getHeader(curl_exec($ch));
}
else
{
$content = curl_exec($ch);
curl_close($ch);
return $content;
}
//截取内容
$header = $m[0];
$body = $m[1];
if (preg_match("/\nlocation:(.+)/", $header, $ar))
{
$url = trim($ar[1]);
$infos = @pathinfo(basename($url));
if (isset($infos["extension"]) && in_array(strtolower($infos["extension"]), $allowExts))
{
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, $header);
$content = curl_exec($ch);
curl_close($ch);
return $content;
}
}
return $body;
}
echo read("http://www.test.com/a.php", array("php"));
CURL 是 Client URL Library Functions 的缩写,由 Daniel Stenberg 创建,更多内容可以参考他的网站。最近几天突然对 HTTP 采集有了兴趣。之前我在做这方面程序,一般通过两种方法,一个是利用 PHP 自身的文件操作函数。PHP 的 fopen,readfile 都是可以支持 http 协议的,这样可以很方便的获取互联网上的内容。另一种方法是通过 PHP 的 Socket 函数,这个方法的好处是对各种协议都可以支持,缺点是使用起来比较麻烦,要对协议有一定的了解。在 HTTP 获取方面,运用 Socket 的 Snoopy 类是一个非常好用的 PHP HTTP 客户端,也是我原来最常用的方法。
随便翻翻 PHP 手册就会发现,PHP 本身可以支持 libcurl。用 C/C++ 写成的 libcurl 相比 Snoopy 更快速更可靠,而且除了 HTTP 协议外,还广泛支持其他协议( https, ftp, ladp 等等)。libcurl 并不是 PHP 默认加载的模块,具体如何启用可以参考 PHP 手册,这里就不多说了。PHP libcurl 使用非常简单,例如:
<?php
$ch = curl_init("http://www.php.net");
curl_exec($ch);
curl_close($ch);
?>
三行简单的程序就可以完成对 http://www.php.net 页面的读取并输出。当然更多的用法可以参考 PHP 手册。这里只说说我在写程序时遇到的一个问题,例如下面的程序:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.php.net"); //指定读取 php.net
curl_setopt($ch, CURLOPT_HEADER, 1); //返回内容中包含 HTTP 头
curl_setopt($ch, CURLOPT_NOBODY, 1); //不读取页面内容
curl_exec($ch); //执行 (1)
curl_setopt($ch, CURLOPT_URL, "http://www.php.net"); //指定读取 php.net
curl_setopt($ch, CURLOPT_HEADER, 0); //返回内容中不包含 HTTP 头
curl_setopt($ch, CURLOPT_NOBODY, 0); //读取页面内容
curl_exec($ch); //执行 (2)
curl_close($ch);
?>
按照我的想法,程序应该可以分别返回 HTTP 响应报头和页面的内容。可是上面这段程序执行结果为:(1)处正常返回 HTTP 响应报头,(2)不会返回任何内容。查了很多资料都没有提到这个问题。最终无奈,只好在读取(2)之前重新执行 curl_init(),即将上程序改成这样:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.php.net"); //指定读取 php.net
curl_setopt($ch, CURLOPT_HEADER, 1); //返回内容中包含 HTTP 头
curl_setopt($ch, CURLOPT_NOBODY, 1); //不读取页面内容
curl_exec($ch); //执行 (1)
curl_close($ch);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.php.net"); //指定读取 php.net
curl_setopt($ch, CURLOPT_HEADER, 0); //返回内容中不包含 HTTP 头
curl_setopt($ch, CURLOPT_NOBODY, 0); //读取页面内容
curl_exec($ch); //执行 (2)
curl_close($ch);
?>
返回结果正常。虽然可以通过这种方法解决问题,但对这个现象我感觉非常的奇怪。是 libcurl 本身的问题,还是我使用的方法不当呢?还希望熟悉 curl 的朋友帮忙指正一下。