Friday 9 July 2010

The End

I’m closing this blog which means that this my very last post here. I'm not going to delete this blog so content which is here will stay online. (At least for a while) I also don't want to finish my career as a blogger :) I’m just moving to a different place … my new blog is available here: http://marekblotny.com/.

Saturday 26 September 2009

The latest news from .Net world (September 2009)

On the very last meeting of Poznan .Net User Group I had a great pleasure to give 15 minutes talk about the latest news from .Net world. Picking the most interesting news isn't a trivial task. In the end I've decided to mention about following three topics:


Visual Studio 2010 and .Net 4

This was quite straightforward choice, new versions of VS and .Net Framework affects everyone so it's good to know what new features will are about to arrive. Probably the best source of information from this field is ScootGu's blog. Recently he posted series of post about VS 2010 and .Net 4.

Just to quickly name a few the most notable:
  • .Net Framework 4 and VS 2010 can be installed side by side with older versions.
  • a bunch of language improvements (C#) like: dynamic keyword, named and optional parameters, covariance, better COM support. Named and optional parameters is a long awaited feature, unfortunately it has some limitations - basically you can't assign to a parameter default value which is not compile-time constant.
  • web.config files will be greatly simplified
  • VS 2010 will have much more project templates available. It will be possible to start with completely clean project but also with simple application having the most basic features included (master page, forms authentication pages, JQuery etc.). Interesting is that new sample project are already using
    • clean client side Id (no more Ids like: ctl00_topLevelNavigation_rptMenu_ctl02_rptNextLevelMenu_ctl02_liTag!)
    • build-in controls are using CSS based rendering
  • Improved Multi-targeting support - Problem with VS 2008 is that Intellisense always shows the types and members from .Net 3.5 (regardless of targeted version of .Net). This issue has been sorted with VS 2010.
  • ASP.Net, HTML and JS Snippet support - finally! :) For people working a lot with the view this is great news. I was writing tags and controls like Repeater from scratch so many times that I'm sick of it. With VS 2010 it can be automated.
  • Auto-Start ASP.Net Applications - Currently web applications are initialized with first request. This is a bit unfortunate because during the initialization sometimes it's required to perform number of heavy operations. That's why the first response is so delayed. There are of course number of ways to workaround this problem but with .Net 4 we will get dedicated means to auto-start our applications and perform initialization before the first request.


Git

Git is a distributed version control system which is getting more and more popular in .Net world. In outside world it is used by a big, very well-known projects like:
  • Linux Kernel,
  • Perl,
  • Ruby on Rails,
  • Gnome,
  • Andriod,
  • Fedora,
  • Debian,
  • X.org
I think the above list provides evidence that this system works well (especially for OSS projects).

Also in .Net world there are projects which decided to dump popular version control systems like SVN and are moving to Git:
Justification for those decision is worth reading:


CodePlex foundation (CodePlex.org)

And finally last topic which I want to mention about is CodePlex foundation. It has been created by Microsoft "to help commercial software developers use Open Source software" and which "ultimately aiming to bring open source and commercial software developers together in a place where they can collaborate".

It's well known that big commercial software development companies are not really keen to use OSS. I think that this approach is changing with time and CodePlex foundation's main goal to help with that. In general all of that sounds really good but for number of different reasons this initiative mostly wasn't well received by the community. Still I think it's worth keeping an eye on it :)

Here you can find a few related links:

Wednesday 16 September 2009

Custom styles in Rich Text Editor (part II)

It wasn't so long ago when I posted 'How to define custom styles in EPiServer's Rich Text Editor'. A few days ago I was following my own instructions to set up my custom styles and for absolutely peculiar reason Rich Text Editor didn't want to catch my settings! It took me a few hours to figure out what was going on.

Basically you can define custom styles in EPiServer by setting uiEditorCssPaths property in web.config:


which is the same as using System Settings in Admin mode:


But of course there are cases where it may not take any effect :)

If you encounter such case then check dynamic properties. You may have dynamic property called UIEditorCssPaths. If this property is set then other settings are ignored.


Monday 7 September 2009

Moving beyond the Scrum

