Schrijf eens je eigen jQuery functies

Sinds enkele jaren en zeker sinds Microsoft gestart is met Asp.Net MVC heeft
jQuery een grote rol gekregen binnen de Microsoft wereld. Dit is duidelijk
zichtbaar door de sterke integratie in de Asp.Net MVC project templates, de door
Microsoft aanboden VS2010 integratie, de door Microsoft gedoneerde jQuery
templates en de sterke afhankelijkheid bij de Telerik MVC Extensions.

Waar nog maar enkele jaren geleden het schrijven van Javascript verguist
werd, is javascript en ajax momenteel HOT.

In mijn dagelijkse werkzaamheden is jQuery nu niet meer weg te denken. Toch
heb ik het idee dat ik en vele andere .Net ontwikkelaars jQuery nogal reactief
gebruiken. We schrijven wat code in de pagina ‘Ready’ functie, we binden
functies aan event, we doen wat ajax callback en we integreren leuke plugins om
de website minder spartaans te maken.

Function

En dat knaagt…

Toch heeft jQuery genoeg interessante facetten die het gebruik nog
plezieriger kunnen maken. Kijk maar eens naar het volgende voorbeeld. Ik wil
hier de link naar http://www.nu.nl/ als publieke link bestempelen. Maar zie jij
de bug?

// this code contains a bug
<html>
  <head>
    <script type="text/javascript"
            src="http://ajax.googleapis.com/ajax
                 /libs/jquery/1.6.1/jquery.min.js"></script>
  </head>
  <body>
    <a id="nupuntnl"
       href="http://www.nu.nl">Nu</a>
    <script type="text/javascript">
      $(document).ready(function() {
        $('#nuputnl').text('Public link');
      });
    </script>
  </body>
</html>

Zag u het? jQuery selectors zijn echt gaaf en kunnen heel veel werk besparen.
Met slechts een statement kan een hele verzameling DOM objecten gemanipuleerd  worden en door de fluent notatie kan diezelfde verzameling hergebruikt worden voor nog meer pret. Maar als je een typo in de selector hebt staan dan gebeurt er h-e-l-e-m-a-a-l niks.

Hierboven is de verwijzing naar de id van de link niet correct over genomen.
Het had moeten zijn:

<html>
  <head>
    <script type="text/javascript"
            src="http://ajax.googleapis.com/ajax
                 /libs/jquery/1.6.1/jquery.min.js"></script>
  </head>
  <body>
    <a id="nupuntnl"
       href="http://www.nu.nl">Nu</a>
    <script type="text/javascript">
      $(document).ready(function() {
        $('#<strong>nupuntnl</strong>').text('Public link');
      });
    </script>
  </body>
</html>

In dit geval wisten we bij het schrijven dat we één en slechts één control
wilden manipuleren. Met een klein beetje meer moeite had dit ook afgedwongen
kunnen worden.

Het is namelijk heel simpel om eigen jQuery functies te schrijven die .Net
ontwikkelaars het beste als ExtensionMethods zullen herkennen. Deze zijn dan
fluent uit te voeren op de $ (..)

De volgende jQuery functie controleert of er exact één control gemanipuleerd
wordt:

(function( $ ){
  $.fn.onlyOne = function(mode) {
    var mode = mode || 'off';
    if (mode != 'off') {
      if (this.length == 1) {
        if (mode != 'on') {
          alert('Information: one object found.' );
        }
      }
      else {
        alert('Warning: not one but '
               + this.length + ' objects expected.');
      }
    }
    // do not break the normal flow;
    return $(this);
  };
})( jQuery );

Deze functie heet OnlyOne en accepteert een string om de werking te
manipuleren. De functie staat in een apart javascript bestand die gerefereerd
zal worden.

De (function( $ ){ … })( jQuery ); is bedoeld om ruzie met andere (jQuery)
bibliotheken te voorkomen.

Als we nu de eerste (buggie) code, met deze functie uitgevoerd zouden hebben
dan krijgen we de volgende waarschuwing:

jquery functions

En de code zier er bijna hetzelfde uit:

<html>
  <head>
    <script type="text/javascript"
            src="http://ajax.googleapis.com/ajax
                 /libs/jquery/1.6.1/jquery.min.js"></script>
     <script type="text/javascript"
              src="jquery.functions.js"></script>
  </head>
  <body>
    <a id="nupuntnl"
       href="http://www.nu.nl">Nu</a>
    <script type="text/javascript">
      $(document).ready(function() {
        $('nupuntnl').<strong>onlyOne('on')</strong>
                     .text('Public link');
      });
    </script>
  </body>
</html>

Deze simpele functie maakt een hoop testen in de browser overbodig. En als
het niet meer nodig is, kan de functie zo uitgeschakeld worden.

