The tutorial is great since it not only introduced the concept, but also a really good example to guide you through the door. Meanwhile, without bending rules by ugly codes.
Friday, May 28, 2010
Great FitNesse tutorial!
I was attracted by FitNesse recently and found this great tutorial from Brett who is working with uncle bob at ObjectMentor.
Is public field still so evil in C#?
In Java, there is a rule: "never make your field public". This rule is borrowed by C# when a lot of Java programmers jumped to .NET. I'm one of them and I loyally kept that habit, you will find no public field defined in classes from my hand. While, not exactly. That changed recently.
One of the main reason of "keep fields private" in Java was, field accessors and method calls are very different. If you expose your field as public, then all dependent applications will use obj.fieldName to access it; while if you encapsulate it using a access method, it's like obj.getField(). So if you have make the field public, and then you need to introduce some business logic on the field, then you've got a headache: you need to change all the depending source codes. With IDEs like IDEA and Eclipse, this kind of change can be much easier and robust than before, but still it's going to take effort, which is a waste.
Since the first day of C#'s birth, it has a special language feature, Property, which I believe was borrowed by the success of Delphi. By this feature, a field can be encapsulated by a property and accessed in the same syntax as field, except under the hood, it's really a method call, and if you disassembly the IL code, there is really setField and getField methods generated. So in this case, is it still so evil to mark your field private and provide a property for it? In most of my applications (and I believe in most of most programmers' applications) the property is nothing but just a dummy get/set pair. And to make this pain less painful, MS invented the "auto-property". But the question is, is this encapsulate really necessary?
I don't think so! For C# applications, the "private-field-rule" is not applicable any more. Since if you want to change a field to a property, none of the dependent codes should change (unless if you use reflection). The only thing a field can not do is, it can not be marked as virtual while properties can; and fields can not be put into interfaces while properties can be (you can make a property writeonly and not field, might be useful for setting injection by IoC). So if you need to make a NHibernate friendly entity, or if you need to define interfaces to other module, use property. For most of rest, try to use field, until you find the needs to introduce property. This will help you get code clean.
Friday, May 14, 2010
Content types if you deploy ClickOnce applications with non-IIS web server.
Wednesday, May 12, 2010
Using Teamcity to build(publish) .net application
Since .NET 2, there is a nice feature to "publish" your application, called ClickOnce, to a website, file share or to CD/DVD. If your application only contains managed code (MS termed this smartclient), this feature is a easy way to simplify the deployment of the application and keep your users update date. I happen to have such a application with a group of users up to ~50 distributed from Europe to Asia, so deployment always bothers me. To make things worse (or better:), I follow the agile way of development. That means frequent change/deployment of software. If it is a website, there won't be a problem, but I'm still stuck to desktop and I need an easy way to handle this. Luckily there is a built in function named "publish" in VS2005 (the aged IDE I'm using), which can make a simple html page and some xml files so you can put them on a website and the users can just click the page and start the application. This only works for IE, unfortunately if you can only use .NET2. Since .NET 3.5, there is a Firefox plugin from MS, and there has always been a unofficial Firefox plugin, but I never tried. Anyway it's enough in my case. One thing to notice is, the application is not downloaded for every startup. The timestamp is used to check if there is a new version on server, and if the return value is 304, http-not-changed, then the copy from IE's local cache is used , deployment file (.application) is downloaded and the version embeded in is compared to the version installed in the local application cache. If the version on server is newer, then the application is downloaded again, or the local copy is used. So this suits local network perfectly, unless your deployment is too large (>10MB?). And it seems the application is running in a full trusted mode, with user's confirmation through a dialog showing the publisher can not be verified (maybe a valid certification key would even remove this dialog, I did not tried).
BTW, it's better to use the context menu "Publish..." in project explorer. I've read/experienced unstable publish when using the "publish wizard"/"publish now" button in the publish tab of project properties page.
I have a build server using Teamcity and each time there is a change in my source code, it will grab it and build the software, and notify some colleagues to deploy it. The tool has great web gui and is free if you limit your project to 20 and users to 20. With some money, you can get more "enterprise" features like active directory integration, etc.
I have been using the build server to build "normal" projects (with out "publish") for quite a while and it all worked fine, until I added publish as one of the targets. The actual build still runs well, but there was a wired error occurred when the publish target is running:
warning MSB3155: Item 'Microsoft.Net.Framework.2.0' could not be located in
I searched through the net and found some solutions. But it does not fit all my situation. I could not find the folder specified in the article and copy the whole folder is a little overkill. In my case (VS2005+.NET 2.0), the folder is under
%ProgramFiles%\Microsoft Visual Studio 8\SDK\v2.0
So the register key
sdkInstallRootv2.0 under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework
should point to this folder and I did not copy everything, only the "BootStrapper\Engine" folder, and the "signtool.exe" under the "bin" folder (keep the bin folder). Since the signtool.exe needs capicom.dll, I copied it from %ProgramFiles%\Microsoft CAPICOM 2.1.0.2\Lib\X86. Then build again and bingo, it worked!
Thursday, April 29, 2010
When there is a language feature, you don't have to use it.
In my opinion, C# language pushed a lot of features that can help programmers do bad things. One thing I don't like is the "var" keyword. In some cases, it saves some typing, but a lot of miss-using of it can cause the code hard to read. Can you figure out what the type of below variable is?
var key = retriveKeyToLanguage();
Another one I don't like is the miss use of #region tag. Normally if you keep a good coding principle and design, your class should not be long enough to make use of this tag. But strangely, some people just like to use the tag to mass the code. I recently read some source code from NInject. In general the codes are well written and easy to read. The problem I had was, it seems the author likes those garbage parts from C# too much, even in small classes, he use it to mass the otherwise beautiful code. Take a look at below code, except the first 2 regions which wrap the license nonsense and using nonsense, the rest are miss using. On my not big screen, the class should be able to be fully displayed on one page (which is extremely good!), with the mess-around-tags-and-comments, it exceeds the screen.
#region License
//
// Author: Nate Kohari
// Copyright (c) 2007-2008, Enkari, Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#endregion
#region Using Directives
using System;
using Ninject.Core.Infrastructure;
#endregion
namespace Ninject.Conditions.Builders
{
///
/// A condition that takes the input of a chain of converter delegates and passes the result to
/// a predicate delegate, determining the result of the condition. This class supports Ninject's
/// EDSL and should generally not be used directly.
///
/// The root type of the conversion chain.
/// The subject type that this condition will examine.
public class TerminatingCondition : ConditionBase
{
/*----------------------------------------------------------------------------------------*/
#region Fields
private readonly IConditionBuilder _previous;
private readonly Predicate _directPredicate;
private readonly Predicate _predicate;
#endregion
/*----------------------------------------------------------------------------------------*/
#region Constructors
///
/// Creates a new TerminatingCondition.
///
/// A predicate delegate that directly examines the root of the condition chain to determine the result.
public TerminatingCondition(Predicate predicate)
{
Ensure.ArgumentNotNull(predicate, "predicate");
_directPredicate = predicate;
}
/*----------------------------------------------------------------------------------------*/
///
/// Creates a new TerminatingCondition.
///
/// The last condition builder in the condition chain.
/// A predicate delegate that determines the result of the condition.
public TerminatingCondition(IConditionBuilder last, Predicate predicate)
{
Ensure.ArgumentNotNull(last, "last");
Ensure.ArgumentNotNull(predicate, "predicate");
_previous = last;
_predicate = predicate;
}
#endregion
/*----------------------------------------------------------------------------------------*/
#region Public Methods
///
/// Determines whether the specified object matches the condition.
///
/// The object to test.
/// if the object matches, otherwise .
public override bool Matches(TRoot value)
{
if (_previous == null)
{
return _directPredicate(value);
}
else
{
TSubject subject = _previous.ResolveSubject(value);
return _predicate(subject);
}
}
#endregion
/*----------------------------------------------------------------------------------------*/
}
}
Wednesday, April 28, 2010
Passing external configuration data to NInject instantiated objects.
I used to be a spring.net user and was quite happy about it. To me, the xml is the best advantage and the worst pain. It's good because it's straight forward, easy to embed external data in; it's bad because it make refactoring a pain, and verbose. With Reshaper's help, the pain is a little less. But still it's less pleasant. Therefore I have been searching for replacements, and NInject (referred as NI) is one of the candidates. The biggest problem to NI is the document. It has a lot of unit test cases, but very limited documents, samples. You can only find a very un-realistic sample from the wiki pages on the website. It reveals the tip of the iceberg, but too simple to be too much usage.
Before I make a migration, I need to make sure all my usage scenarios are covered by NI. I used spring.net's mostly as a IOC container, therefore I assume NI should be able to provide most of the functions. In my case, some of my components needs some configuration data to startup, and if the configuration is wrong or invalid, the whole application should fail to start and administrators will know immediately (it's a server side app).
In real world applications, external configuration in xml, ini, yaml, json format is very common and will affect application behaviors. But I did not find any example, tutorial about that. I asked a question in stackoverflow, but no response yet. So I decide to help myself :).
The code in question is like below:
public interface IServer
{
void start();
void stop();
}
public class ServerImp
{
IDictionary _config;
public ServerImp(IDictionary theConfig)
{
_config = theConfig;
}
public void start()
{
// ... logics
}
public void stop()
{
// ... logics
}
}
The problem is, the dictionary passed to the constructor is data from an xml config file. (Actually I use a dictionary to make it difficult. Most config data in my case are just simple string or numerics.) In spring.net it's a breath to make it happen. But in NI, it turns out also a easy task:
public class ConfigData
{
public IDictionary dic;
//...
}
public class ServerModule : StandardModule
{
ConfigData _config;
public ServerModule(ConfigData data)
{
_config = data;
}
public override void Load()
{
Bind<IServer>().To<ServerImp>().WithConstructorArgument("theConfig", dic);
}
}
In startup process, I just need to read the config data by deserialize the xml and pass the data to the moduel.
// in main
ConfigData cfg = loadConfigData(); // deserialize xml.
using (IKernel kernel = new StandardKernel(new ServerModule(cfg)))
{
IServer transport = kernel.Get();
And it works!
Friday, April 23, 2010
The story that users are not ready for agile yet!
In most of the agile methods, on the spot customer is a very important roll. And the user stories are decided by him. He provides real time business consultant to the team. But is he really always correct on making business decisions?
I haven't seen any discussion about this. All the materials I've read share the same sentences, the customer will decide which story will go into scope and in which sequence to be implemented, and so on and so on. But still, in a *lot* of companies, agile is just a normal word with no special meaning. IT are usually on the opposite side to the customers. The customers will try their best to push everything in, with the fear that they won't get anything if missed the chance. And normally in big companies, those who provide feature descriptions and use them, are not the same ones who provide money. So mostly it is a user, but not customer who is working with the team. He don't care about cost, he only needs features. Since he's not IT guy, he does not understand software has quality and needs to be maintained; he doesn't understand the more features in the more complicated the software is, the more bug will be. With the fear of getting nothing afterwards, he'd even imagine some feature to be implemented. Anyway, it's already paid, isn't it?
In one of my recent projects, I met such a case. The user needs a very special search feature. It's easy to implement. But there is a potential problem: by miss using it, it can bring a lot of load to database and application server. For this kind of search, DB must do full table scanning. We pointed out this and asked the user under which scenario this feature will be used, so we can figure out some strategy. And it turned out it's an imaginary feature. He *thought* it might be used in some future scenario.
So the team needs to remember that the on the spot user should sometimes be questions, especially when the team is in a transition period from traditional way to agile methods. The users are not used to the transform yet!
Subscribe to:
Posts (Atom)