| Sean Feldman's profileברוכים הבאיםPhotosBlogLists | Help |
|
29/02/2008 Pair Programming And Sharing KnowledgePair programming is a proven technique for sharing knowledge among team members and teams. Benefits of that are felt after relatively a short period of time, boosting not just the productivity, but self-confidence of the developers (which is playing an important role even though is not admitted), and most of all, improving the maintainability of the code when it comes later. And it comes. It always comes. But I would like to review additional alternatives to the knowledge sharing with team members (both direct team members, and those that are a part of another teams that might not come into direct contact with what your team is doing). What are the ways to share the knowledge? From my personal experience, group lectures are in-effective. People are coming into those, hating it, and taking almost nothing valuable as they leave. Code camps are excellent, but the majority of the people who are attending those are doing it out of their own curiosity, enthusiasm, or just will to be better developer. What I was doing in the company I work for, is a short (30-45 minutes) meetings once a week or two, hands on code. And the presenter was elected at the end to present his/her topic. IMHO this was working, but others may disagree. I think this was working for the developers who believed that it's not just a task of presenting, but a responsibility not to waste others time and let them learn from others what they would not learn on their own due to the lack of time or opportunity. So what are you practicing if at all? 26/02/2008 Sucks To Work Blind22/02/2008 Know Your Friends Well, Know Your Enemies BetterLong time ago I had to deal with a case where the famous ViewState generated by WebForms was quiet heavy. This post is not going to wine about how bad ViewState is for the environment. This post is to show that even working with something big and nasty such as web forms, you still have to give a thought what are you trying to do and what is out there that can help you to accomplish the mission. Before getting into the "solution" (well, it is a solution, but kind-of stinky if you are asking me), I would really recommend the post about what is ViewState and it's influence on your nervous system. So what is solution - not to use ViewState :) Week solution. Spike and invent something - bad idea. The wheel in already invented. Spike on WebForms implementation and learning - that's the one.
First we need to look at the "container" of the ViewState which is nothing but a Page. This is where one of my favourite tools for reflection is making its' big entrance - Reflector. Looking at the page, you shall see that a page has an interesting getter called "PageStatePersister". Digging deeper provides an insight into the intension of this property: 1: protected virtual PageStatePersister PageStatePersister 2: { 3: get 4: {5: if (this._persister == null) 6: {7: PageAdapter pageAdapter = this.PageAdapter; 8: if (pageAdapter != null) 9: {10: this._persister = pageAdapter.GetStatePersister(); 11: }12: if (this._persister == null) 13: {14: this._persister = 15: new HiddenFieldPageStatePersister(this); 16: } 17: }18: return this._persister; 19: } 20: }A few interesting things in particular we can learn from the code:
What a world of opportunities in such a limited world of ViewState! Let's use reflection to find out what are the possibilities. And the winners are: Not that much of options, but hey, we can have an option of keeping it at "home" on the server side, rather than sending to the client EVERY-SINGLE-ROUNDTRIP! There are a few options:
Option 3 is for your wild and kinky imagination, option 1 is too trivial, option 2 is what I would like to expand a bit. So we want to reconfigure the entire web application for a different persister (Session one for the application that has lots of stuff in ViewState, and should produce a slim HTML). Adding a folder App_Browsers allows us to register different controls adapters. Page is a control as well, see for yourself: In this folder, we can specify adapters per browser, or all of them (ahh, my old days of WAP development with Mobile ASP.NET are bubbling up, causing me a horror moment). Something like BrowserFile.browser file should do it - use VS.NET add new item option to add a .browser file. Then register an adapter for a page. The adapter code would be simple as this: 1: using System.Web.UI.Adapters; 2: using System.Web.UI; 3: 4: public class SesionPageStateAdapter : PageAdapter 5: {6: public override PageStatePersister GetStatePersister() 7: {8: return new SessionPageStatePersister(this.Page); 9: } 10: }.browser file would be a mapping like this: 1: <browsers> 2: <browser refID="Default"> 3: <controlAdapters> 4: <adapter controlType="System.Web.UI.Page" 5: adapterType="SesionPageStateAdapter" /> 6: </controlAdapters> 7: </browser> 8: </browsers> Unfortunately it will not remove the ViewState completely, but it will definitely minimize it. Sometime several dozens of KB can be prevented from going back and forth. Also keep in mind that ControlState (from ASP.NET 2.0 and later) is possible contributing, and that one is not disableable. Hopefully this helps to those who are in pain of watching hundreds of Kilobytes traveling there, taking more "page weight" than the page content itself. 20/02/2008 Understanding IoC Container - Part 2I try to lower expectations in order not to be disappointed, but in this case I was asked by several individuals to address the fact that IoC container power is in the ability to "hook" implementer with the contract through an external file, leaving application code unaware of the actual implementer till the run-time, having no reference to implementers' assembly or whatsoever. I am going to expand the sample from the part 1 post to achieve that goal in a couple of day. 16/02/2008 Understanding IoC ContainerIn a multi layered application architecture, loosely coupled code is more than a important. It's the basic which can either help the entire project progress, or drive it down the slope to the end (in the bad meaning of the word). One of the basics to keep coupling as low as possible is Inversion of Control (IoC) container. I will try to show how to put in place a simple version of IoC container to allow loosely coupled design. The solution will contain several projects to emulate a layered application as much as possible. The choice of console application is only driven by intent to keep it as simple as possible. In our application we do basic logging at all layers. Logger that does it is following the next contract: public interface ILogger { void Log(string message); } Lets assume that the initial version of logger is implemented as a simple Console logger: public class ConsoleLogger : ILogger { public void Log(string message) { System.Console.WriteLine(message); } } Now lets look what the layered structure looks like. The lowest layer in the stack is going to be Core. This one will contain the interfaces (such as ILogger for instance) all other layers have to consume. This is a sort of tight coupling, but it is not bad as upper layers will depend on abstraction and not concrete implementation (DIP). AssemblyOne, Two, Three, and others are all potential layers you could have (and I am not necessarily insisting on having them - there should be a rational limit). ConsoleApp is the top layer that represent the application. This could be easily a Windows application or a web application. To spice up our life, we have to implement a gadget in AssemblyOne that will follow a certain contract (IGadget) and each operation defined by the contract, has to be logged when implementation is invoked. The contract is: public interface IGadget { void TurnOn(); void TurnOff(); } Now the implementation of the Gadget will be quiet simple: 1: using Core; 2: 3: namespace AssemblyOne 4: {5: public class Gadget : IGadget 6: {7: private readonly ILogger logger; 8: 9: public Gadget(ILogger logger) 10: {11: this.logger = logger; 12: } 13: 14: // Default constructor will be discussed a bit later 15: // public Gadget() {} 16: 17: public void TurnOn() 18: {19: logger.Log("TurnOn"); 20: } 21: 22: public void TurnOff() 23: {24: logger.Log("TurnOff"); 25: } 26: } 27: }The program in the upper (ConsoleApp) layer will look this way: 1: using System; 2: using AssemblyOne; 3: using Core; 4: 5: namespace ConsoleApp 6: {7: internal class Program 8: {9: private static void Main() 10: { 11: AppCode(); 12: 13: Console.WriteLine("done."); 14: Console.ReadLine(); 15: } 16: 17: private static void AppCode() 18: {19: ConsoleLogger logger = new ConsoleLogger(); 20: Gadget gadget = new Gadget(logger); 21: gadget.TurnOn(); 22: gadget.TurnOff(); 23: } 24: } 25: }AppCode method (lines 19-22) is what we are interested in. A few question can be raised at this point:
These are all excellent questions. The first two are definetely a bad smell. Why? Well, because we should be really sticking to what contracts were obligating implementers, and not be even able to use the "extras" provided by contract implementers "outside" of the contract. This will eliminate any chance that an "undocumented" by contract method will extinct from existing, causing our client code to break. The third question is the one that shows that current design is not going to work - current ILogger implementer is located in ConsoleApp layer and we have to pass it as a dependency into gadget. But what if we introduce another implementation of ILogger, like XML logger, and it will live in another layer, AssemblyTwo? And what if we want to be able to create gadget without specifying logger, relying on a default one? This is where IoC container would help. The idea behind container is simple: lower layer provides an option of registering a contract implementer, and later, retrieve that contract implementer instance, by just using the contract type. Expressing this in code would look like the next snippet: namespace Core.IoC { public interface IContainer { // register contract implementer void AddImplementerFor<ContractType>(Type implementer); // retrieve contract implementer ContractType GetImplementerOf<ContractType>(); } } Implementation of this contract is a subject to a separate discussion. To keep it simple, I have decided to use the simplest way out there: 1: using System; 2: using System.Collections.Generic; 3: 4: namespace Core.IoC 5: {6: public class Container : IContainer 7: {8: public static readonly IContainer Instance = new Container(); 9: 10: 11: private readonly Dictionary<Type, Type> container; 12: 13: private Container() 14: {15: container = new Dictionary<Type, Type>(); 16: } 17: 18: public void AddImplementerFor<ContractType>(Type implementer) 19: {20: container.Add(typeof(ContractType), implementer); 21: } 22: 23: public ContractType GetImplementerOf<ContractType>() 24: {25: return (ContractType)Activator.CreateInstance(container[typeof (ContractType)]); 26: } 27: } 28: }Yes, the core secret is in Activator class, provided by .NET framework. No magic. With this in hand, we can start using container all other the place, breaking the dangerous coupling. First thing first, registering contracts and their implementers for the application. This will change how we start our application: 1: using System; 2: using AssemblyOne; 3: using Core; 4: using Core.IoC; 5: 6: namespace ConsoleApp 7: {8: internal class Program 9: {10: private static void Main() 11: { 12: ApplicationStartup(); 13: 14: AppCode(); 15: 16: Console.WriteLine("done."); 17: Console.ReadLine(); 18: } 19: 20: private static void ApplicationStartup() 21: {22: Container.Instance.AddImplementerFor<ILogger>(typeof( ConsoleLogger)); 23: Container.Instance.AddImplementerFor<IGadget>(typeof(Gadget)); 24: } 25: 26: private static void AppCode() 27: { 28: IGadget gadget = Container.Instance.GetImplementerOf<IGadget>(); 29: gadget.TurnOn(); 30: gadget.TurnOff(); 31: } 32: } 33: }Line 12 introduces a new (quiet old actually) concept - application startup point. In web application something like Application_Start in Global.asax would be an equivevalent. What it does is teaching the container about contracts, and who are the implementers. That way, we can get an instance of an IGadget without worrying who implements it (line 28). Also we don't need to directly inject the logger dependency, due to the fact that gadget can query for the default logger through the container. Updated logger looks like this: 1: using Core; 2: using Core.IoC; 3: 4: namespace AssemblyOne 5: {6: public class Gadget : IGadget 7: {8: private readonly ILogger logger; 9: 10: public Gadget(ILogger logger) 11: {12: this.logger = logger; 13: } 14: 15: public Gadget() : this(Container.Instance.GetImplementerOf<ILogger>()) {} 16: 17: public void TurnOn() 18: {19: logger.Log("TurnOn"); 20: } 21: 22: public void TurnOff() 23: {24: logger.Log("TurnOff"); 25: } 26: } 27: }Line 15 defines a default constructor that leverages container to get the default implementation of logger. Now we will substitute the default logger by another implementer, from another assembly (AssemblyTwo) that logs information into an XML file: 1: using System; 2: using System.IO; 3: using System.Xml; 4: using Core; 5: 6: namespace AssemblyTwo 7: {8: public class XmlLogger : ILogger 9: {10: private readonly string fileName; 11: 12: public XmlLogger() : this("log.xml") 13: { 14: } 15: 16: public XmlLogger(string fileName) 17: {18: this.fileName = fileName; 19: } 20: 21: public void Log(string message) 22: {23: XmlDocument document = new XmlDocument(); 24: string filePath = Path.GetFullPath(fileName); 25: CreateFileIfDoesntExist(filePath); 26: document.Load(filePath); 27: XmlElement root = document.DocumentElement;28: XmlElement element = document.CreateElement("log"); 29: element.SetAttribute("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")); 30: element.InnerText = message; 31: root.AppendChild(element); 32: document.Save(fileName); 33: } 34: 35: private void CreateFileIfDoesntExist(string filePath) 36: {37: if (!File.Exists(filePath)) 38: { 39: XmlWriter writer = XmlTextWriter.Create(fileName);40: writer.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");41: writer.WriteStartElement("logs"); 42: writer.Close(); 43: } 44: } 45: } 46: }The adjustment has to be done to the startup method to register the new implementer in the container: private static void ApplicationStartup() { Container.Instance.AddImplementerFor<ILogger>(typeof(XmlLogger)); Container.Instance.AddImplementerFor<IGadget>(typeof(Gadget)); } Now the entire system uses XML logger as a default logger: There is a scenario when contract implementer is in an assembly that should not be referenced from the code (due to the fact that it is just not available during the development time)? Then something like an external file for container configuration can/should be used. We will have to specify the assembly name as well, so the activator would be able through the reflection to invoke constructor. Bottom line - this is far from being perfect, but it was not intended to do the heavy lifting (though could be used to do IoC container work). My recommendation would be to understand what power it gives you and take one of the existing containers such as Windsor, Spring.NET, StructureMap, etc. ...hey, what's up with the log there? Was it working at all? See for yourself, get the code .<?xml version="1.0" encoding="UTF-8"?> <logs> <log timestamp="2008-02-14 22:53:10.014">TurnOn</log> <log timestamp="2008-02-14 22:53:10.060">TurnOff</log> </logs> 04/02/2008 Immutable Collection (Secure Proxy Pattern) ExampleMr. Mo has wrote a nice post about securing collection and turning it into an immutable object. I am adding my 20 cents by reminding a great example JP Boodhoo has showed during his "Nothin But .NET" training session, leveraging ReadOnlyCollection<T> class to make a collection immutable. 03/02/2008 Domain Objects vs. Primitive TypesLately I am paying more and more attention to aspects of Domain Driven Development (DDD), development where code is looking more at the domain in which it is trying to resolve problem(s), rather than technologies it is using. One of the biggest headaches that you getting into when trying to adopt DDD is persistence. Normally persistence is done in Relational database such as SQL server, Oracle, or another vendor database. And this is exactly the problem - Object Oriented model vs. Relational Data model. So what is more important, a software that is written in DDD way, that forces you to put DB on a lower priority, or DB efficiency as a priority pushing your software from Domain driven development to become a Data Driven development? If you asking me - domain is more valuable. I will show an example that to me serves the best proof for those who still try to save the "extra round trips to DB" or "we could combine the queries and have a single call to the DB". Keep in mind, I am not going against DB efficiency, after all a sloppy data access can kill the best application out there. But having a great data access model will not make you application writing easier, on contrary. The example is simple. The system defines Organizations. One of the views has to list all the organizations in the system with one business rule that is coming from a client as a requirement - "the default" organization has always to appear on top. So having a list of Organizations I need to apply the rule to transform the list and pass to the view. Simple. This is where differences between Domain DD and Data DD are starting to bubble up. Note: according to the client, default organization is setup once per application and is not changing. The development team has decided to store the default organization id (Guid) in a configuration file for simplicity. The first code does the next: 1: namespace Sample 2: {3: public class DefaultOrganizationIsOnTopBusinessRule 4: {5: private readonly Organization defaultOrganization; 6: private readonly List<Organization> originalOrganizationList; 7: 8: public DefaultOrganizationIsOnTopBusinessRule( 9: IEnumerable<Organization> organizations, 10: Organization defaultOrganization) 11: {12: originalOrganizationList = new List<Organization>(organizations); 13: this.defaultOrganization = defaultOrganization; 14: } 15: 16: public IList<Organization> Apply() 17: {18: if (originalOrganizationList.Contains(defaultOrganization)) 19: {20: List<Organization> newList = new List<Organization>(); 21: newList.Add(originalOrganizationList22: .Find(delegate(Organization org) 23: {24: return org.Equals(defaultOrganization); 25: })); 26: newList.AddRange(originalOrganizationList27: .FindAll(delegate(Organization org) 28: {29: return !org.Equals(defaultOrganization); 30: }));31: return newList; 32: } 33: 34: return originalOrganizationList; 35: } 36: } 37: }The second code, does almost the same, except that it tries to "save a trip to DB" in terms of supplying just the default organization id, and not the entity. the code is: 1: namespace Sample 2: {3: public class DefaultOrganizationIsOnTopBusinessRule 4: {5: private readonly Guid defaultOrganizationGuid; 6: private readonly List<Organization> originalOrganizationList; 7: 8: public DefaultOrganizationIsOnTopBusinessRule( 9: IEnumerable<Organization> organizations, 10: Guid defaultOrganizationGuid) 11: {12: originalOrganizationList = new List<Organization>(organizations); 13: this.defaultOrganizationGuid = defaultOrganizationGuid; 14: } 15: 16: public IList<Organization> Apply() 17: {18: Organization defaultOrg = originalOrganizationList 19: .Find(delegate(Organization org) 20: {21: return org.Guid == defaultOrganizationGuid; 22: });23: if (defaultOrg != null) 24: {25: List<Organization> newList = new List<Organization>(); 26: newList.Add(defaultOrg); 27: newList.AddRange(originalOrganizationList28: .FindAll(delegate(Organization org) 29: {30: return org.Guid != defaultOrganizationGuid; 31: }));32: return newList; 33: } 34: 35: return originalOrganizationList; 36: } 37: } 38: }but this is an illusion of "quick" and "quality" code - several reasons:
If you answer these questions and you find yourself preferring the 1st code snippet, then domain is what you care for more, and along with it maintainability of what you build. In case the second code snippet is more appealing to your heart, then DB is all you care and get ready for some serious hacks and workarounds in your code to keep it running for the sake of efficient DB access. To finish this post, I would like to comment a few sentences from Eric Evans book: "The goal of domain-driven design is to create better software by focusing on a model of the domain rather than the technology. By the time a developer has constructed an SQL query, passed it to a query service in the infrastructure layer, obtained a result set of table rows, pulled the necessary information out, and passed it to a constructor or FACTORY, the model focus is gone. It becomes natural to think of the objects as containers for the data that the queries provide, and the whole design shifts toward a data-processing style. The details of the technology vary, but the problem remains that the client is dealing with technology, rather than model concepts." |
|
|