I used to be a firm supporter of Scrum process. I was deeply convinced that Scrum's approach makes total sense and is the right one. My impressionable attitude has changed with time. Now I see that "pure" Scrum is a quite rigid process which not always fits the best our specific type of work. What is exactly on my mind?


Scrum is stopping us from higher productivity



Sprint length is derived based on project's life expectancy. Having at lest 4-6 sprints within the project is an absolute minimum. Usually we are choosing from two options: one or two weeks for sprint. Unfortunately there are some issues with both options:
  • One week sprint gives us only 4 days of development so one day is "wasted" on Scrum related activities. 20% of our time, it's quite a lot.
  • With two week sprints there is still one day devoted for demo, planning session, retrospective etc. but ratio here is 9 to 1. It's a significant improvement but in the same time we have to deal with new issues which are more evident for two weeks sprint.
    • Unchangeable sprint plan - sometimes it happens that somewhere in the mid-sprint all stories are done or blocked by some external dependency with which we can't do anything. Because we can't add new stories in the middle of sprint and we can't proceed with blocked stories we are forced to fill our time with "other stuff".
    • Another absolutely normal thing is that some new, very important and extra urgent things need to be done ASAP. We can moan that things like that shouldn't happen but in reality they happen so we have to be prepared for it! Scrum's answer to situation like this is "we will take care of that in next sprint as current one is already in progress" or "we can stop this sprint, run planning session again and incorporate this very urgent story into sprint plan". Both options are not good enough, replacing one story with another of similar size in the mid-sprint doesn't hurt the team and in the same time can address important requirement. Scrum is not very flexible here.

Even though there are some issues with Scrum I don't think that we should look for some revolutionary changes. This process works, we just need to tweak it in order to make it more suitable for our projects. Here are a few ideas to consider:
  • Do we need a sprint planning sessions? For sure we need prioritized product backlog to know which stories we should work on in the first place. On planning session we will either overestimate (stories which are not done by the end of sprint will be moved to the following one) or underestimate (and then we need to add some stories in the middle of sprint), priorities may change (stories swapping) therefore plan is very likely to change. Maybe it's better to simply use product backlog as a queue and finish as many stories as we can during the sprint?
  • Retrospective meetings - they are very beneficial when project starts but when it's closing to the deadline they are getting less and less valuable. Maybe it should be team's decision if it makes sense to have such a meeting? If something is going wrong and it's obvious to everyone why should we wait till the end of sprint with retrospective?
  • Demo - usually we want to have implemented functionality available to the client as soon as possible so maybe instead of delivering new stories after one big demo we can have number of small demos and this way be more responsive?

Probably the most important thing which I have learned from Scrum is that we should keep looking for things which can be improved and experiment with the process. So if answer to some of above questions is positive then maybe it's time to move towards more lean processes? Scrum-ban? Kanban?


Last words ...



I have been using Scrum with different deviations for about 3 years now and I still think that Scrum has a lot to offer. The thing is that it doesn't have to fit perfectly for all types of projects. I think I can say that I'm still a firm supporter but not so impressionable any more.

It seems that more and more teams is already moving along this path:

Tuesday 1 September 2009

How to display Dynamic Content without Property control

Recently I was investigating EPiServer's Dynamic Content a bit. General impression is very positive, Dynamic Content is a great feature. From developer's point of view it's fairly easy to develop custom Dynamic Content, everything works like charm .... maybe beside one thing :)

Unfortunately, to display property's value with dynamic content replaced with our controls it's required to use EPiServer's control:

   1:  <EPiServer:Property PropertyName="MainBody" runat="server" />

Different approaches won't work.

   1:  <%= CurrentPage["MainBody"] %>
   2:  <%= CurrentPage.Property["MainBody"] %>
   3:  litMainBody.Text = CurrentPage.Property["MainBody"].ToWebString()



It is a considerable drawback as there are cases in which it's required to do something with property's value before displaying it:
  • For example you may want to alter all links by adding some extra parameters
  • When using Model-View-Presenter (flavor of MVC) you want to pass only pure data to the view.
