昨天的开发日志:
昨天是让我相当高兴的一天——觉得停滞的团队建设向前跨出了坚实的一步。
上午LY老师召开了PM会议,5个小组的PM分享了各自小组所遇到的问题,并讨论了解决思路。会议得到的结论主要是要整顿实训纪律,保证工作时间的工作效率。会议后我也召集小组成员开了个小型会议,重新明确了大家的分工,以确保工作负担能充分的分散下去。
-------------------------------------------------------
会议后,老师介绍了一个有趣的软件:
iReaper
引用
iReaper是什么?
iReaper是由国内的.Net爱好者开发的桌面小工具,用来帮助您下载中文MSDN Webcast。
中文MSDN Webcast是什么?
中文MSDN Webcast是由微软中国主办的一系列网络在线课程。任何人只要能自由使用互联网,就能完全免费的收听收看实时的网络视频直播,或者下载往期的网络课程录像。
为什么要使用iReaper?
中文MSDN Webcast从2004年诞生至今已经开播了500多门课程,这些课程都是非常优秀的技术资料,很多爱好者都会选择将他们下载到自己的计算机上慢慢观看并做为长久收藏。然而如此众多的课程,1000多个文件,一个一个的下载、解压实在是一件可怕的工作,而这么多文件下载到硬盘上如何进行管理,如何将课程和文件一一对应起来,也是一件令人头疼的工作。
正是由于这些原因,iReaper诞生了。他的设计理念非常简单,从一个统一的视角:中文MSDN Webcast课程,为我们提供一个一站式的下载->解压->播放管理功能,使得这些网络视频资料能够更加充分的造福每一个开发者。
确实是个好东西。现在我可以让组员们在他们的上班时间总是有事情做了——没事做了就看教学视频去! XDD
-------------------------------------------------------
出于教学方便的原因,前天下午LY老师先介绍了Pet Shop的架构设计,并让每个小组思考如何根据自己的需要去选择裁剪并得到自己的架构设计。于是在PM会议之后,昨天上午就交给各小组去建立自己的“架构”——在Visual Studio里建立一个简单的解决方案,里面按照三层架构的形式建立作为后端的若干类库项目和作为前端的一个网站来。要求是:功能没任何要求,只要能build出来,能最低限度的演示该架构能完成从访问数据库一直到在页面交互就行。
这事情很简单,可以马上动手。把解决方案和项目/网站都建好之后,我们的解决方案资源图:
(呃,上面的图在拼接的时候把拼接位置弄错了 T T)
大致上就是把Pet Shop 3的架构照搬了过来,外加后期可能加上的Membership。本来在DAL层具体用哪个(虽然这里只有一个)版本实现应该由DALFactory读配置文件来决定,不过既然只要做“最低限度”,这里就只建了个空项目(所以那文件还叫Class1.cs)。另外DBUtility里的SQLHelper也做得很简单……连本来应该从Web.Config里配置的connectionString也硬编码到代码里了……嘛,偷懒过头了?
在数据库里放了点dummy数据来做准备。打开SQL Server Management Studio Express,直接登录进去。新建一个叫test的数据库,然后通过下面语句创建了一张表和两行dummy数据:
use test;
create table Message (
Id int,
Message varchar(50)
);
insert into Message (Id,Message) values (1,'I am the first message');
insert into Message (Id,Message) values (2,'I am the second message');
然后嘛做出了这样的页面:
有两个文本栏和一个按钮。在上面的文本栏里输入id,按按钮,下面的文本框里就会显示数据库里对应的信息。
对应的ASPX页面代码:
Default.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Search" />
<br />
<asp:TextBox ID="TextBoxResult" runat="server" Enabled="False"></asp:TextBox>
</div>
</form>
</body>
</html>
Code-behind的C#代码:
Default.aspx.cs:
using System;
using System.Collections.Generic;
using System.Web.UI;
using BLL;
using Model;
public partial class _Default : System.Web.UI.Page
{
private TextMessageBO bo;
protected void Page_Load(object sender, EventArgs e)
{
bo = new TextMessageBO();
}
protected void Button1_Click(object sender, EventArgs e)
{
IList<TextMessage> list = bo.GetMessageById(this.TextBox1.Text);
this.TextBoxResult.Text = list[0].Message;
}
}
看,几乎啥也没有……有的就是一骨架。
接下来在BLL里去实现页面上用的那个BO。TextMessageBO类也很简单,只有一个方法:GetMessageById(),里面只做一件事:检查用户的输入是否合法,当合法的时候委托给下面的DAL去完成数据访问,不合法则返回一条错误信息。在这个原型里我偷懒了,直接在BO里用了SQLServerDAL里的东西……前面已经提过了 XD
DAL层里有三个项目,IDAL定义了DAL里的接口,SQLServerDAL是对IDAL的一个实现,而DALFactory用于通过配置文件选择生成DAL的实例。没什么,我这里把一堆恶心东西都硬编码到SQLServerDAL的类里了:
TextMessageDAO.cs:
using System.Collections.Generic;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using IDAL;
using Model;
using DBUtility;
namespace SQLServerDAL
{
public class TextMessageDAO : ITextMessageDAO
{
private const string SQL_CONNECTION
= @"Data Source=(local)\SQLEXPRESS;Database=Test;Trusted_Connection=yes";
private const string SQL_SELECT_MESSAGE_BY_ID
= "SELECT Message.Id, Message.Message FROM Message WHERE Message.Id = @Id";
private const string PARAM_MESSAGE_ID = "@Id";
#region ITextMessageDAO 成员
public IList<TextMessage> GetMessageById(string id)
{
IList<TextMessage> list = new List<TextMessage>();
SqlParameter param = new SqlParameter(PARAM_MESSAGE_ID, SqlDbType.Int);
param.Value = id;
using (SqlDataReader reader = SqlHelper.ExecuteReader(
SQL_CONNECTION, CommandType.Text, SQL_SELECT_MESSAGE_BY_ID, param))
{
while (reader.Read())
{
TextMessage tm
= new TextMessage(reader.GetInt32(0), reader.GetString(1));
list.Add(tm);
}
}
return list;
}
#endregion
}
}
至于下面DBUtility里的SQLHelper基本上就是直接抄了Pet Shop的,没什么值得记录。啊对了,那些readonly的string都让我设成null了——因为没在Web.Config里写,而这里也用不到。
如此只用了很短时间超偷懒的搭出了个“架构”。然后上午的时间就颓废了。
-------------------------------------------------------
之前我一直很困扰该如何把拖着的BPM图画完。昨天下午组员们终于有所行动,把他们原本负责的部分拿回去修改了一番。一个下午的努力后,这部分算是了结了。呼,松了一口气。
不过PowerDesigner在画图方面的功能真的太弱了。如果能帮忙给个什么snap to grid,然后帮忙把箭头也snap to grid那就好多了。不然要在PowerDesigner里想画出条水平线加竖直线的折线都异常困难,总是歪的……
=======================================================
今天的开发日志:
今天上午是想赶紧把昨晚组员们给我的BPM图赶紧整合到自己的图上,不过老师却安排了比较多的点评和教学,把这计划打乱了。
先是对之前各个小组所搭建的“架构”原型的点评。要求各个小组先把那个原型上传到VSS服务器上。签入解决方案的时候我突然后悔之前没先把网站和项目的保存目录设置好,按照Visual Studio 2005提供的默认路径保存后,Projects跟Websites就分开了。一着急,直接就把网站目录跟项目目录一股脑的扔到了VSS上。
我们组是第一个上去演示的。结果直接用VS2005打开那解决方案文件,果然说无法打开的网站了……呃。修了一下之后终于能演示。效果还可以吧,反正三层架构都很清晰了。后面演示的几个组做的也差不多,应该说在这点上没什么优势不优势的问题,太简单了。
后来LY老师提到了Projects跟Website不在一起该如何解决的问题。先是问有没有人有什么办法,我就上去说了下直接用文本编辑器修改*.sln文件的办法。像我们的那个Website1.sln文件开头是这样的:
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "C:\...\WebSite1\", "..\..\WebSite\WebSite1\", "{6AC7E574-A57D-43D1-9CDC-3B00DAD66C55}"
所以其实很好办,把WebSite1里的内容复制过来(到".\Web\"),然后改改这个sln文件就行:
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "WebSite1", "Web\", "{6AC7E574-A57D-43D1-9CDC-3B00DAD66C55}"
很方便。
-------------------------------------------------------
接下来,老师介绍了一下用例图的绘制。这次我们被要求使用Borland Together 2006 for Visual Studio。然则我的VS2005打过了SP1,结果就是无法安装Together。于是我索性就不装了,这可恶的东西。Borland公司的产品还真是从来没给我带来过好感。这恶劣的兼容性,哼哼。我从个人偏好的角度十分讨厌Borland,这次只是更增加了厌恶。
不管了,用例图只好尽量分配给组员们做吧。虽说己所不欲勿施于人,但他们至少没给VS2005打SP1所以能装上Together……
上午看了几段用Together画用例图和顺序图的教学视频。
-------------------------------------------------------
下午,很多人都请假去面试了,我们的支持经理也在其中。总觉得机房人里一少,整个机房就有种惰性……
Anyway,下午各组都在完成用例文档。我们组是由PX和YLY来做这部分,我还在完成BPM图的最终整合,而计划经理还在头疼如何将计划定义最终完成。
有同学提出要老师再播一次上午提供的视频。老师又亮出了个有趣的玩意:NetMeeting。
这不是什么新东西,其实我们的Windows上都有,就是没用过而已。在“运行”输入“conf”就开始配置NetMeeting。配置好了之后就可以通过新生成的快捷方式来使用NetMeeting了。
然后老师就通过NetMeeting来播放视频给需要的同学看。嗯,不错。
-------------------------------------------------------
在下午的工作时间快结束时,ZHY老师通过SharePoint架设的开发部内网给出了业务分析的范例。
但这些都是BPM文件,如果直接打开它们,就会侵入到“当前”的工作区(workspace)。PowerDesigner在这点上做得特别……傻乎。在File菜单里确实有“Close Workspace”选项,但按了之后其实还是有一个活动的工作区(“当前工作区”),却没有任何地方告诉用户可以“新建”一个新工作区。假如前一次在关闭PowerDesigner前没有把工作区关掉,那么以后直接打开一个BPM文件时这文件就会被加到上次开着的那个工作区——原本的工作区就被修改了,让人很不爽。也可能是我没摸清楚怎么用,不过看老师也似乎没关心过这个问题,或许并不是什么问题?还是得想办法既要正确打开老师给的范例BPM文件,又不要破坏自己的工作区。
还好,PowerDesigner用的文件格式都是XML文件,内容是纯文本的,因而可以自己制作一个workspace文件(*.sws)出来去指向那些BPM文件(*.bpm)。
随便打开其中一个BPM文件:
AttendanceFuture.bpm:
<?xml version="1.0" encoding="UTF-8"?>
<?PowerDesigner AppLocale="UTF16" ID="{060A9EA9-1FDA-40C8-9CCD-6B01D2D534D1}" Label="" Name="AttendanceFuture" Objects="53" Symbols="32" Target="Analysis" Type="{3D3C409C-B60D-430E-A1C4-B880653AC634}" signature="BPM_MODEL_XML" version="12.0.0.1700"?>
<!-- ...内容省略... -->
可以看到在XML声明之后有一个PowerDesigner指令,里面有些比较有趣的属性;这里要关注的是ID、Name和Type。
然后打开我之前正在用的工作区文件:
Workspace_NetOA.sws:
<?xml version="1.0" encoding="UTF-8"?>
<?PowerDesigner signature="Workspace" version="12.0.0.1700"?>
<!-- do not edit this file -->
<Workspace>
<Local Expanded="Yes">
<Model Expanded="Yes" ID="{BB40561B-B815-4003-9562-0F6144EBA083}" Name="NetOA" Type="{3D3C409C-B60D-430E-A1C4-B880653AC634}" URL="NetOA.bpm"/>
</Local>
<BrowserModule Name="Repository"/>
</Workspace>
结构明了,一看就知道应该在Workspace/Local里添加Model节点来描述工作区里的图。Model里Expanded属性看来重要性不大,而URL属性一看就知道应该是文件路径;剩下的ID、Name和Type属性则无法一眼看出。但我们知道BPM文件开头的PowerDesigner指令也有相同的几个属性,只要复制过来就可以了。
于是手工制作出一个新的工作区文件:
NetOA.sws:
<?xml version="1.0" encoding="UTF-8"?>
<?PowerDesigner signature="Workspace" version="12.0.0.1700"?>
<!-- do not edit this file -->
<Workspace>
<Local Expanded="Yes">
<Model Expanded="Yes" ID="{060A9EA9-1FDA-40C8-9CCD-6B01D2D534D1}" Name="AttendanceFuture" Type="{3D3C409C-B60D-430E-A1C4-B880653AC634}" URL="AttendanceFuture.bpm"/>
<Model Expanded="No" ID="{9505FC94-59B3-49BC-86B8-D595CEE4107A}" Name="CustomerFuture" Type="{3D3C409C-B60D-430E-A1C4-B880653AC634}" URL="CustomerFuture.bpm"/>
<Model Expanded="No" ID="{051C4EB1-4723-44E2-A12F-A05D9524C430}" Name="MailFuture" Type="{3D3C409C-B60D-430E-A1C4-B880653AC634}" URL="MailFuture.bpm"/>
<Model Expanded="No" ID="{99C33681-D194-400B-B10A-F14CF36BA185}" Name="ContactFuture" Type="{3D3C409C-B60D-430E-A1C4-B880653AC634}" URL="ContactFuture.bpm"/>
<Model Expanded="No" ID="{AB77AAE9-AA10-40D4-AEFB-F36F92257F12}" Name="MessageFuture" Type="{3D3C409C-B60D-430E-A1C4-B880653AC634}" URL="MessageFuture.bpm"/>
</Local>
<BrowserModule Name="Repository"/>
</Workspace>
用PowerDesigner打开,实验后确信没问题。总算不用干扰自己的工作区。