| Sean Feldman 的个人资料ברוכים הבאים照片日志列表 | 帮助 |
|
2008/6/27 IDs to ObjectsA few months ago I blogged about Domain Objects vs. Primitive Types. Back then it felt right to me to transform a primitive type, like a Guid that represented, to an Organization domain object. Unfortunately at that time I was not educated enough to know that this is a common idiom in among many object designers. Apparently it is. Craig Larman writes it nicely in his book (in my case Organization is what Craig references to as a Customer):
The other important note is when this transformation is taking place - when an ID or a Key leaves the UI layer and gets to the Domain Layer. 2008/6/19 Have Honest OpinionIt is very hard to provide an honest opinion when you are involved in a situation. I found it always difficult for myself and admired people of being able to do it, lifting themselves from emotional attachments to the matter. I am a big fan (if not huge) of the whole Google Apps platform. I use heavily Gmail, rely a lot on Google Calendar, abandoned Excel for simple-to-average stuff and went with Google spreadsheets. I used Google Maps, because it was better than Microsoft's competitive version of the product. Till I had a chance to re-evaluate it again. This time around Microsoft has produces a better result. Microsoft Live Maps gives me more than Google Maps does (weird even to think it, not mentioning writing it :). What made the difference? The level of details, an option of having a closer look, real images. Anyway, I am not using Live Maps. 2008/6/16 Command-Query Separate PrincipleA few days ago read in Larman's book about Command-Query Separation Principle. Funny to mention that I heard about the concept many times ago, but this is the only source that stated it as a principle. And it makes total sense once you evaluate all the pros and cons of the idea. What's the principle? Simple. There are two kinds of messages to objects:
A Command message would be "void Calculate()" or "void Add(double value)". Command message never returns a value, and that's for clear separation of the messages and easier maintenance of the object state (i.e. no surprises). A Query message would be what Command isn't "int GetValue()" or "IsVisible()". One exception the author brought up was internal/private messages that are not a part of the interface, and therefore can violate the principle - I guess this is a matter of personal preference. An example is an implementation of a Die (for a monopoly game) modified by myself. public interface IDie { void Roll(); int GetFaceValue(); } public class Die : IDie { private int faceValue; private Random rand = new Random(); public void Roll() { faceValue = rand.Next(6) + 1; } public int GetFaceValue() { return faceValue; } } I added the interface on purpose, to have DbC, where implementation doesn't matter that much, because the contract is expressing well enough the intension of how to use an implementer of an IDie. Thanks to the CQS Principle it becomes crystal clear. It is easy to determine a value of a die, and there's no surprises when a die is queries for it's value. Now imagine a system with a significant number of components that violate this principle versus a system where components follow it. Can you imagine the difference? 2008/6/15 3 YearsToday is 3 years since I started working with the company I work today. It's being a long journey from figuring out what I want, till realizing what I am and need to be. The team has accepted all of my wildest ideas about the code and was very tolerant to the fact that I cannot wait to get something done. We've made a long way. Besides improving as a software developer, I also realized a few bitter realities - it doesn't matter how good I am, still need to strive to be better. Besides the excellence in code, there must be a proficiency in human relationships. The code is not only about a single developer level, but about team level, because if you are the only one who can have fun with it, it is no longer fun. Lessons are good, but I have to look forward and setup certain goals for myself, what do I want to achieve the next year? A lot.
Some of my targets will change or get updated, but the core set of goals will remain. A lot ahead, I better start moving towards it. 2008/6/12 Code Smell vs. Code StenchInteresting difference I picked up from a book this morning - code smell vs. code stench. Code smell might indicate there's a problem in code that requires refactoring, but a closer evaluation might prove the smell is false alarm. Code stench is an obviously bad/poor code that has to be refactored. From now on I will be more accurate on describing the code issues :) Google Shortcut Keys - AwesomeFor all keyboard junkies out there - if you are also hooked on Google products (GMail, Reader, Calendar, etc), don't miss the option of using GMail with keyboard shortcuts. The are awesome. I loved the navigation shortcut (combination of pressing first G and then another key, neat). To enable keyboard shortcuts, you will have to go to the settings under you GMail account and check off the option to enable it. 2008/6/11 Two Loosely Coupled Code - Part 2In the I raised the question of "Too loosely coupled design". There's a lot to discuss about it, and I am not going more time on it, except showing one more sample that IMHO shows the benefits and outcomes of the principle being applies, or consequences of not doing so.Table 1 namespace Local.ADL.Home { public class HomePresenter : IPresenter { private readonly IHomeModel model; private readonly IHomeView view; public HomePresenter(IHomeView view): this(view, new HomeModel()){} public HomePresenter(IHomeView view, IHomeModel model) { this.view = view; this.model = model; } public void Initialize() { view.Load += View_OnLoad; } private void View_OnLoad(object sender, EventArgs e) { if (!view.IsPostBack) { view.AssignInitialData(model.IsUserMemberOfPlanAOrPlanB(), model.CanShowSomething()); } } } } Table 2 namespace Local.ADL.Home { public class HomeModel : IHomeModel { public bool IsUserMemberOfPlanAOrPlanB() { return UserSession.IsPlanAorB; } public bool CanShowSomething() { return UserSession.ShouldSeeSomething; } } } Q: Can HomePresenter be tested based on the code in Table 1? A: Yes. It has a parameterized constructor that accepts all dependencies for HomePresenter as contracts (interfaces) without knowing or carrying who are the real components that implement those contracts. Loosely coupled code, where we depend upon abstraction and not concrete implementation. Q: Does HomePresenter is loosely coupled at run-time? A: No. It has a direct dependency on HomeModel class. This is a tight coupling, meaning that anywhere in the code we used this type of coupling, we made HomeModel “visible” for HomePresenter, i.e. we violated the principle of depending upon abstraction and not concrete implementation. What would be a solution? Dependency Injection Principle with a standard container (lets call it DependencyResolver). Using this simple principle would change the code to be something similar to the code in Table 3. Now HomePresenter is loosely coupled to the implementer of the IHomeModel contract. Some configuration file / startup code will determine who is the actual implementer at run-time. Testing is still possible. Table 3 namespace Local.ADL.Home { public class HomePresenter : IPresenter { private readonly IHomeModel model; private readonly IHomeView view; public HomePresenter(IHomeView view): this(view, DependencyResolver.GetImplementerOf(IHomeModel)){} public HomePresenter(IHomeView view, IHomeModel model) { this.view = view; this.model = model; } // ... Q: Can HomeModel be tested based on the code in Table 2? A: No. It is tightly coupled to the UserSession, which in its’ case is a static class and cannot be mocked / faked / taken out as a component that is not required to be tested at this moment. To solve it:
|
|
|