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();
transport.start();
transport.stop();
}

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!

Monday, April 12, 2010

Rake default tasks when namespace presents

Rake, the Ruby version of make, is really elegant and powerful. Given the power and terseness of Ruby, it's really easy to build building scrips.

Normally when you type rake at command line, give you have everything installed correctly and a rake file under the same folder, the :default task is executed. But when you have namespaces to help organize the tasks, specifying the default task needs a little trick.

This is what you normally do
task :default => :build
task :build do ..... end

With namespaces, you have to use string, instead of symbol to specify the task name:
task :default => "build:build"
namespace :build do
task :build do ..... end
end

Sunday, April 11, 2010

.Net 2 remoting with security support, simplified

I tried a complicated way to initialize the channels to make the caller's identity pass through wire from client to the server. If you need to really impersonate the client or even delegate functions on behalf of the client user, then you have go through that tedious way. I don't like it. The parameters are in plain string and you have to make sure no typo is made. (What's wrong with a strong typed parameter objects?)

Anyway, what all I need to is to know which user is calling some function. I don't need to impersonate or delegation. So there is a simpler way:

On server, just use
IChannel tsc = new TcpServerChannel(8888);
ChannelServices.RegisterChannel(tsc, true);
Note you have to specify ture when you register the channel. Then you are ready to publish objects, either by RemotingConfiguration.RegisterWellKnownServiceType, or by RemotingServices.Marshal.
At client side, you MUST register a TcpClientChannel also with true to the 2nd parameter before activating the server objects. If you forget this, or put false, the client will not be connected correctly.
TcpClientChannel tcp = new TcpClientChannel();
ChannelServices.RegisterChannel(tcp, true);
_Server = (IService)Activator.GetObject(typeof(IService), "tcp://localhost:8888/ASvc");

That's it, no ugly hashtable for parameter passing and still you can pass the caller's identity to server.

Saturday, April 10, 2010

.Net 2 remoting with security support.

Yes I know there is clear statement in MSDN saying this is outdated technology and I should use WCF. But if you are like me who is stuck with .NET 2 on Windows 2000, you still have to use this.

Normally I use spring.net to inject all my objects and control config through external config files, so I don't use the *.config files normal tutorials use. I need to get everything done by code. This is not hard, but needs a little search around.

Below code will create a secure tcp channel at server side:
IDictionary prop = new Hashtable();
prop["port"] = 9999;
prop["secure"] = true;
prop["impersonate"] = false; // when "secure" is true, this is by default, thus optional
TcpServerChannel tcp = new TcpServerChannel(prop, null, new AuthorizationImp()); // auth module can also be specified in property hashtable.
ChannelServices.RegisterChannel(tcp, true);

IService svc = new ServiceImp(); // this makes the server a singleton.
ObjRef or = RemotingServices.Marshal(svc, "Service");

Now the server is ready for servicing clients, under the name "tcp://localhost:9999/Service". We can build a client to connect to it:

IDictionary prop = new Hashtable();
prop["port"] = 9999;
prop["secure"] = true;
prop["tokenImpersonationLevel"] = TokenImpersonationLevel.Identification; // when "scure" is true, this is by default and also optional
IChannel tcp = new TcpClientChannel(prop, null);

ChannelServices.RegisterChannel(tcp, true);

IService svc = (IService) Activator.GetObject(typeof (IService), "tcp://localhost:9999/Service");

IDictionary csp = ChannelServices.GetChannelSinkProperties(svc);

svc.Repeat("From client", 5); // call with default login

csp["username"] = "rrr"; // now use another user to call
csp["password"] = "rrr";
svc.Repeat("From client", 5);

csp["username"] = "mmm"; // another
csp["password"] = "mmm";
svc.Repeat("From client", 5);

From the code you might have figured out that IService is a interface used by both server and client to decouple a concrete dependency to any implementation. It has only 1 method called Repeat.

So how does server know who is calling for service? Even without impersonation, the server code can still retrieve the caller's identity by Thread.CurrentPrincipal.Identity.But the WindowsIdentity.GetCurrent() will still return the current user the process is running on. MSDN made a mistake at this point.