Voor diegene die dit willen gaan toepassen, de functie accepteert vier
soorten input:

  1. ‘on’ geeft een melding als er niet fluent één object doorgegeven wordt.
  2. ‘verbose’ geeft altijd aan hoeveel objecten fluent doorgegeven worden.
  3. ‘off’ geeft nooit een melding, dit schakelt de interne logica uit.
  4. Geen parameter doorgeven is gelijk aan ‘off’. Of haal je de functie weer weg?

Een aardige variatie op de eerste function is het controleren of er één of
meer objecten doorgegeven worden met een nieuwe functie:

(function( $ ){
  $.fn.atLeastOne = function(mode) {
    var mode = mode || 'off';
    if (mode != 'off') {
      if (this.length > 0) {
        if (mode != 'on') {
          alert('Information: ' + this.length + ' objects found.');
        }
      }
      else {
        alert('Warning: At least 1 object expected.');
      }
    }
    // do not break the normal flow;
    return $(this);
  };
})( jQuery );

Als deze losgelaten wordt op drie links die dezelfde class delen:

<html>
  <head>
    <script type="text/javascript"
            src="http://ajax.googleapis.com/ajax
                 /libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript"
            src="jquery.functions.js"></script>
  </head>
  <body>
    <a id="nupuntnl" href="http://www.nu.nl">Nu</a>
    <a id="telegraaf" href="http://www.telegraaf.nl">Telegraaf</a>
    <a id="geenstijl" href="http://www.geenstijl.nl">geenstijl</a>
    <script type="text/javascript">
      $(document).ready(function() {
        $('.public').atLeastOne('verbose').text('Public link');
      });
    </script>
  </body>
</html>

In dat geval krijgen we netjes de melding dat we drie objecten gaan
manipuleren.

jquery functions

Uiteindelijk worden dan ook alle drie de links aangepast:

jquery functions

Conclusie
Natuurlijk kunnen bovenstaande functies nog uitgebreid worden. Te denken
valt aan het globaal aan of uitzetten of een extra string om de melding
specifieker te maken (bij welke aanroep gaat het exact fout).

Maar met een beetje fantasie of juist die minimale frustraties rond
jQuery kan het gebruik van jQuery functies ons dagelijkse leven iets dragelijker
maken. Wil je meer details weten, ga dan naar de jQuery site.

DebugView: Debug meldingen uitlezen zonder debugger

Bij mijn huidige project werd de vraag gesteld of één van onze websites
geïnstrumenteerd kon worden met debug meldingen zodat de werking, de flow door de code, gecontroleerd kon worden.

Daar we al aardig op weg waren naar de oplevering van een nieuwe release
was het introduceren van injectie frameworks geen optie. De gemakkelijkste
oplossing leek het ons om meldingen in de eventlog te schrijven. Natuurlijk
geeft dit een aardige belasting op die Application eventlog dus waren we wel zo
slim (..) om dit alleen te doen als onze projecten in debug mode gecompileerd
werden.

We wilden dus aan het begin en einde van een aantal methodes even loggen
dat we hier langsgekomen waren. Ook enkele try-catches moesten opgefleurd
worden.

Debugger

Het gebruik van #if DEBUG #endif had als neveneffect dat de code lekker
onleesbaar en minder onderhoudbaar werd. Gelukkig kwam ConditionalAttribute tot de redding:

using System.Diagnostics;
namespace Logging
{
  /// <summary>
  /// Log a message to the eventlog.
  /// This code is only available when the project is
  /// compiled in Debug mode
  /// </summary>

  public class LogToDebugEventLog
  {
    /// <summary>
    /// Logs the specified text only when the project is
    /// compiled as Debug.
    /// </summary>
    /// <param name="text">The text to log.</param>
    [Conditional("DEBUG")]
    public static void Log(string text)
    {
      EventLog.WriteEntry("Application", text);
    }
  }
}

Dit gaf lucht. Bovenstaande code geeft een compact statement om een tekst
te loggen. En het mooie is dat deze code verdwijnt als deze NIET in debug mode
wordt gecompileerd (vandaar dat het een static void is en dat in combinatie met
die “DEBUG”).

Vervolgens was er de vervolg-wens om de tijdsduur te loggen die verstreek
als een bepaalde actie uitgevoerd werd. Hiervoor is de StopWatch class prima te
gebruiken, maar ook die geeft nogal wat verstoring aan de huidige code. De
stopwatch moet in het geheugen aangemaakt worden, het moet gestart worden, het wordt hopelijk ook ooit gestopt en dan moet de tijdsduur afgedrukt worden. En een exception mag de werking niet verstoren…

Door handig met IDisposible te werken kan deze “code verstoring” sterk
teruggebracht worden:

using System.Diagnostics;using System;
namespace Logging
{
  /// <summary>
  /// Use this class in a Using to count the number of
  /// milliseconds an action takes
  /// </summary>
  public class DebugStopwatch : Stopwatch, IDisposable
  {
    /// <summary>
    /// Gets or sets the text to show when the stopwatch is stopped.
    /// </summary>
    /// <value>
    /// The text.
    /// </value>
    public string Text { get; set; }
    /// <summary>
    /// Initializes a new instance of the
    ///     <see cref="DebugStopwatch"/> class.
    /// </summary>
    /// <param name="text">the stopwatch is stopped.</param>
    public DebugStopwatch(string text)
    {
      Text = text;
      Start();
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing,
    /// releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
      Close();
    }

    /// <summary>
    /// Closes this instance.
    /// </summary>
    public void Close()
    {
      if (this.IsRunning)
      {
        Stop();
        LogToDebugEventLog.Log(
            String.Format("{0} - Elapsed time: {1}ms",
            Text,
            ElapsedMilliseconds));
      }
    }
  }
}

Bovenstaande class kan nu aangeroepen worden met slechts één
using:

using (var debugStopwatch = new DebugStopwatch("Method X"))
{
  // do some stuff here...
}

De stopwatch wordt gestart in de constructor (zegmaar: bij de eerste
accolade)en gestopt bij de dispose (de tweede accolade). De tekst die aan de
constructor meegegeven wordt, zal ook afgedrukt worden, tesamen met de
verstreken tijd in milliseconden.

De Close actie krijg je kado om eventueel met code de stopwatch te
stoppen.

Helaas wordt de timer ook aangemaakt, gestart en gestopt als de
applicatie niet als DEBUG versie wordt opgeleverd. Alleen de tekst wordt dan
niet getoond. Dit kan nog wel met een #if #endif opgelost worden want dit speelt
zich binnen de DebugStopwatch af. Maar wat er nog meer knaagde, was het feit dat we nog steeds de eventlog aan het vullen waren. Eigenlijk iedere vorm van loggen naar een permanente vorm (file/database) was niet wenselijk.

Toen moest ik denken aan een verwijzing naar een blog in de Morning
Brew
. Ik kan iedere Microsoft ontwikkelaar aanraden om zeker deze blog te
volgen. Sterker nog, als je dagelijks maar één blog wilt lezen, lees dan deze.
Het geeft simpele maar uitstekende opsomming van wat er momenteel aan
ontwikkelingen zijn rond Microsoft development. Ik laat het uittreksel dagelijk
in Outlook landen want die heb ik altijd openstaan en dan heb ik geen extra
feedreader nodig.

DebugView
In de Moringbrew had ik enkele weken geleden iets gelezen over debuggen
zonder debugger. Gelukkig vond ik het item snel terug en het bleek over DebugView te gaan, onderdeel van de onvolprezen SysInternals.

In deze gave verzamling van diagnose tooling zit ook een simpele
executable die kan luisteren naar Debug.Write en Trace.Write. Dus ik heb de betreffende blogpost doorgenomen en dit is een heel aardig stuk gereedschap. Het is namelijk erg lastig als op bepaalde machines (lees de test- of productieserver) de bestaande logging onvoldoende inzicht geeft over de
interne werking. En in die situatie zatten wij ook. Met deze tool kan gewoon
meegeluisterd worden zolang het een debug build betreft. Het is ook een ideale
tool naast Visual Studio om te werking te controleren zonder dat je met de
VS2010 debugger door de code moet steppen. Het kleine debugger schermpje binnen VS2010 loopt niet zo handig mee en DebugView heeft een keur van opties om de output inzichtelijk te maken (zoals always-on-top, filteren en zoeken).

Het tooltje is al enkele jaren oud maar het functioneert nog prima. Het
werkt zowel op XP als op nieuwere OS-en zoals Windows 7. Ik heb het werkend
getest met IIS en met IIS Express. Trace messages werken pas als “Capture Global Win32” wordt aangezet, maar die optie is niet beschikbaar onder XP. Onderstaande schermafdruk is in XP gemaakt. Hier wordt dus alleen de debug melding getoond (de breakpoint werd niet actief doordat ik draaide zonder debugger; opstarten met CTRL-F5):

DebugView in action

DebugView draait als executable dus hoeft niet geinstalleerd te worden op de
server. Wellicht draait het zelf vanaf een memorystick. Er is ook een Remote
Monitoring optie voor het debuggen van servers over het netwerk maar dit lijkt
mij lastig uit te leggen aan systeembeheerders…


Conclusie

Als nu de DebugStopWatch gecombineerd wordt met het gebruik van
Debug.WriteLine() voor DebugView, dan kan dit leiden tot een tijdelijke log die
prima inzicht geeft in de werking van een applicatie. Er is ook alleen maar een
afhankelijkheid met System.Diagnostics. De gecontroleerde code hoeft niet extra
geinstrumenteerd te worden met 3e partij frameworks.