Showing posts with label Miscellaneous Stuff. Show all posts
Showing posts with label Miscellaneous Stuff. Show all posts

Wednesday, 15 April 2009

Action<T> and Func<TResult> delegates

In this post I would like to write a little bit about two types of delegates which were added recently with ASP.NET 3.5 (System Namespace):

Action<T> - "Encapsulates a method that takes a single parameter and does not return a value". There are additional versions for two, three and four parameters:
It can be used with method like this:

   1:  public static void UpdatePage(PageData page, Action<PageData> action)
   2:  {
   3:      var writableClone = page.CreateWritableClone();
   4:      action(writableClone);
   5:      DataFactory.Instance.Save(writableClone, SaveAction.Publish);
   6:  }

To updated page in EPiServer it's required to create writable clone first, then we can apply our changes and finally instance of PageData has to be saved. This is a procedure which you can probably find in many places in your projects. With delegates you can easily "close" standard steps into a single method and pass changeable part as a parameter, like this:

   1:  PresenterUtils.UpdatePage(CurrentPage,
   2:                            p =>
   3:                                {
   4:                                    p.Property["MetaAuthor"].Value = "Marek";
   5:                                    p.Property["MainBody"].Value = "Hello World!";
   6:                                });

I think it should be pretty obvious that the above piece of code changes MetaAuthor and MainBody properties on CurrentPage. For me, main benefit of this approach is increased readability, hence the code is easier to maintain. Note that there is nothing in this call about creating writable clone, calling save method on DataFactory, those are all important and required steps to get things working properly but in the same time they are irrelevant from businesses logic point of view. You don't need to see those "standard" actions to understand what your class/method is doing.

You can also use delegates which return a value:
The simples version Func<TResult> - "encapsulates a method that has no parameters and returns a value of the type specified by the TResult parameter."

In this example, method returns default value if property doesn't exist or is not set. If property is set then its value can be formatted in some special way:

   1:  public static string GetProperty<T>(PageData page, string propertyName, string defaultValue, Func<T, string> customAction)
   2:  {
   3:      if (page == null || string.IsNullOrEmpty(propertyName) || page[propertyName] == null)
   4:      {
   5:          return defaultValue;
   6:      }
   7:  
   8:      return customAction((T) page[propertyName]);
   9:  }

And this is how this method can be used:

   1:  public string GetFormattedDate(PageData page, string format)
   2:  {
   3:      return PresenterUtils.GetProperty<DateTime>(page, "EventDate", "", x => x.ToString(format));
   4:  }

In the above example we are interested in EventDate property, if this property is not set then empty string (default value) will be returned, otherwise DateTime will be formatted appropriately.

Of course, in pre-ASP.NET 3.5 era things like this were also possible but it was required to define your own delegates etc. Now you can use those which are available for you in the framework. Personally I really like lambda expressions and this "way" of crating APIs, it's much more readable for me therefore I encourage you to give it a try! :)

Friday, 10 April 2009

Convention over Configuration

In this post I would like to introduce design pattern which is particularly close to my heart - Convention over Configuration. What I like the most about this pattern is that it eliminates lots of monkey code which we have to write from time to time. Firstly let me explain to you what I mean by monkey code.

Monkey code

Typical case of monkey code can be found in old-fasihion NHibernate mappings:

   1:  <hibernate-mapping>
   2:    <class name="Product" table="tblProduct">
   3:      <id name="Id" type="Int32" column="ProductID">
   4:        <generator class="identity" />
   5:      </id>
   6:      <property name="ProductLine" type="String">
   7:        <column name="ProductLine" length="2" />
   8:      </property>
   9:      <property name="Class" type="String">
  10:        <column name="Class" length="2" />
  11:      </property>
  12:      <property name="Size" type="String">
  13:        <column name="Size" length="5" />
  14:      </property>
  15:      <property name="DaysToManufacture" type="Int32">
  16:        <column name="DaysToManufacture" not-null="true" />
  17:      </property>
  18:      <property name="ModifiedDate" type="DateTime">
  19:        <column name="ModifiedDate" not-null="true" />
  20:      </property>
  21:      <property name="ListPrice" type="Int32">
  22:        <column name="ListPrice" not-null="true" sql-type="money" />
  23:      </property>
  24:    </class>
  25:  </hibernate-mapping>

Even though in most cases column name and property name are the same, we still have to specify them. There is nothing really creative in this code. I think it's general problem for all sorts of mappings, it doesn't really matter if they are in a form of XML or a plain-old-CLR-objects - someone has to write this pesky piece of code. If you multiply time needed to map single column by number of columns and then by number of tables then you will get huge waste of time.

