Set Jmail=server.createobject("Jmail.Message")
Jmail.Silent=true
Jmail.Charset="gb2312"
Jmail.Priority=3 '优先级
Jmail.MailServerUserName="xxxx@xxxx.com"
Jmail.MailServerPassword="123456"
Jmail.From="xxxx@xxxx.com"
Jmail.FromName="xxxx@xxxx.com"
Jmail.Subject=name
Jmail.AddRecipient rs("mail")
JMail.HTMLBody=body
Jmail.Send("mail.xxxx.com")
send_jmail="ok"
if err then
err.clear
send_jmail="no"
end if
Jmail.close()
Set Jmail=nothing
VS2008快捷键大全
Ctrl+m+Crtr+o折叠所有大纲
Ctrl+M+Crtr+P: 停止大纲显示
Ctrl+K+Crtr+C: 注释选定内容
Ctrl+K+Crtr+U: 取消选定注释内容
Ctrl+J : 列出成员 智能感知
Shift+Alt+Enter: 切换全屏编辑
Ctrl+B,T / Ctrl+K,K: 切换书签开关
Ctrl+B,N / Ctrl+K,N: 移动到下一书签
Ctrl+B,P: 移动到上一书签
Ctrl+B,C: 清除全部标签
Ctrl+I: 渐进式搜索
Ctrl+Shift+I: 反向渐进式搜索
Ctrl+F: 查找
Ctrl+Shift+F: 在文件中查找
F3: 查找下一个
Shift+F3: 查找上一个
Ctrl+H: 替换
Ctrl+Shift+H: 在文件中替换
Alt+F12: 查找符号(列出所有查找结果)
Ctrl+Shift+V: 剪贴板循环
Ctrl+左右箭头键: 一次可以移动一个单词
Ctrl+上下箭头键: 滚动代码屏幕,但不移动光标位置。
Ctrl+Shift+L: 删除当前行
Ctrl+M,M: 隐藏或展开当前嵌套的折叠状态
Ctrl+M,L: 将所有过程设置为相同的隐藏或展开状态
Ctrl+E,S: 查看空白
Ctrl+E,W: 自动换行
Ctrl+G: 转到指定行
Shift+Alt+箭头键: 选择矩形文本
Alt+鼠标左按钮: 选择矩形文本
Ctrl+Shift+U: 全部变为大写
Ctrl+U: 全部变为小写
代码快捷键
Ctrl+Shift+空格键 / Ctrl+K,P: 参数信息
Ctrl+K,I: 快速信息
Ctrl+E,U / Ctrl+K,U: 取消选定注释内容
Ctrl+K,M: 生成方法存根
Ctrl+K,X: 插入代码段
Ctrl+K,S: 插入外侧代码
F12: 转到所调用过程或变量的定义
窗口快捷键
Ctrl+W,W: 浏览器窗口
Ctrl+W,S: 解决方案管理器
Ctrl+W,C: 类视图
Ctrl+W,E: 错误列表
Ctrl+W,O: 输出视图
trl+W,P: 属性窗口
Ctrl+W,T: 任务列表
Ctrl+W,X: 工具箱
Ctrl+W,B: 书签窗口
Ctrl+W,U: 文档大纲
Ctrl+D,B: 断点窗口
Ctrl+D,I: 即时窗口
Ctrl+Tab: 活动窗体切换
Ctrl+Shift+N: 新建项目
Ctrl+Shift+O: 打开项目
Ctrl+Shift+S: 全部保存
Shift+Alt+C: 新建类
Ctrl+Shift+A: 新建项
Shift+Alt+Enter: 切换全屏编辑
Ctrl+B,T / Ctrl+K,K: 切换书签开关
Ctrl+B,N / Ctrl+K,N: 移动到下一书签
Ctrl+B,P: 移动到上一书签
Ctrl+B,C: 清除全部标签
Ctrl+I: 渐进式搜索
Ctrl+Shift+I: 反向渐进式搜索
Ctrl+F: 查找
Ctrl+Shift+F: 在文件中查找
F3: 查找下一个
Shift+F3: 查找上一个
Ctrl+H: 替换
Ctrl+Shift+H: 在文件中替换
Alt+F12: 查找符号(列出所有查找结果)
Ctrl+Shift+V: 剪贴板循环
Ctrl+左右箭头键: 一次可以移动一个单词
Ctrl+上下箭头键: 滚动代码屏幕,但不移动光标位置。
Ctrl+Shift+L: 删除当前行
Ctrl+M,M: 隐藏或展开当前嵌套的折叠状态
Ctrl+M,L: 将所有过程设置为相同的隐藏或展开状态
Ctrl+M,P: 停止大纲显示
Ctrl+E,S: 查看空白
Ctrl+E,W: 自动换行
Ctrl+G: 转到指定行
Shift+Alt+箭头键: 选择矩形文本
Alt+鼠标左按钮: 选择矩形文本
Ctrl+Shift+U: 全部变为大写
Ctrl+U: 全部变为小写
WAP2.0知识分享PPT