It was worth spending some time to find a workaround. In the end, solution turned out to be not so convoluted, here is a control which takes a string and displays it replacing any dynamic content with corresponding controls.

   1:  public partial class DynamicContent : UserControlBase
   2:  {
   3:      public string StringToDisplay
   4:      {
   5:          set
   6:          {
   7:              var propertyControl = new PropertyLongStringControl
   8:                                        {
   9:                                            Page = Page,
  10:                                            PropertyData = new PropertyXhtmlString(value)
  11:                                        };
  12:              Controls.Add(propertyControl);
  13:          }
  14:      }
  15:  }

And the usage is really straightforward:

   1:  <unit:DynamicContent runat="server" id="dcMainBody" />
   2:  
   3:  dcMainBody.StringToDisplay = CurrentPage.Property["MainBody"].ToWebString();

Before calling dcMainBody.StringToDisplay you can of course change property's value in any arbitrary way.

Hope it will save someone a bit of time :)

Tuesday 30 June 2009

EPiServer Composer - How to load content functions defined on a different page

This in another example of interesting EPiServer Composer (version 3.2.5) use case - on homepage there is a content area called "Bottom Area" which contains number of content functions. I want to display this whole content area on other arbitrary pages.

Here is a piece of code which can do this for us:

   1:  var structure = PageDataManager.LoadPageStruct(homepage.PageLink);
   2:  var contentArea = structure.GetContentAreaById(AreaName.BOTTOM_AREA_ID);
   3:  for (var i = 0; i < contentArea.ContentFunctions.Count; i++)
   4:  {
   5:      var data = contentArea.ContentFunctions[i];
   6:      var contentFunction = PageDataManager.InitContentFunctionControl(ExtensionGeneric.ViewMode.ExtensionNormalMode,
   7:                                                                       Page, data);
   8:      plhContainer.Controls.Add(contentFunction);
   9:      
  10:      var element = contentFunction as IListItemPosition;
  11:      if (element == null) continue;
  12:  
  13:      element.IsLastElement = IsLastElement(i, contentArea);
  14:      element.IsFirstElement = IsFirstElement(i);
  15:      
  16:  }

Explanation:
  1. In first two lines I'm using PageDataManager to get instance of ExtensionPageData class for homepage and then I can easily access required content area. Please note that to load data from a different page you just need to provide reference to a different page.
  2. Heaving an instance of ContentAreaData class (contentArea variable) I have access to the list of all content functions (contentArea.ContentFunctions)
  3. In lines 5-8 I'm instantiating each content function and then it can be added to the PlaceHolder which is a container for all content functions.
  4. In lines 10-14 I'm detecting first and last element as those elements may require some special CSS classes. You can read more about IListItemPosition interface and how to figure out which content function is first/last in my previous post.
To get everything working you still need those two simple methods:

   1:  private static bool IsFirstElement(int i)
   2:  {
   3:      return i == 0;
   4:  }
   5:  
   6:  private static bool IsLastElement(int i, ContentAreaData contentArea)
   7:  {
   8:      return i == contentArea.ContentFunctions.Count - 1;
   9:  }

I think it's fairly simple but if you have any questions don't hesitate to leave a comment.

Sunday 28 June 2009

EPiServer Composer - How to figure out which content function is first (or last) within a content area

In my previous post (EPiServer-based site in 4 weeks?) I have presented number of quite high level thoughts regarding our last EPiServer project. In this and a few forthcoming post I would like to focus more on technical details and present several more interesting EPiServer Composer (version 3.2.5) use cases.

How to figure out which content function is first (or last) within a content area.

Imagine following piece of user interface:


It's an area where editors can define four arbitrary components. Components can be a text, image + text or just an image. Here is a typical html for this use case:

   1:  <div class="options">
   2:     <div class="option first"> ... </div>
   3:     <div class="option"> ... </div>
   4:     <div class="option"> ... </div>
   5:     <div class="option last"> .... </div>
   6:  </div>

Div with class options is a wrapper for all components. Each component has a class option. Quite typically in situation like this, first and last elements are a bit different. Depending on site design it's required to add some visual effects and that is why additional classes are added to the first and last element. This is very flexible approach as changes in html are minimal and final visual effect depends fully on CSS.