Conventions

I like Fluent NHibernate so much because it uses conventions, for instance I can say that all my tables have the same names as my classes and let fluent-nh map everything for me.

Within one application there might be number of aspects to which conventions can be applied. For instance, in fluent-nh it might be:

  • class name vs table name
  • property name vs column name
  • reference property name vs foreign key column name

Another project using conventions is ASP.NET MVC:

  • project structure - there are separate folders for Views, Controllers and Model
  • views placement - by default ASP.NET MVC framework will try to find view for given controller and action in folder like this: /Views/controllername/actionname.aspx.
    Action name equals view name.
As you can see based on ASP.NET MVC example, conventions are not just to eliminate monkey code, they can be also used to establish common standards for project structure, classes/properties naming etc.

Implementation

Lets try to put this high level ideas into concrete ... how Convention over Configuration can be implemented? I will try to present an algorithm based on fluent-nh and real life scenario where we have to map database tables to classes but all tables in database have "tbl" prefix. Of course we don't want to name our classes with this prefix, also we don't want to specify manually for each class that corresponding table's name is "tbl" + class name.

Normally with fluent-nh you would write your own convention implementing IClassConvention interface, then you would use FluentConfiguration class to "fluently" configure your database, add your mappings and also add your custom conventions. Having that you would call BuildSessionFactory() to get instance of properly configured NHibernate's SessionFactory. It's all straightforward but lets look under the hood to see what is going on behind the scene:
  1. In the first step fluent-nh loads classes responsible for "convention discovery". Each class from this group is responsible for single convention, this way it's really simple to add new additional conventions later.
    To find all "discovery" classes you can for instance use reflection to get all classes from a given namespace (flunet-nh's way) or all classes implementing some interface.
  2. Then it instantiates all mapping classes, custom conventions and default conventions. Default conventions will be used if there are no custom conventions. Be default class name will be equal to table name, we want to change it therefore we have to provide our own convention. It's important to remember that default convention shouldn't overwrite custom one.
  3. Next, it executes all "convention discovery" classes. Corresponding methods will get as a parameter all mappings and are responsible for finding and applying specific conventions.
This is high level algorithm which allows you easily add additional conventions. You can have set of default conventions, but also you can provide your custom one. In general it is important to remember that
  1. Any convention (default or custom) shouldn't overwrite explicit configuration!
  2. Default convention shouldn't overwrite custom conventions!

Code samples

All conventions have to implement this simple interface:


   1:  public interface IConvention<T> : IConvention
   2:  {
   3:      /// <summary>
   4:      /// Whether this convention will be applied to the target.
   5:      /// </summary>
   6:      /// <param name="target">Instace that could be supplied</param>
   7:      /// <returns>Apply on this target?</returns>
   8:      bool Accept(T target);
   9:  
  10:      /// <summary>
  11:      /// Apply changes to the target
  12:      /// </summary>
  13:      /// <param name="target">Instance to apply changes to</param>
  14:      void Apply(T target);
  15:  }

Accept() method allows you to have number of conventions of given type and use them based on your custom logic.

This is how "discovery" is implemented:

   1:  public void Apply(IEnumerable<IClassMap> classes)
   2:  {
   3:      var conventions = conventionFinder.Find<IClassConvention>();
   4:  
   5:      foreach (var classMap in classes)
   6:      {
   7:          foreach (var classConvention in conventions)
   8:          {
   9:              if (classConvention.Accept(classMap))
  10:                  classConvention.Apply(classMap);
  11:          }
  12:      }
  13:  }

ConventionFinder returns all objects implementing IClassConvention interface, then it applies this all conventions to all mappings.

Finally, our convention which will add "tbl" prefix for table name:


   1:  public class TableNameConvention : IClassConvention
   2:  {
   3:      public bool Accept(IClassMap target)
   4:      {
   5:          return string.IsNullOrEmpty(target.TableName);
   6:      }
   7:  
   8:      public void Apply(IClassMap target)
   9:      {
  10:          target.WithTable("tbl" + target.EntityType.Name);
  11:      }
  12:  }

And a few interesting pieces of code which I found in fluent-nh sources:


   1:  private void AddDefaultConventions()
   2:  {
   3:      foreach (var foundType in from type in typeof(PersistenceModel).Assembly.GetTypes()
   4:                                where type.Namespace == typeof(TableNameConvention).Namespace && !type.IsAbstract
   5:                                select type)
   6:      {
   7:          ConventionFinder.Add(foundType);
   8:      }
   9:  }

The above method finds all default conventions. Next method instantiates type using default constructor or the one which takes (in this case) ConventionFinder as a parameter:

   1:  private object Instantiate(Type type)
   2:  {
   3:      object instance = null;
   4:  
   5:      foreach (var constructor in type.GetConstructors())
   6:      {
   7:          if (IsFinderConstructor(constructor))
   8:              instance = constructor.Invoke(new[] { this });
   9:          else if (IsParameterlessConstructor(constructor))
  10:              instance = constructor.Invoke(new object[] { });
  11:      }
  12:  
  13:      return instance;
  14:  } 

I hope that this post gives you much better idea about Convention over Configuration in general but also explains how to implement this pattern in practice. I encourage you to give it a try instead of writing monkey code.

If you encountered different cases where CoC fits perfectly I would be very interested to hear about it, leave a comment or send me an email. Or maybe you in general disagree ... leave a comment ... it will be interesting to know your view on this.

Tuesday, 3 March 2009

DefaultButton - Deal with users hitting ENTER on your forms

Developers tend to assume that users will be always clicking on the buttons to submit forms. Is it a valid assumption? Unfortunately not always ... the simplest example can be quick search, a common component on many sites.


What if user simply hit ENTER instead of clicking on the button next to the text box? Because our button wasn't clicked then of course even handler for Click event won't be invoked. The problem is that users expect that hitting Enter will correctly submit the form. So what can we do?

HtmlForm and Panel classes have a property called DefaultButton. Thanks to this property we can address the issue. First lets check the HtmlForm.DefaultButton property, here is how it can be used:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      Page.Form.DefaultButton = btnSearch.UniqueID;
   4:  }