对于手机WAP的开发,大家也许很陌生,有些人甚至不知道如何入手。
其实只要有HTML和CSS的基础,加上熟识WAP2.0规范,就可以制作WAP2.0页面。
而现在国内关于WAP2.0规范的资料和教程很少,在结合自己多次项目开发的经验,并翻阅熟读WAP2.0英文规范的基础上,为大家做一个简单扼要的WAP2.0知识分享,分享内容主要为WAP2.0规范中的XHTML MP和WAP CSS。
怿飞期望大家看完PPT,都可以轻松打造属于自己的WAP2.0站点。
点击下载此文件
使用交叉联接
使用交叉联接
没有 Where 子句的交叉联接将产生联接所涉及的表的笛卡尔积。第一个表的行数乘以第二个表的行数等于笛卡尔积结果集的大小。下面是 Transact-SQL 交叉联接示例:
USE pubs
Select au_fname, au_lname, pub_name
FROM authors CROSS JOIN publishers
orDER BY au_lname DESC
结果集包含 184 行(authors 有 23 行,publishers 有 8 行;23 乘以 8 等于 184)。
不过,如果添加一个 Where 子句,则交叉联接的作用将同内联接一样。例如,下面的 Transact-SQL 查询得到相同的结果集:
USE pubs
Select au_fname, au_lname, pub_name
FROM authors CROSS JOIN publishers
Where authors.city = publishers.city
orDER BY au_lname DESC
— 或
USE pubs
Select au_fname, au_lname, pub_name
FROM authors INNER JOIN publishers
ON authors.city = publishers.city
orDER BY au_lname DESC
C#的反射方法
using System;
namespace Webtest
…{
public interface interface1
…{
int add();
}
public class ReflectTest:interface1
…{
public String Write;
private String Writec;
public String Writea
…{
get
…{
return Write;
}
set
…{
Write = value;
}
}
private String Writeb
…{
get
…{
return Writec;
}
set
…{
Writec = value;
}
}
public ReflectTest()
…{
this.Write = “Write”;
this.Writec = “Writec”;
}
public ReflectTest(string str1,string str2)
…{
this.Write = str1;
this.Writec = str2;
}
public string WriteString(string s,int b)
…{
return “欢迎您,” + s + “—” + b; ;
}
public static string WriteName(string s)
…{
return “欢迎您光临,” + s;
}
public string WriteNoPara()
…{
return “您使用的是无参数方法”;
}
private string WritePrivate()
…{
return “私有类型的方法”;
}
public int add()
…{
return 5;
}
}
}
然后,建立再建立一个项目引入该HelloWorld.dll,
using System;
using System.Threading;
using System.Reflection;
class Test
…{
delegate string TestDelegate(string value,int value1);
static void Main()
…{
//Assembly t = Assembly.LoadFrom(“HelloWorld.dll”); 与下面相同的效果
Assembly t = Assembly.Load(“HelloWorld”);
//**********************************************************************
foreach (Type aaa in t.GetTypes())
…{
//Console.Write(aaa.Name); //显示该dll下所有的类
}
//**********************************************************************
Module[] modules = t.GetModules();
foreach (Module module in modules)
…{
//Console.WriteLine(“module name:” + module.Name);//显示模块的名字本例为”HelloWorld.dll”
}
//**********************************************************************
Type a = typeof(Webtest.ReflectTest);//得到具体的类的类型,和下面一个效果
//Type a = t.GetType(“Webtest.ReflectTest”);//
//Console.Write(a.Name);
//**********************************************************************
string[] bb =…{ “aaaa”, “bbbbb” };
object obj = Activator.CreateInstance(a,bb); //创建该类的实例,后面的bb为有参构造函数的参数
//object obj = t.CreateInstance(“Webtest.ReflectTest”);//与上面方法相同
//**********************************************************************
MethodInfo[] miArr = a.GetMethods();
foreach (MethodInfo mi0 in miArr)
…{
//Console.Write(mi0.Name); //显示所有的共有方法
}
//**********************************************************************
MethodInfo mi = a.GetMethod(“WriteString”);//显示具体的方法
object[] aa=…{“使用的是带有参数的非静态方法”,2};
string s = (string)mi.Invoke(obj,aa); //带参数方法的调用
MethodInfo mi1 = a.GetMethod(“WriteName”);
String[] aa1 =…{“使用的是静态方法”};
string s1 = (string)mi1.Invoke(null, aa1); //静态方法的调用
MethodInfo mi2 = a.GetMethod(“WriteNoPara”);
string s2 = (string)mi2.Invoke(obj, null); //不带参数的方法调用
MethodInfo mi3 = a.GetMethod(“WritePrivate”,BindingFlags.Instance | BindingFlags.NonPublic);
string s3 = (string)mi3.Invoke(obj, null); //私有类型方法调用
//Console.Write(s3);
//**********************************************************************
PropertyInfo[] piArr = a.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (PropertyInfo pi in piArr)
…{
//Console.Write(pi.Name); //显示所有的属性
}
//**********************************************************************
PropertyInfo pi1=a.GetProperty(“Writea”);
//pi1.SetValue(obj, “Writea”, null);
//Console.Write(pi1.GetValue(obj,null));
PropertyInfo pi2 = a.GetProperty(“Writeb”, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
pi2.SetValue(obj, “Writeb”, null);
//Console.Write(pi2.GetValue(obj, null));
FieldInfo fi1 = a.GetField(“Write”);
//Console.Write(fi1.GetValue(obj));
//**********************************************************************
ConstructorInfo[] ci1 = a.GetConstructors();
foreach (ConstructorInfo ci in ci1)
…{
//Console.Write(ci.ToString()); //获得构造函数的形式
}
ConstructorInfo asCI = a.GetConstructor(new Type[] …{ typeof(string), typeof(string) });
//Console.Write(asCI.ToString());
//**********************************************************************
Webtest.interface1 obj1 = (Webtest.interface1)t.CreateInstance(“Webtest.ReflectTest”);
Webtest.ReflectTest obj2 = (Webtest.ReflectTest)t.CreateInstance(“Webtest.ReflectTest”);
//Console.Write(obj1.add());典型的工厂模式
//**********************************************************************
foreach (Type tt in t.GetTypes())
…{
if (tt.GetInterface(“interface1”)!=null)
…{
Webtest.interface1 obj3 = (Webtest.interface1)Activator.CreateInstance(a);
//Console.Write(obj3.add());
}
}
//**********************************************************************
TestDelegate method = (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), obj, “WriteString”);
//动态创建委托的简单例子
//Console.Write(method(“str1”, 2));
//**********************************************************************
ConstructorInfo asCI1 = a.GetConstructor(new Type[0]);
Webtest.ReflectTest obj5 = (Webtest.ReflectTest)asCI1.Invoke(null);
//通过无参构造函数实例化的方法
//Console.Write(obj5.Writea);
ConstructorInfo asCI2 = a.GetConstructor(new Type[] …{ typeof(string), typeof(string) });
//通过有参构造函数实例化的方法
Webtest.ReflectTest obj6 = (Webtest.ReflectTest)asCI2.Invoke(bb);
Console.Write(obj6.Writea);
//**********************************************************************
Console.Read();
}
}
window.close屏蔽提示窗口
不多说了,就这两句
window.opener=null; window.close();
Flex介绍很全很详细
一,概述
二,Flex开发环境
三,RIA的发展和Flex的版本历史
四,使用FLEX BUILDER 2进行应用开发步骤
五,Flex编程语言
六,MXML标记语言
七,ActionScript编程语言
八,Flex面向对象编程
九,Flex的安全机制
十,Flex程序性能的优化
十一,Flex与Flash
十二,Flex社区的开源的组件库项目
参考
地址:
http://www.deepcast.net/wiki/ow.asp?p=Flex&revision=61#h3
Linq To Sql
Linq To SQL是Microsoft开发的针对解决data!=object问题的新技术。在笔者的一系列的文章中,对它已经做了大量的介绍。现在,笔者将从经验的角度,谈谈它的优劣。
1、Linq To SQL的优点
在Linq To SQL推出之前,我们只是把sql语句形成一个string,然后,通过ado.net传给sql server,返回结果集.这里的缺陷就是,如果你sql语句写的有问题,只有到运行时才知道.而且并不所有的人都懂数据库的。Linq To SQl 在一切围绕数据的项目内都可以使用。特别是在项目中缺少sql server方面的专家时,Linq To SQl的强大的功能可以帮我们快速的完成项目。Linq To SQl的推出,是让大家从烦琐的技术细节中解脱出来,更加关注项目的逻辑。Linq To Sql的出现,大大降低了数据库应用程序开发的门楷,它实质是事先为你构架了数据访问层,势必将加快数据库应用程序的开发进度。Linq To Sql解放了众多程序员,让他们的把更多的精力放到业务逻辑以及code上,而不是数据库。对于初学者来讲,Linq To Sql可以让他们迅速进入数据库应用程序开发领域,节约了培训成本。
Linq To SQl 的实现,是在ado.net和C#2.0的基础上的。它通过自动翻译sql语句,并把结果集创建成对象并返回。这里我们可以看出,发送到Sql Server端的sql语句是Linq To Sql自动生成的。这对不懂sql的人来说,无疑是个福音。第二,Linq To Sql语句是在编译期间就做检查的。而不是运行时检查。这样,那里出了问题,可以及时更改,而不是到了运行时才发现问题。第三,Linq To Sql是针对对象操作的,更符合今天的oo呼声。
在Linq To SQl 之前,在java领域有Hibernate,在net领域有NHibernate技术,来实现object/relational 持久和查询服务。那和NHibernate比起来,它又有那些优势呢.第一,影射代码自动生成。VS2008提供了SqlMetal和OR Designer两个工具来完成此步骤。而在NHibernate中,你不得不自己手工写。第二,影射代码有更多的选择.NHibernate只能把数据库的信息配置在一个xml中,而Linq To Sql有两种方式,一个是放到xml中,我们称为Externl Mapping, 再一种就是以Attribute的形式,存在于各个property中。当然,笔者本人并没有使用过NHibernate,只是从资料上得到这些消息,所以无法给出更多的比较。
2、Linq To Sql的缺点
很久前,有个网友问到这么一个问题。他在界面上有个DataView,里面绑定了一些Column,然后他勾选那一列就按某列排序。其传回的参数是列的名字。然后问我该怎么用Dlinq 来实现。
在以前拼接Sql语句的年代,这个很简单,一个” order by ” + string,想按什么排就按什么来排。而现在dlinq是用是一个对象的属性,已经不可能拼接了。我当时给他的答案是这样的。
以下是引用片段:
private void Methods(string orderId)
{
var q = db.Customers.Select(c=>c);
switch(orderId)
{
case “ID”:
q = q.OrderBy(c=>c.ID);
break;
case “Name”:
q = q.OrderBy(c=>c.Name);
break;
default:
break;
}
var result = q.ToList();
}
我那时也没有想出一个更好的方案来。而后告诉他去查下Compiled Query,说不定可以找到更方便的。后来我才在这个例子中,看到更方便的。
以下是引用片段:
var query =
db.Customers.Where(“City == @0 and orders.Count >= @1”, “London”, 10).
orderBy(“CompanyName”).
Select(“New(CompanyName as Name, Phone)”);
在这里OrderBy直接接收的就是列的名字。再仔细一看,好像Where里是Linq的语句哎,那OrderBy也该是linq语句。后来,我把CompanyName换成小写的,一跑过了。莫非真的是列的名字?出个难题吧。找了一个列名,是带空格的,重新来建这个工程.一跑,错了!把列名用中国扩号扩起来了,也是错了。咳,只是动态构造Expression Tree而已,永远都不能直接接收列的名字。这个例子看着是很简单,可不知道你有没有注意到它有一个80多k的Dynamic.cs文件。更有意思的事情是,它的名称空间是System.Linq.Dynamic.看样子,ms本来是打算把它加在.net3.5中吗.不晓得为什么放到了例子中了。这个名称空间下,其主要内容就是动态构造Expression Tree. 和Linq To Sql进阶系列(七)动态查询一文中的方法类似。只是,它还包含了解析字符串部分.
从上面那个例子中,可以看出,Linq To Sql在这种动态构造语句时,比拼接sql麻烦很多。在Linq To Sql进阶系列(七)动态查询 一文中,笔者极力推荐使用object的查询。这符合Linq To Sql的设计原则。因为,它主要是为了解决data!=objects 的问题而产生的.它所有的操作均针对object,那就让我们使用object的查询吧.
当然,依然会有人习惯拼接字符串.我并不认为这是个坏毛病。只是有点不符合oo思想而已。事实上,在Linq To Sql中,你依然可以使用拼接字符串的形式,而不使用它提供的Query Expression. 它提供了这么两个接口,一个是,db.ExecuteQuery(string sql); 另一个是,db.ExecuteCommand(string sql);这两个函数都是直接接收 sql语句的.习惯拼接的人,依然可以调用它们来实现你的程序。特别是第一个,其返回的就是一个对象的集合,多少还是有点oo思想的。
看下面的例子:
以下是引用片段:
var products = db.ExecuteQuery(
“Select [Product List].ProductID, [Product List].ProductName ” +
“FROM Products AS [Product List] ” +
“Where [Product List].Discontinued = 0 ” +
“ORDER BY [Product List].ProductName;”
).ToList();
它返回的就是product的集合。而不是什么dataset和datatable之类的。这里,你可以大胆的使用该函数继续拼接你的sql吧,再看下面这个:
以下是引用片段:
db.ExecuteCommand(“Update Products SET UnitPrice = UnitPrice + 1.00”);
它在做批处理的时候,你想不用它,都不行.当然,你如果觉得性能不是问题的话,那就用submitchange方法来做更新好了。简单明了的说,Linq To Sql在批处理更新的时候,SubmitChange只会一个个的更新。浪费时间资源.而这个接口,恰好满足了批处理更新或删除的问题。从这两个例子,我们可以看出。没有任何方案是万能的。各有各的优点。
3、Linq To Sql的性能
Linq 的性能已经被好多人提及.Linq To Object 的性能大家讨论的比较多些.它确实比自己实现的查找要慢.但是当数据量特别大时,更多是时间是花在分配虚拟内存上了,那么他们的差别就不是那么明显了。 Linq To Sql是又如何提升性能的?第一,采用延迟加载(deferred loading)技术。语句是声明了,但是并不立即执行,而是在真正需要的时候才执行。第二,采用缓存技术。已经取到内存的数据,再依次提取时,会先从缓存中返回,而不是再次访问数据库。当然,笔者建议,不要对象的时候,没有必要使用Linq To Sql.比如,只是填充DataView或DataGrid时,返回dataset或datatable要比用Linq To Sql实现的快很多。
结论:各种技术都有其自身的优点和缺点。使用什么样的技术,完全在于项目对性能和开发进度的要求,以及程序员自身的爱好有关。扬长避短,才是正道。
Python的学习资源
Python基本安装:
* http://www.python.org/ 官方标准Python开发包和支持环境,同时也是Python的官方网站;
* http://www.activestate.com/ 集成多个有用插件的强大非官方版本,特别是针对Windows环境有不少改进;
Python文档:
* http://www.python.org/doc/current/lib/lib.html Python库参考手册。
* http://www.byteofpython.info/ 可以代替Tutorial使用,有中文译版的入门书籍。
* http://diveintopython.org/ 一本比较全面易懂的入门书,中文版翻译最近进步为很及时的5.4了。
* http://www.python.org/peps/pep-0008.html 建议采用的Python编码风格。
* http://doc.zoomquiet.org/ 包括Python内容的一个挺全面的文档集。
常用插件:
* http://www.pfdubois.com/numpy/ Python的数学运算库,有时候一些别的库也会调用里面的一些功能,比如数组什么的;
* http://www.pythonware.com/products/pil/ Python下著名的图像处理库Pil;
* http://simpy.sourceforge.net/ 利用Python进行仿真、模拟的解决方案;
* Matplotlib 据说是一个用来绘制二维图形的Python模块,它克隆了许多Matlab中的函数, 用以帮助Python用户轻松获得高质量(达到出版水平)的二维图形;
* http://www.amk.ca/python/code/crypto python的加解密扩展模块;
* http://cjkpython.i18n.org/ 提供与python有关的CJK语言支持功能:转码、显示之类。
* Psyco、Pyrex:两个用于提高Python代码运行效率的解决方案;
* Pyflakes、PyChecker、PyLint:都是用来做Python代码语法检查的工具。
* http://wxpython.sourceforge.net/ 基于wxWindows的易用且强大的图形界面开发包wxPython;
* http://www.pygame.org/ 用Python帮助开发游戏的库,也可以用这个来播放视频或者音频什么的,大概依靠的是SDL;
* http://starship.python.net/crew/theller/py2exe/ win下将Python程序编译为可执行程序的工具,是一个让程序脱离Python运行环境的办法,也可以生成Windows服务或者COM组件。其他能完成Python脚本到可执行文件这个工作的还有Gordon McMillan's Installer、Linux专用的freeze以及py2app、setuptools等。不过此类工具难免与一些模块有一些兼容性的问题,需要现用现测一下。
* 嵌入式数据库:BerkeleyDB的Python版,当然还有其他的好多。
* PEAK提供一些关于超轻量线程框架等基础性重要类库实现。
部分常用工具:
* http://www.scons.org/ Java有Ant这个巨火的构建工具,Python的特性允许我们构建更新类型的构建工具,就是scons了。
* Python Sidebar for Mozilla FireFox的一个插件,提供一个用来查看Python文档、函数库的侧边栏。
* IPython 很好用的Python Shell。wxPython发行版还自带了PyCrust、PyShell、PyAlaCarte和PyAlaMode等几个工具,分别是图形界面Shell和代码编辑器等,分别具有不同特点可以根据自己的需要选用。
* Easy Install 快速安装Python模块的易用性解决方案。
推荐资源:
* Parnassus山的拱顶 巨大的Python代码库,包罗万象。既可以从上面下载代码参考学习,同时也是与Python有关程序的大列表。
* Python号星际旅行船 著名Python社区,代码、文档、高人这里都有。
* faqts.com的Python程序设计知识数据库 Python程序设计知识库,都是与Python有关的程序设计问题及解决方法。
* 啄木鸟 Pythonic 开源社区 著名的(也可以说是最好的)国内Python开源社区。
代码示例:
* http://newedit.tigris.org/technical.htm Limodou的NewEdit编辑器的技术手册,讨论了一些关于插件接口实现、i18实现、wxPython使用有关的问题,值得参考。
其他东西:
* http://www.forum.nokia.com/main/0,,034-821,00.html Nokia居然发布了在Series 60系统上运行Python程序(图形界面用wxPython)的库,还有一个Wiki页是关于这个的:http: //www.postneo.com/postwiki/moin.cgi/PythonForSeries60 。Python4Symbian这个页面是记录的我的使用经验。
* pyre:使用Python完成高性能计算需求的包,真的可以做到么?还没研究。
* Parallel Python:纯Python的并行计算解决方案。相关中文参考页面
* Pexpect:用Python作为外壳控制其他命令行程序的工具(比如Linux下标准的ftp、telnet程序什么的),还没有测试可用程度如何。
* pyjamas:Google GWT的Python克隆,还处在早期版本阶段。
* Durus:Python的对象数据库。
有意思的东西:
* Howie:用Python实现的MSN对话机器人。
* Cankiri:用一个Python脚本实现的屏幕录像机。
参考资料
* ZDNET文章:学习Python语言必备的资源
* Pythonic Web 应用平台对比
* 在wxPython下进行图像处理的经验 (其实,仅使用wxPython也可以完成很多比较基础的图像处理工作,具体可以参照《wxPython in Action》一书的第12节)
* 通过win32扩展接口使用Python获得系统进程列表的方法
* 如何获得Python脚本所在的目录位置
* Python的缩进问题
* py2exe使用中遇到的问题
* idle的中文支持问题
* 序列化存储 Python 对象
Python IDE
我的IDE选择经验
* http://www.xored.com Trustudio 一个基于Eclipse的、同时支持Python和PHP的插件,曾经是我最喜欢的Python IDE环境,功能相当全了,不过有些细节不完善以致不大好用。
* http://pydev.sourceforge.net/ 另一个基于Eclipse的,非常棒的Python环境,改进速度非常快,现在是我最喜欢的IDE。
* http://www-900.ibm.com/developerWorks/cn/opensource/os-ecant/index.shtml 用 Eclipse 和 Ant 进行 Python 开发
* http://www.die-offenbachs.de/detlev/eric3.html ERIC3 基于QT实现的不错的PYTHON IDE,支持调试,支持自动补全,甚至也支持重构,曾经在Debian下用它,但图形界面开发主要辅助qt,我倾向wxpython,所以最后还是放弃了这个。
* http://www.scintilla.org/ 同时支持Win和Linux的源代码编辑器,似乎支持Python文件的编辑。
* http://boa-constructor.sourceforge.net/ 著名的基于WxPython的GUI快速生成用的Python IDE,但是开发进度实在太差了……
* http://pype.sourceforge.net/ 成熟的Python代码编辑器,号称功能介于EMACS和IDLE之间的编辑器。
* http://www.stani.be/python/spe SPE:号称是一个Full Featured编辑器,集成WxGlade支持GUI设计。
.NET企业级应用架构设计系列之应用服务器
其实很久以前就想写点关于架构设计方面的东西,一直以来都没有最终落到实处。正好这段时间在做一个WEB架构,决定把和架构设计有关的内容写成一个系列文章。算是回馈CSDN提供的各种免费服务,同时给初学架构设计的朋友一点小小的提示。在我工作的六年多时间里,除了第一年是纯粹编码以外,其余时间都在做和架构设计有关的工作,当然也还一直在写各种各样的代码。也就是说,我本人其实也只有不多的经验可以分享,所以文中肯定有一些观点不能让所有人都认同。如有异议,可以发邮件和我讨论。
1、架构设计是件容易的事情。
对于不熟悉的或者没有架构设计经验的程序员来说,架构设计可能看起来很神秘,不知道究竟该如何入手,也不清楚该注意些什么问题。其实架构设计也只是软件系统开发中的一个环节而已,整个软件系统的开发和维护以及变更还涉及到很多事情,包括技术、团队、沟通、市场、环境等等。在分析和设计架构的时候也是有很多套路和原则的,只要我们按照一些最基本最简单的思路和方向去分析问题,就能得到一个大体满足实际情况的架构。前面我曾写过两篇关于人脑思考复杂系统的文章:《破解复杂性》以及《和SOA一起对抗复杂性》。这是软件开发中的方法论问题,可以贯穿于软件开发的多个阶段,包括架构设计、编码实现、后期维护等。掌握一定的原则,对架构设计能带来事半功倍的效果。
2、架构设计不是件简单的事情。
虽然架构设计是件容易的事情,但也不是大多数没有架构设计经验的程序员想象中的画画框图那么简单。把几台服务器一摆,每一台服务器运行什么软件分配好,然后用网络连接起来,似乎每个企业级应用都是如此简间单单的几步。但现实生活中的软件系统实实在在可以用复杂大系统来形容,从规划、开发、维护和变更涉及到许许多多的人和事。架构设计就是要在规划阶段都把后面的事情尽量把握进来,要为稳定性努力,还要为可维护性、扩扩展性以及诸多的性能指标而思前想后。除了技术上的考虑,还要考虑人的因素,包括人员的组织、软件过程的组织、团队的协作和沟通等。也许你会说那些都是项目管理上的事,和架构设计没关系。但一个团队成员无法实现的架构没有任何实际意义。另外,现在是解决方案满天飞的时代,很多事情都可以用多种途径来解决,如何在五花八门的选项中间做出决定,可能让很多人都头疼过。自己的经验、团队的素质、领导的要求、环境的压力以及市场的变化,够折腾了。
3、架构设计需要方法论的指导
所以,总的说来,在正确的方法论指导下,复杂的架构设计其实是件容易的事情。这些方法论的思路包括,至上而下的分析,关注点分离,横向/纵向模块划分等。有时候觉得架构设计决策就像是浏览Google Earth,实际上反映的是一种自上而下的决策过程。对问题的分解是软件思维的基本素质,可以有横向分解、纵向分解以及两者的结合。能不能有效快速准确的分解问题,是软件开发人员需要首先训练的项目。另外,架构设计中图形化的工具非常有用,它能把系统的结构和运作机制以图形化的方式表达出来。也正因为这样才有了架构设计就是画框图的误会。再者,架构设计是一个工程性质的工作,对当事人的实际从业经验要求较高。只有对市场上的各种技术有较全面的了解之后才有可能设计出一个尽可能满足各种设计约束的架构。
这里说的技术选型实际上是指技术方向的选择,或者叫平台方案的选择,也或者叫技术路线等,总之是大方向的把握。假定项目背景是要做一个中型WEB系统,公司组建新的技术团队以及运营团队来运作。基于这个模糊的项目背景,看看我们能得到些什么。
首先我们想到的是目标系统的特征:
A) 稳定性及可服务性:这是对软件系统最基本的要求,为客户提供稳定的服务是业务开展的最基础的保证。这是和客户的耐心作战,是赢取客户和扩展业务纵深度的前提。很难想象有人会在一个不稳定的系统面前花费精力去做一件本该很容易的事情。
B) 整体性能及升级扩容余地:虽然很多时候对系统压力的担心是多余的,但系统架构必须有一定的应付突发事故的能力以及具备足够的升级扩容空间来满足潜在的业务扩张,不然总会有手忙脚乱的一天。系统性能是可服务性的一方面,而升级扩容空间是系统持续长期运作的保障。
C) 可维护性及可管理性:除开灵活的系统实现带来的可维护性,系统软件和硬件设备的选择同样对可维护性产生重要的影响。这需要结合团队的人员架构来共同考虑。在维护性和管理性方面的问题必然带来升级扩容和应对业务变化方面的巨大困难。
再者,我们会想想想在市面上的解决方案提供商都能给我们什么:
目前在WEB系统方面流行的主要是Java和.NET两个平台级的软件技术方向,它们之所以流行是因为在许许多多的场合被证明能保障较高的生产效率。两者提供的解决方案都表现不错,只不过可能达到相同的目标所带来的总体拥有成本不一样而已。也就是说,它们在解决方案特征方面差异不大。一些重点比对项参考如下:
结论来自某人才招聘网统计资料。
另外,我们会想想我们的人手,也就是说开发团队方面我们拥有哪些方面的人和技术。整个系统的开发需要团队的力量,架构设计和技术方向选型必须关注人的因素。只有合适的人做合适的事情才能产生预期的高位价值。人力资源和技术团队架构在选择方向上起重要作用,需要结合人力资源市场的人才分布来思考。团队的历史经验对架构设计有很大影响,因为历史经验可以带来架构重用以及减少学习新技术和新工具的曲线。另外,团队的素质决定了软件过程能否顺利实施。所以,团队在架构设计中占有相当的分量。(这里,绝不要把架构设计孤立起来看待,它不只是规划期的事情,因为架构设计是对未来的把握,任何影响因素都要尽可能的考虑进来,特别是一些重大影响因素)。
上面的三点,是一个相互联系的整体,合在一起就成了一个三角形,我把它叫做“架构设计三角形”:
图1:架构设计三角形
接下来,结合一些指导原则,它们是许许多多软件系统成功失败的经验总结。其实,看起来也是非常直接的,很容易理解和接受:
A) 寻找最容易找到的技术人员组建团队。这样可以将人员流动对项目的影响减到最小,同时也可以快速的组建团队进入开发期。目前,IT人力资源市场上,Java方向和.NET方向是两个主要的企业级开发方向,多数IT人才也集中在这两块。
B) 使用成熟技术。显然,Java和.NET都是成熟的技术。在软件解决方案方面都有各自的长处和优点,但对企业级应用而言都可以胜任。通过这几年的发展,. NET和Java都形成了丰富的社会技术资源。.NET经过1.0到3.5的发展,在企业级应用方面已经在实践中变得更加的成熟了。
C) 使用团队熟悉的技术。避免过于陡峭的学习曲线,可以把对开发人员的的要求降至更低。但这并不等于使用最简单的技术来完成复杂庞大的企业级应用,应该是在易学易用的前提下构造稳定可维护的目标系统。冒着危险选择不成熟的技术或者不熟悉的技术都只能得到一个漏洞百出的系统。
D) 侧重于开发期的规划与管理,开发稳定可维护的产品。对团队的素质侧重点放在沟通和编写稳定可维护代码的视角,避免目标系统走向紊乱而不可控的地步,从而导致最终失败的结局。
结合具体实际情况,结论很容易得出了。考虑的方向是:目标系统 + 技术团队 =〉 解决方案。详细的结论就不写了,我这次为项目选择的是.NET 2.0平台。
这里要说到的是关于三层架构中的应用服务器。对于电子商务网站来说,成熟的架构基本上都是采用分层式的。分层的结构一方面适合人脑的思维方式,另一方面在解决扩展性方面非常有效。目前市面上的各大解决方案提供商在电子商务和一般WEB应用领域都有相应的分层解决方案,软件架构设计在这一方面几乎不存在多少争议。