The problem for developer is that EPiServer Composer allows to simply drag and drop any number of content functions and each function is fairly autonomous. Content function is responsible for displaying html, it has no knowledge about context in which it was used. It doesn't know anything about content area to which it belongs, also it doesn't know anything about other content functions within the same content area. That is why to get information about context you need to operate one level above the functions.

But firstly, each content function need to implement following interface:

   1:  public interface IListItemPosition
   2:  {
   3:      bool IsLastElement { get; set; }
   4:      bool IsFirstElement { get; set; }
   5:  }

And now tricky part - changes on the higher level. A few things need to be added to the page/class which inherits from ExtensionBaseTemplate.

You need to override OnInit method:

   1:  protected override void OnInit(EventArgs e)
   2:  {
   3:      CurrentExtensionPageHandler.LoadContentArea += CurrentExtensionPageHandler_LoadContentArea;
   4:      CurrentExtensionPageHandler.LoadContentFunction += CurrentExtensionPageHandler_LoadContentFunction;
   5:  
   6:      base.OnInit(e);
   7:  }
Above code adds our handlers to the following events:
  • LoadContentArea - this way we will get information about all available content areas and what is more important - count of content functions for each area!
  • LoadContentFunction - Composer fires this event for each content function. Having a total number of content functions for each area we can easily detect first and last elements.

Here are implementations for the handlers:

   1:  #region ContentAreaFunctionCounter
   2:  
   3:  protected ContentAreaFunctionCounter ContentAreaFunctionCounter = new ContentAreaFunctionCounter();
   4:  
   5:  protected void CurrentExtensionPageHandler_LoadContentFunction(object sender, ExtensionPageEventArgs e)
   6:  {
   7:      var element = e.ContentFunction as IListItemPosition;
   8:      if (element == null) return;
   9:      
  10:      element.IsFirstElement = IsFirstElement(e);
  11:      element.IsLastElement = IsLastElement(e);
  12:  }
  13:  
  14:  private static bool IsFirstElement(ExtensionPageEventArgs e)
  15:  {
  16:      return e.ContentArea.Controls.Count == 0;
  17:  }
  18:  
  19:  private bool IsLastElement(ExtensionPageEventArgs e)
  20:  {
  21:      var numberOfElements = ContentAreaFunctionCounter.GetContentAreaFunctionCount(e.ContentArea.ID);
  22:      return e.ContentArea.Controls.Count == (numberOfElements - 1);
  23:  }
  24:  
  25:  protected void CurrentExtensionPageHandler_LoadContentArea(object sender, ExtensionPageEventArgs e)
  26:  {
  27:      var functionsCount = e.ContentAreaData == null ? 0 : e.ContentAreaData.ContentFunctions.Count;
  28:      ContentAreaFunctionCounter.SetContentAreaFunctionCount(e.ContentArea.ID, functionsCount);
  29:  }
  30:  
  31:  #endregion

Missing part is class ContentAreaFunctionCounter which is responsible only for keeping information about available content areas and functions count:

   1:  public class ContentAreaFunctionCounter
   2:  {
   3:      private readonly IDictionary<string, int> contentAreaFunctionCount = new Dictionary<string, int>(); 
   4:      
   5:      public void SetContentAreaFunctionCount(string contentArea, int functionCount)
   6:      {
   7:          contentAreaFunctionCount[contentArea] = functionCount;
   8:      }
   9:  
  10:      public int GetContentAreaFunctionCount(string contentArea)
  11:      {
  12:          if (contentAreaFunctionCount.ContainsKey(contentArea))
  13:          {
  14:              return contentAreaFunctionsCount[contentArea];
  15:          }
  16:  
  17:          return 0;
  18:      }
  19:  }

I would recommend creating a base class encapsulating this functionality. Each content function which needs to be aware of it's position just need to implement the IListItemPosition interface. And that's it! :)

If it's necessary you can easily extend IListItemPosition interface to contain int Position {get; set;} property and this way give all functions idea about it's position (not just first and last one).