That's all what is needed to make sure that post back generated by pressing the ENTER key will be "associated" with the button btnSearch. That is an improvement, but there is another problem to solve, check contact us page:

This is slightly more complex situation as here we would like to have Send button to be the default button for HtmlForm. So what about quick search? The following piece of code will solve it:

   1:  <asp:panel id="pnlSearch" runat="server" defaultbutton="btnSearchButton">
   2:      <asp:textbox id="txbSearchQuery" runat="server" validationgroup="search" maxlength="50" />
   3:      <asp:Button id="btnSearchButton" runat="server" text="Search" validationgroup="search" />
   4:  </asp:panel>

By surrounding the quick search controls with ASP.NET panel we can define for that group default button, different default button then the one on HtmlForm. In this simple way it's possible to define arbitrary number of small areas on the page with custom default button.

Another thing worth noticing is that defining unique validation group for all functionally related groups of controls is considered as a good practice. This way you can be sure that submitting one group won't trigger validation somewhere else.

I know that those are not a life-changing features but still I find them very useful, it's good to dust off basics like this from time to time.

Wednesday, 18 February 2009

Google Trends

Have you ever wanted to check how popular are certain key words in search engines? Or maybe how busy are popular websites? Now it's all possible with Google Trends.

For instance you can check number of daily unique visitors for popular websites like Twitter and Digg and additionally, you can compare them on a single chart:

Clearly you can see that Twitter is growing whereas Digg has some problems with keeping the levels.

If you check Search Volume Index then you will get the same conclusion:

On this graph you don't see actual traffic numbers ...
The numbers you see on the y-axis of the Search Volume Index aren't absolute search traffic numbers. Instead, Trends scales the first term you've entered so that its average search traffic in the chosen time period is 1.0; subsequent terms are then scaled relative to the first term. Note that all numbers are relative to total traffic.
It's not my intention here to show you that Twitter is trendy, I want to give you an idea how interesting information you can find with Google Trends. You can now easily check how popular different ideas/technologies/products/politicians are. Try to see for instance how rapidly is growing number of searches for ASP.NET MVC - it's growing really fast. (Actually, thanks to an article Interest in ASP.NET MVC is raising I have learned about Google Trends)

Remember though, Google Trends will give you only estimated values, those are not accurate data:
It's important to keep in mind that all results from Trends for Websites are estimated. Moreover, the data is updated periodically, so recent changes in traffic data may not be reflected. Finally, keep in mind that Trends for Websites is a Google Labs product, so it's still in its early stages of development and may therefore contain some inaccuracies.
In opinion ... even though the data are estimated and not all websites are included ... it's still an awesome tool!

Sunday, 8 February 2009

That's what I call a comfortable office

You guys know Joel Spolsky right? At the moment he is a CEO at Fog Creek Software, small company in Manhattan. I'm really impressed with their new office, take a look on a slideshow.

Joel was writing a few times that his main goal is to provide the best possible environment for software developers and this way gain the highest productivity:

Building great office space for software developers serves two purposes: increased productivity, and increased recruiting pull. Private offices with doors that close prevent programmers from interruptions allowing them to concentrate on code without being forced to stop and listen to every interesting conversation in the room. And the nice offices wow our job candidates, making it easier for us to attract, hire, and retain the great developers we need to make software profitably. It’s worth it, especially in a world where so many software jobs provide only the most rudimentary and depressing cubicle farms.
I know exactly how important that is as I'm lucky to work for company having the same goal. But still, there are things I feel jealous about after checking the slideshow. Beside the awesome design I especially like 30“ monitors (I had a chance to work a bit on 22“ monitors and I'm 100% convinced that it makes a difference) or long desks (huge monitors require huge desks ;) ). I'm sure that one day I will talk my boss into buying such a nice monitors for us ;)


Here you can find Joel's post about new office, and an article about the office in The New York Times.

Thursday, 4 December 2008

The Story of the Ribbon

Yesterday I had a chance to attend the 14th Poznan .Net User Group meeting. One of the guests was Mariusz Jarzębowski from Microsoft with his presentation "The Story of the Ribbon".


Microsoft Word 2007 and the Ribbon user interface

This excellent presentation was demonstrated for the first time during the MIX 2008 by Jensen Harris. (Edit: Presentation which we saw was inspired by both Jensen Harris' blog post and his presentation during the MIX08) Thanks to Mariusz we got a chance to see it live and "experience" evolution of Microsoft Office user interface (UI) from the very beginning - version 1.0 to the latest one - Office 2007. I think it's safe nowadays to say that The Ribbon started new era in UI design world. Mariusz gave us lots of insights regarding the process and decisions which have changed the way we think about the UI. Microsoft has invested years of work to check number of concepts, build prototypes, analyse data ... very detailed data.

For instance there are at least three ways to save document in MS Word
  1. Ctrl+S,
  2. save on toolbar and,
  3. menu File->Save.

Based on gathered data Microsoft realized that roughly 80% of people use Toolbar to save documents, 20% use Ctrl+S and almost noone uses the File->Save option. It was even more interesting that the same rule applies to other commands, hence that they can get rid of the old-fashion menu as people don't use it anyway!

Even though the numbers (exact number of clicks for each option) were convincing, still changing approach and switching from ordinary menu to the Ribbon was a risky decision. Microsoft took that risk and released the Ribbon which in my opinion (and not only my) makes them one of the most innovative company in the IT industry.

Mariusz also presented some other cool and relatively new concepts/features like:
  • Deep Zoom which allows users to explore collection of (usually) high resolution pictures without downloading them all at once to the client. Microsoft released Deep Zoom Composer which users can use to create presentation of images and then preview it with Silverlight 2 and Deep Zoom feature. check Seadragon project for more details and demos. Also check Hard Rock website for great example of Deep Zoom in action.
  • Photosynth is yet another cool concept which allows users to generate 3D model based on the pictures taken with any ordinary digital camera. Great stuff and very spectacular, it also uses Deep Zoom to enrich user experience. Check this presentation of Blaise Aguera y Arcas showing Deep Zoom and Photosynth.



  • pptPlex - Deep Zoom can also be used to change your Powerpoint presentations, this plug-in enables this feature.

For me this meeting was very interesting and I hope that Mariusz will visit us again at some point in the future. In a meantime let's enjoy all that new tools and keep eyes open for next innovative ideas as I'm sure that they will come.

Sunday, 31 August 2008

ASP.NET and JQuery = powerful combination

Over last few years number of interesting JavaScript frameworks emerged. My reaction to JavaScript used to be quite allergic, for me there was no such thing like a maintainable JavaScript code. But apparently things have changed drastically. At the moment we can choose from many different frameworks:

All of them are pretty mature, well documented and definitely worthwhile.

Recently I was forced to play with JQuery a bit ... believe me, we were trying everything to avoid it but in the end we gave up. Why? Partly because we couldn't replace JQuery with ASP.NET Ajax in a efficient way and partly because after a profound investigation I changed my mind about Javascript. In fact I was having one of those 'Ah-ha!' moments ... I was really amazed how many cool things you can do with just a few lines of code.

I don't pretend to be a JQuery expert but let me show you just a simple example, simple use case which I used as a opportunity to learn more about JQuery.

Okey, let's start ... we want to create a personal contact list. Applications will list all people with a telephone number and some additional details. Important part of this use case is user experience, our aim is to use ajax calls as much as we can in order to avoid reloading the whole page. Let's say that this is how the application will look like:



I have used one of WUFOO's css thames and this is the only reason why this application looks not so bad ... UI and CSS design is not my strong side ;)

Anyway, interesting part now ... after clicking on details, table should expand and we should get some additional information regarding selected person. Expandable table should be implemented using ajax calls. Final view should look like this:



Assumptions

  • Normally, to create application like this, you need to have some way to persist data, it can be anything ... database, xml file, text file or anything else. In this case our data will be hardcoded (check source code) as this post is focused on user interface.
  • Number of controls can be used to generate table like this ... personally I would use repeaters to do the job but other options are also good and again ... that's not the point.

JQuery magic

JavaScript in this example is responsible for:
  • making sure that when 'Details' link is clicked our function will be invoked.
  • getting all required details for selected person with ajax call and showing them to the user.

All of that can be done with this piece of JavaScript:



$(document).ready(function () {
// find our 'Details' links and bind click event with our function
$(".aDetails").click(function (e) {

// we will use this link to get contactID
var link = $(this);

// find parent row
var row = link.parent('td').parent('tr');

// remove focus from the link
link.blur();
e.preventDefault();

// remove selection from other rows
$(".on").removeClass("on").next('tr.detailsPanel').remove();

// select this row
row.addClass("on");

// get details - ajax call
$.ajax({
url: applicationPath + "/utils/ContactDetails.aspx?contactID=" + link.attr("contactID"),
success: function(html){
row.after(html);
}
});
});
});

In-code comments should give you the idea about what is going on ... if something is still not clear then
  • check how the HTML is structured, it should help you understand what exactly functions like next('tr.detailsPanel') are doing,
  • and of course check JQuery documentation

Why ASP.NET Ajax is not a good alternative?

It's not a big challenge to get the same results in terms of user experience with ASP.NET Ajax, the simplest way is to put control responsible for rendering the table to a UpdatePanel like this:



<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Repeater ID="Repeater1" runat="server">
....
</asp:Repeater>
</ContentTemplate>
</asp:UpdatePanel>


It works but in fact each ajax call refreshes whole table ... and in this case it means that almost whole site is refreshed instead of one row. As long as number of records is small it's fine ... but if you have huge number of records it might turn out to be a problem. I haven't found any sensible way to update just one row ... maybe you can suggest something?

I hope that this little application shows that JavaScript is back in the first league. Developers should be familiar with at least one JavaScript framework ... pick the one which you like. Frameworks like JQuery provide many very flexible and powerful features which can help enhance your sites.

My plan is to continue enhancing this application, keep learning and experimenting ... stay tuned as next parts of my adventures with JQuery will show up. Source code for this part can be downloaded from here.

Wednesday, 6 August 2008

ASP.NET Web Application debugging and timeouts

While developing web applications it's absolutely normal that at some point it's necessary to debug a code to check variable's value, execution flow for some weird input data and so on. Before running application in debug mode Visual Studio will prompt you with a following dialog:



For developers answer is simple ... of course that we want to enable debugging! So you click OK button and everything works fine. But do you know where is it saved and what are the implications? If you are not sure then probably you should read this post carefully ;)