出于对可扩展性以及可维护性的考虑,对业务逻辑的解耦得到的便是应用服务器。这样的情况在软件系统中非常常见,在任何情况下都能通过额外一层间接来获得灵活性,但可能会引入潜在的性能问题。在Windows Server 2008问世之前的.NET平台没有应用服务器的专门产品,架设应用服务器可以有多种可选的方案。常用的.NET应用服务器方案有:
A) 使用IIS驻留ASP.NET Web Service
B) 使用.NET Remoting提供远程对象
C) 使用Enterprise Services (COM+)提供跨进程对象调用
这三种方式中,采用TCP/Binary通道的.NET Remoting是三个方案中性能最好的,而采用ASP.NET Web Service则能提供更多的跨平台特性。在性能对比上,ASP.NET Web Service大约是TCP/Binary .NET Remoting的60%左右(和传递的数据有关),这中间的差异来自于网络传输上,ASP.NET Web Service会花费较多时间在大对象的数据串行化(Serialization)上。二进制格式的Remoting实现也提供了对象级(包括单件—— singleton特性)的支持,在性能要求占主导地位的方案中较多采用。
面对这个情况,最好的解决方法是在实现的时候提供一个更加灵活的架构来随时调整策略而让调整的代价保持在最小。也就是说,把系统的核心逻辑实现为一个对象群,然后通过facet方式以最小的努力适配到不同的调用接口上。当然,最初是以SOA的方式发布WEB服务给客户端调用,以尽量实现可移植的环境。如果发现这种模式成为了系统中的性能瓶颈,则改为TCP/Binary .NET Remoting的方式发布对象。
总的来说,应用服务器的架构是一个演化模型,可以随着需求和实际负载的变化实行平滑过渡。当应用服务器的横向扩展也无法应付更大的负载的时候,实际的性能瓶颈已经转移到了系统的其它地方,比如磁盘访问或接入带宽等。
Mikel