ctodx

This Blog

News

Favorite Posts

Archives

December 2010 - Posts

  • DevExpress Newsletter 39: Message from the CTO

    Just a quickie thought this time around, not too heavy:

    Avoiding micro-optimizations

    What's a micro-optimization, you may ask? It's applying a local-in-scope rule about optimization to your code without actually testing to see if it makes any difference to the performance of your application as a whole. Micro-optimizations are generally cast as never-to-be-broken rules, or even as items in some coding standards document.

    Sometimes we refer to them as premature optimizations. The root of all evil, to quote Knuth.

    Examples are easy to find: always using for instead of foreach, appending to a StringBuilder object instead of string concatenation, avoiding small methods to minimize the call time.

    Now, before you start huffing and puffing, I'm not advocating abandoning these optimizations, or saying that they are inherently evil, or anything like that. All I'm saying is that you should initially write code to be as clear as possible. That implies that your code should be readable, simple and understandable. Writing clear code gives you the best chance of creating provably correct software and of creating code that is easier to optimize. Writing clear code provides the best opportunity for enhancing maintainability. Clear code is generally more flexible and better able to adapt to future needs and changes. Consider using refactorings guided by software metrics to simplify your code. Consider using your skills as a developer to identify and remove code smells.

    And it's only after your code is written that you get to profile it to test its performance within the application. Only then do you get to analyze the hot spots in your application as a whole. Only then do you get to formulate a thesis ("replacing this simple-to-read foreach with a slightly harder to read for loop will improve the performance of my application as a whole") and then test it with the real application. Only then should you accept code changes that have a measurable change in your application's performance. Only then should you reject failed theses and revert your code to the simpler-to-read version.

    Don't change your code to suit some optimization fad: change it to improve its performance.

    Having written it, I now wonder: when do micro-optimizations become so familiar that they are clear and readable? As an example, I would venture to say that using a StringBuilder is actually more legible than writing a set of statements that do string concatenation. Or someInt >> 1 becomes just as readable as someInt / 2. Hmm.

  • Have VCL subscription? Get Build 54!

    Rainbow in Fireworks Vancouverphoto © 2006 Tony Hisgett | more info (via: Wylio)Just to let our VCL customers know that build 54 of our VCL subscription has just been released. The notification emails are just going out. Login, nip over to your download area, and download your early Christmas present!

    For the What’s New, check out this page. Remember that ExpressBars 7 and ExpressQuantumGrid 7 remain in beta for now.

    Have fun!

  • “Hey, you got a comparison chart between you and X?”

    There’s a short answer and a long one.

    The short one is No.

    The long one involves a couple of blog posts I’d written in the past, one from 2008 and one from 2007. I can’t really expand on them particularly since I said it all then and my/our viewpoint hasn’t changed.

    In essence, the only meaningful comparison between two paths/opportunities/products is the one you make or write, because a comparison is essentially subjective and not objective (what’s important to you may not be important to me, etc). But it’s amazing that people still ask for them (as did someone today; hence this post). Agreed they’re great for something to present to your boss without having to do any work, but it’ll be your reputation on the line, not ours, if the biased/generic/all-glitz-but-no-substance comparison turns out to be not specific enough to your environment and requirements.

  • Refactoring JavaScript to follow best practices

    NAM - Radium furniture polishphoto © 2006 Marshall Astor | more info (via: Wylio)Back in August this year, Mehul Harry, our ASP.NET evangelist, published a how-to blog post on adding keyboard support to the ASPxDataView. As he does sometimes, he asked me to check it for general readability — we all ask each other to do this every now and then: it’s amazing what errors a different pair of eyes can pick up in the text. Anyway, I can’t remember whether I found anything in his writing or not because I did find something awkward in the JavaScript being demonstrated in the post (which was written by the R&D team). At the time I promised Mehul I’d write something up on what I found — thinking it would be the following week — but it’s taken me until now (a good 3 months later) to follow up on my promise to fix and polish the code.

    When I wrote the JavaScript chapter in Professional DevExpress ASP.NET Controls, I espoused a particular best practice for coding in JavaScript -- minimizing your footprint in the global space. The optimal plan is to do as jQuery and YUI do: have one (or at the most two) global variables. Apart from the usual reasons for not using global variables which apply across all languages (well, apart from those that have no locals I suppose), the problem is doubled in JavaScript and other dynamic languages: redefining an existing global causes no error. Good luck on finding out that you’ve just stomped on some global variable without knowing about it; many intense sessions with Firebug lie in your future.

    In the book, I showed how this could be done by declaring a single global helper object and then having all previous global members be members of that object. Let’s do that here. First of all, get a hold of the CodeCentral code from here, and then follow along. (I’ll note that I recreated the project from scratch with a new ASP.NET project, so my “infrastructural” code that I may show won’t be exactly the same as you see in CodeCentral.) Before making any changes, run the app to ensure that you have no errors.

    The first thing we should do is get rid of the script block and put the JavaScript into its own JS file. Add a new JScript item to the Scripts folder (I called mine unimaginatively JSRefactor.js) and cut/paste the JavaScript into it. This is what you should have:

    var dataviewPerformingCallback = false;

    function AddKeyboardNavigationTo(dv) {
    dv.BeginCallback.AddHandler(function (s, e) { dataviewPerformingCallback = true; });
    dv.EndCallback.AddHandler(function (s, e) { dataviewPerformingCallback = false; });
    ASPxClientUtils.AttachEventToElement(document, "keydown",
    function (evt) {
    return OnDocumentKeyDown(evt, dv);
    });
    }

    function OnDocumentKeyDown(evt, dv) {
    if (typeof (event) != "undefined" && event != null)
    evt = event;
    if (NeedProcessDocumentKeyDown(evt) && !dataviewPerformingCallback) {
    if (evt.keyCode == ASPxKey.Left /*37-Left Arrow*/) {
    if (dv.cpPageIndex > 0)
    dv.PerformCallback('Prev');
    return ASPxClientUtils.PreventEvent(evt);
    } else if (evt.keyCode == ASPxKey.Right /*39-Right Arrow*/ && dv.cpPageIndex < dv.cpPageCount - 1) {
    dv.PerformCallback('Next');
    return ASPxClientUtils.PreventEvent(evt);
    }
    }
    }

    function NeedProcessDocumentKeyDown(evt) {
    var evtSrc = ASPxClientUtils.GetEventSource(evt);
    if (evtSrc.tagName == "INPUT")
    return evtSrc.type != "text" && evtSrc.type != "password";
    else
    return evtSrc.tagName != "TEXTAREA";
    }

    You can then replace the script block with this code by dragging the JS file to your header section of your ASPX file:

    <script src="Scripts/JSRefactor.js" type="text/javascript"></script>

    Rerun the app to make sure it still works. Now, to me, apart from the global variable issue (there are four in this minor piece of code), the code just looks like a C# developer wrote it. OK, the anonymous function declarations are idiomatic JavaScript, but that’s about it.

    Now to refactor. My first set of refactorings was fairly minor: I avoid == and != like the plague (see here for details) and so I replaced them with === and !==. In this example code, there’s no difference between the two but forcing yourself to using triple-equals may save you some debugging heartache in the long run and will make you look like a JavaScript pro. (CodeRush notes: we don’t support this code refactoring yet and we should.)

    The next refactoring is going to lay the foundation: we’ll add a new global object that will start to act as a repository for all the other JavaScript code.  Following along with another JavaScript best practice, we’ll be setting it up so that it uses a closure to hide data from the outside world (in other words, it’ll have private members — if we were talking about a C# object, that is). Also, because scoping in JavaScript is function-based we’ll set it up so that the object is created as a result of a function call. And to make sure we don’t have to name that function (and therefore have two global variables) we’ll declare it anonymously and immediately execute it. Ready?

    var jmbHelper = function () {
    var C = "private";
    return {
    A: 1,
    B: true
    };
    } ();

    Reading from the top down, I’m declaring a new global variable (that is, it’s a new member of the window object) to have the return value of the immediately-executed (spot the function call parentheses on the last line) anonymous function. The function returns an object, which has two public place-holder members: A, of value 1, and B, of value true. It has one private place-holder member C that, because of the joys of JavaScript closures is only visible throughout the anonymous function but not outside.

    Now to add some oomph to this object. If you look at the original code, you’ll see that the only function that should be visible publicly is the AddKeyboardNavigationTo() method (it’s used by the DataView’s ClientSideEvents.Init string/function) . Everything else is and should be private. So we’ll make that function a member of the returned object (basically replacing A and B) and everything else becomes part of the function itself (replacing C, in essence). I decided to make AddKeyboardNavigationTo()a function that called a private function, but the rest is as it was. (Note that I had to change the C# Page_Load code slightly to reference jmbHelper.AddKeyboadNavigationTo instead of just AddKeyboadNavigationTo.)

    var jmbHelper = function () {

    var dataviewPerformingCallback = false;

    function HookKeyboard(dv) {
    dv.BeginCallback.AddHandler(function (s, e) { dataviewPerformingCallback = true; });
    dv.EndCallback.AddHandler(function (s, e) { dataviewPerformingCallback = false; });
    ASPxClientUtils.AttachEventToElement(document, "keydown",
    function (evt) {
    return OnDocumentKeyDown(evt, dv);
    });
    }

    function OnDocumentKeyDown(evt, dv) {
    if (typeof (event) !== "undefined" && event !== null)
    evt = event;
    if (NeedProcessDocumentKeyDown(evt) && !dataviewPerformingCallback) {
    if (evt.keyCode === ASPxKey.Left /*37-Left Arrow*/) {
    if (dv.cpPageIndex > 0)
    dv.PerformCallback('Prev');
    return ASPxClientUtils.PreventEvent(evt);
    } else if (evt.keyCode === ASPxKey.Right /*39-Right Arrow*/ && dv.cpPageIndex < dv.cpPageCount - 1) {
    dv.PerformCallback('Next');
    return ASPxClientUtils.PreventEvent(evt);
    }
    }
    }

    function NeedProcessDocumentKeyDown(evt) {
    var evtSrc = ASPxClientUtils.GetEventSource(evt);
    if (evtSrc.tagName === "INPUT")
    return evtSrc.type !== "text" && evtSrc.type !== "password";
    else
    return evtSrc.tagName !== "TEXTAREA";
    }

    return {
    AddKeyboardNavigationTo: function (dv) { return HookKeyboard(dv); }
    };
    } ();

    You can check that this code works as before, but with only one global object: jmbHelper (and obviously you try and give this a unique name).

    Now we can do some further refactorings like renaming of variables (which originally were long since we didn’t want global identifier clashes). However, there’s actually a bug that perhaps is made more obvious by having wrapped this code into a single object: although AddKeyboardNavigationTo() can be called for any number of controls, there is only one flag that shows whether a control is in callback mode or not.  That’s a simple change in one way (add another property to the dv instance) or to have an array of flags. The first is just as bad as the global variable situation (how do you know you won’t choose an identifier that’s already being used?), so we’ll use the second. Here’s my final JavaScript code (at least for this article):

    var jmbHelper = function () {

    var inCallback = [];

    function canProcessKeyDown(evt) {
    var evtSrc = ASPxClientUtils.GetEventSource(evt);
    if (evtSrc.tagName === "INPUT") {
    return evtSrc.type !== "text" && evtSrc.type !== "password";
    }
    return evtSrc.tagName !== "TEXTAREA";
    }

    function processKeyDown(evt, dv) {
    if (inCallback[dv]) { return true; }

    evt = event || evt;
    if (!canProcessKeyDown(evt)) { return true; }

    // look for left arrow, process it if we can
    if ((evt.keyCode === ASPxKey.Left) && (dv.cpPageIndex > 0)) {
    dv.PerformCallback('Prev');
    return ASPxClientUtils.PreventEvent(evt);
    }

    // look for right arrow, process it if we can
    if ((evt.keyCode === ASPxKey.Right) && (dv.cpPageIndex < dv.cpPageCount - 1)) {
    dv.PerformCallback('Next');
    return ASPxClientUtils.PreventEvent(evt);
    }

    return true;
    }

    function hookKeyboard(dv) {
    inCallback[dv] = false;
    dv.BeginCallback.AddHandler(function (s, e) { inCallback[dv] = true; });
    dv.EndCallback.AddHandler(function (s, e) { inCallback[dv] = false; });
    ASPxClientUtils.AttachEventToElement(document, "keydown",
    function (evt) { return processKeyDown(evt, dv); });
    }

    return {
    addKeyboardNavigationTo: function (dv) { hookKeyboard(dv); }
    };
    } ();

    Some notes:

    1. hookKeyboard never returned anything, so I changed the definition of addKeyboardNavigationTo. Since the returned object is defined inside the scope of the outer function, its addKeyboardNavigationTo method has access to that internal (private) function because of the closure (I didn’t mention this before)
    2. Notice how I use the function scoping rules for the dv parameter in hookKeyboard. Even the anonymous handlers being set up in there have access to it.
    3. processKeyDown has had the biggest changes:
      • I’m using guard clauses to get out quickly, should the control be already in a callback or should the control process its own left/right arrow keys.
      • Notice the idiomatic JavaScript to set evt to event, or if it’s undefined or null to evt itself.
      • Event handlers return true (“we didn’t handle it so allow the event to propagate”) or false (“cancel the event, we’ve dealt with it”).
      • Although JavaScript has the “feature” that all identifiers declared in the scope of a function are visible throughout the function, I belong to the Douglas Crockford and JSLint camp where you should declare identifiers before you use them. Hence I’ve reordered the private members to be declaration-first. (Note that the final code passes JSLint’s default tests.)
    4. By convention, normal function names in JavaScript should start with a lowercase letter. An uppercase letter indicates a constructor. I changed all *my* function names; can’t do anything about existing ones.

    I hope you found that little discourse on JavaScript refactoring and polishing to be of interest. It actually helped me a lot: I’ve been trying to work out how to make our JavaScript support in CodeRush better and this refactoring exercise, although fairly simple, solidified some thoughts for me. I see a webinar between me, Mark Miller, and the IDE Tools team in my future...

  • 2011 roadmap digest for our VCL products

    As promised in the webinar this lunchtime, I wanted to make sure that our VCL customers were not left out in the cold with regard to plans for 2011 despite our discussion for VCL occurring after the webinar was over. Here are our plans.

    Overarching  goals

    Like with our other product lines I talked about in the webinar, I’m first going to define the overarching goals we have for VCL in 2011. These are:

    1. Changing our sales and distribution model
    2. Providing evaluation versions
    3. Provide more content in the form of tutorial videos, webinars, blog posts

    Up to now, we’ve had a crazy mix of how we sell our VCL products. There’s the traditional way of selling individual controls (traditional in the VCL market, that is) where customers buy an individual product and then get free updates for life on that product. The only way we can further monetize that product is to provide a major update which which we then charge for. Then there is the subscription model for the entire suite, where you purchase an annual subscription for all updates during that year, but you can use the package for as long as you want to even if you don’t renew. The latter is how we sell all of our .NET products and packages.

    We are going to change this sales mix as soon as we’ve worked out pricing and discounts for existing customers. From that point on we will only offer three suites, all on a subscription basis. We’ll beef up the ExpressQuantumPack suite with printing and skins. We’ll add a new pack, the ExpressGridPack to contain the grid, tree-list, pivot grid and printing. And then there will be the usual full VCL subscription. Doing this gives us the opportunity to provide better and more increased functionality across the board, without having to ignore some controls in favor of beefing up the main ones in order to provide a more compelling paid upgrade. It also helps us retire old versions of controls and avoid the complexities of managing interactions between an old version of control X and a newer version of control Y. With all controls on the same upgrade and testing path, our job is made easier and you get more stable and robust controls.

    Along with this change, we are going to move to a biannual release cycle for major releases with intermediary minor bug-fix releases released every month or so. In essence, the VCL team will be following the DXperience release cycle. and the major releases next year will be dubbed v2011 vol.1 and v2011 vol.2 (or 11.1 and 11.2 for short) and will appear in quarter 2 and in quarter 4.

    The next big change is that we are going to restrict which Delphi/C++Builder/RADStudio IDEs we will officially support. For Delphi these are Delphi 7 (we know a lot of you are still using it), Delphi 2007 (it’s the last ANSI string version), and Delphi XE (for UNICODE string fans). For C++Builder, it’s C++Builder 2007 and C++Builder XE. (Of course, these include the equivalent RADStudio versions.) Doing this means that we can spend less time in testing and support for a myriad of compilers and more time in writing new functionality. 

    OK, that was pretty much everything under that first overarching goal. The second goal has been requested for time immemorial, ever since we started DevExpress: provide a trial version. Goal 1 made this goal much more viable since it reduces the number of trial versions we should produce. Remember DCUs cannot be shared across IDE versions so every version of the IDE would require its own evaluation version. Three evaluation versions are easier to produce (and be more likely to be produced) than 9 or 10 under the old system.

    The third goal is merely a statement that VCL is a first class citizen of the DevExpress product line and will participate in the usual customer benefits and services.

    After all that, here are the plans for the two major releases in summary form.

    v2011 vol.1

    • Provide evaluation version of our VCL components – first IDE: RADStudio XE.
    • ExpressPivotGrid
      • Support compact layout for hierarchical row values (like the WinForms XtraPivotGrid in v2010.1)
      • Extend summary types (for example, count unique values) 
      • Add end-user capability to easily change the SummaryType of data fields
      • Improve export to Excel – make it possible to export data in a simplified layout to support further data analysis
      • Improve OLAP support
    • ExpressScheduler
      • Increase performance by redesigning the data store
      • Add an agenda view
      • Add task groups and subtasks for the Gantt view
      • Add milestone indicators for the Gantt view
      • Implement a treeview-like hierarchy for events and tasks in the Gantt view
      • Add iCal support
    • ExpressQuantumGrid
      • Add grid design wizard
      • Improve data controller performance
      • Add more chart views (examples being considered: splines)
    • ExpressBars
      • Add VS2005 (and later) docking indicator to the Docking manager
      • Add Office-like color selection dropdown

    v2011 vol.2

    • ExpressQuantumGrid
      • Add server mode
    • ExpressEditors
      • TcxDateEdit - provide a way to specify edit mask/display format
      • TcxScrollBar as a standalone component
      • Allow to use TcxImageList in TcxButtons
      • ReadOnly style
      • Extend functionality of Rich Text Editor
      • Add Windows Explorer breadcrumb editor
    • ExpressScheduler
      • Add an agenda view
    • ExpressQuantumTreeList, ExpressVerticalGrid, ExpressSpellChecker
      • Miscellaneous improvements

    More details to come when I publish the full roadmap towards the end of the year.

  • WinForms videos uploaded–gallery control, project wizard, simple skinning support (v2010 vol.2)

    We’ve just uploaded a trio of videos I did 10 days or so ago (yes, a little delayed but we’ve been producing videos faster than Jeff, our videographer, can edit and render, poor chap). They’re on new v2010 vol.2 functionality and are in a tutorial style.

    (Video) Adding skinning functionality simply to a WinForms application that uses traditional menu/bars.

    (Video) Using the new Project Wizard to create a standard layout as a starting point for a new WinForms application.

    (Video) Using the new Gallery control in a non-beribboned traditional WinForms application.

    I’ve got a few more up my sleeve, so stay tuned.

LIVE CHAT

Chat is one of the many ways you can contact members of the DevExpress Team.
We are available Monday-Friday between 7:30am and 4:30pm Pacific Time.

If you need additional product information, write to us at info@devexpress.com or call us at +1 (818) 844-3383

FOLLOW US

DevExpress engineers feature-complete Presentation Controls, IDE Productivity Tools, Business Application Frameworks, and Reporting Systems for Visual Studio, along with high-performance HTML JS Mobile Frameworks for developers targeting iOS, Android and Windows Phone. Whether using WPF, ASP.NET, WinForms, HTML5 or Windows 10, DevExpress tools help you build and deliver your best in the shortest time possible.

Copyright © 1998-2017 Developer Express Inc.
All trademarks or registered trademarks are property of their respective owners