<compilation debug="false"/>


This part of web.config determines if debugging is enabled or not. Also this part will be changed if you click OK button. What are the implications beside the fact that you can debug the code? Well, literally, consequences are extremely HUGE, here comes a short list:

  1. The compilation of ASP.NET pages takes longer (since some batch optimizations are disabled)
  2. Code can execute slower (since some additional debug paths are enabled)
  3. Much more memory is used within the application at runtime
  4. Scripts and images downloaded from the WebResources.axd handler are not cached


Moreover, timeouts are turned off, which is necessary to debug the code but can be potentially very dangerous on production sever.

I don't want to write yet another post about debug="true" attribute, production servers and performance impact as there are already lots of really good posts about it, check at least those two:


But one additional thing is worth pointing out ... even if you forget about the debug="true" issue then you can do something on production servers to make sure that web.config settings will be ignored:

in machine.config file set:



<configuration>
<system.web>
<deployment retail="true"/>
</system.web>
</configuration>


You will disable the debug="true" switch, disable the ability to output trace output in a page, and turn off the ability to show detailed error messages remotely. Note that these last two items are security best practices you really want to follow (otherwise hackers can learn a lot more about the internals of your application than you should show them).


Debug mode disabled and timeouts

In the optimistic version, when debug is turned off you can control your application timeouts with this attribute:



<system.web>
<httpruntime executiontimeout="40">
</httpruntime>


executionTimeout specifies the maximum number of seconds that a request is allowed to execute before being automatically shut down by ASP.NET.


But remember that:

This time-out applies only if the debug attribute in the compilation element is False.


I hope that this post made those things clear for you, check your configuration and make sure that web.config settings are not slowing your application down.