DCSIMG
December 2007 - Posts - Justin myJustin = new Justin( Expriences.Current );

December 2007 - Posts

ASP.Net AJAX In Action, Manning (2007)

This post is meant so I could write some notes for myself while reading AJAX In Action (Manning, 2007). Feel free to read my comments, but do remember that the target audience is one well-armed MS AJAX self-proclaimed guru.

image 

 

 

Page 41 - Javascript diagram

image

I don't like this diagram. It's very demagogic. It shows a very organized "Server" and a very messy "Client".
Also, It doesn't highlight the fact the Javascript isn't just one more thing in the browser, It is AJAX.

Javascript isn't equivalent to DOM0, DOM2, CSS & XmlHttpRequest object.
It's bigger then any one technology, it's the glue that binds everything together.

 

 

Page 48 - That's the point of all this AJAX stuff

 

The book features this little XmlHttpRequest code (after properly explaining all the different members & cross-browser initialization issues).

image 

OK, pretty scary and I'm having flash-backs just by looking at "readyState == 4" and "status == 200".

However, then the authors just keep going like nothing happened and explain about AJAX.

People, Microsoft AJAX exists for one reason - developers are lazy and don't want to write code. Period.
We've just seen we can update a <div> text without MS AJAX.
This would have been a perfect place to show the 2 (!) lines of code needed by MS AJAX to do the exact same thing.

 

 

Page 52 - Xml-Script

image

Ok, Seriously, didn't the authors get the memo? Xml-script is dead.
Dead.

We took it out back and shoot it like the old diseased dog it was.
So why is the first MS AJAX sample in this entire book of Xml-Script?

 

 

Page 60 - We finally got started!

image

Finally, 60 pages and now they remember to open a new project!
Woo hoo!

 

 

Everywhere - Cross-browser under the radar

 

This one is just cool. Without telling the reader to pay attention - the authors randomly demo MS AJAX in different browsers.

image

image

 

 

Page 67 - Showing the Javascript proxy

image

This means nothing to everyone.
It's a bunch of random Javascript code.

If you're going to show it - explain what it does.

What I did in my "Will the Real Ajax presentation" (given at Jan '07 in front of 1,000+ folks) was the following slide:

image 

After drawing the watcher's attention to the relevent piece of code, I explained that this is the code that gives us "PageMethods" class of type "Sys.Net.WebServiceProxy" with a method "PageMethods.HasBlog". No point in showing code unless you explain it's highlights.

 

 

Page 68 - Using the MS AJAX $AddHandler and $get for event handling

 

image

Very nice syntax.
I don't use it often, I just use the normal onchange="depertment_onchange" HTML DOM0 events registration.

That's the common way of doing that... But It's still a nice syntax. 

 

 

 

Page 77 - ASP.Net Page == MS AJAX Application

image

Hmm... I never thought about this like that. That's a very true association.

I always thought of "Sys.Application" (Javascript) as the equivalent of "ApplicationDomain.CurrentDomain" (.Net).
It made since because the MS AJAX domain starts when browser loads a page and ends when it exits the page.

But it makes more sense to say that "Sys.Application" since also knows of events in the current MS Ajax page that it's equivalent to "System.Web.UI.Page".

 

 

Page 81 - "pageLoad" and "pageUnload" are automaticlly called

    <asp:ScriptManager ID="TheScriptManager" runat="server"></asp:ScriptManager>

 

    <script type="text/javascript">

        Sys.Application.add_init(pageInit);

 

        function pageInit() {

            alert("Entered the Init stage!");

        }

 

        function pageLoad() {

            alert("Page loaded!");

            alert("Hello Microsoft Ajax!");

        }

 

        function pageUnload() {

            alert("Unloading page!");

        }

    </script>

These two "pageLoad" and "pageUnload" methods are called without being attached to any event!
It's a "string based" function search and if the function exists then the MS AJAX framework fires it.

Yep, I Just learned something new.

Have a look at the code inside the framework that fires the "load" event and after that actually looks a for a method called "pageLoad" to lunch.

    function Sys$_Application$raiseLoad() {

        var h = this.get_events().getHandler("load");

        var args = new Sys.ApplicationLoadEventArgs(Array.clone(this._createdComponents), !this._initializing);

        if (h) {

            h(this, args);

        }

 

        if (window.pageLoad) {

            window.pageLoad(this, args);

        }

        this._createdComponents = [];

    }

 

 

Page 87 - Dom abstraction

image

 

Have a look at the documentation for these two classes:

image
image
 image

From http://asp.net/ajax/documentation/live/Samples/Sys.UI.DomEvent/cs/Default.aspx:

image

I really like the "preventDefault()" method and the "stopPropagation()" since they give us the option of fine-grain event firing control.

 

image

from http://www.asp.net/ajax/documentation/live/Samples/Sys.UI.DomElement/cs/Default.aspx:

image

I've worked with both this classes for a while now, they're very useful.

 

 

Page 100 - Browser detection

image

image 

*insert evil laughter*

Opera... 9.1... MS AJAX... :)

 

 

Page 102 - Debugging

 

The authors show this code:

image

image

 

And how it looks like in FireBug:

image

 

I was checking if I could make the Internet Explorer developer toolbar work with this, but it doesn't look like it can.

 

If we want to see the debugging information we have to add this HTML code:
image

I checked inside the MicrosoftAjax.js framework and again, there's a hard-coded ID and tag name.

    function Sys$_Debug$_appendTrace(text) {

        var traceElement = document.getElementById('TraceConsole');

        if (traceElement && (traceElement.tagName.toUpperCase() === 'TEXTAREA')) {

            traceElement.value += text + '\n';

        }

    }

It looks like the MS AJAX framework has a lot of "Magic strings" going around.
Just goes to show you, After two years of working with this framework (Since Atlas December '05 CTP) this is the first time I see this hard-coded values. Imagine if they were Global variables that we could set on "page_init" event, it would have actually been useful.

 

 

Page 165 - Having a LOL moment

 

image

 

 

Page 174 - Changing the Error message at Server-side

 

        protected void Page_Load(object sender, EventArgs e)

        {

            ScriptManager scriptManager = ScriptManager.GetCurrent(this.Page);

            scriptManager.AsyncPostBackError += new EventHandler<AsyncPostBackErrorEventArgs>(OnAsyncPostBackError);

        }

        void OnAsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)

        {

            ScriptManager.GetCurrent(this.Page).AsyncPostBackErrorMessage = "We're sorry, an unexpected error has occurred.";

        }

Nice.
But since client-side errors still occur, you will still have to implement a client-side global page request error handling policy.

From the PageRequestManager.EndRequest event:
http://www.asp.net/AJAX/Documentation/Live/ClientReference/Sys.WebForms/
PageRequestManagerClass/PageRequestManagerEndRequestEvent.aspx

        <script type="text/javascript" language="javascript">

                Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);

 

 

                function EndRequestHandler(sender, args)

                {

                   if (args.get_error() != undefined)

                   {

                       var errorMessage = args.get_error().message;

                       args.set_errorHandled(true);

                       ToggleAlertDiv('visible');

                       $get(messageElem).innerHTML = errorMessage;

                   }

                }

            </script>

image

 

BTW, I really don't like this repeating pattern in the book to keep using the ScriptManager.GetCurrent everywhere.

This should be encapsulated in some base class.

 

Before:

    public partial class WebForm2 : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            ScriptManager scriptManager = ScriptManager.GetCurrent(this.Page);

            scriptManager.AsyncPostBackError += new EventHandler<AsyncPostBackErrorEventArgs>(OnAsyncPostBackError);

        }

        void OnAsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)

        {

            ScriptManager.GetCurrent(this.Page).AsyncPostBackErrorMessage = "We're sorry, an unexpected error has occurred.";

        }

    }

After:

    public abstract class BasePage : Page

    {

        public ScriptManager CurrentScriptManager

        {

            get

            {

                return System.Web.UI.ScriptManager.GetCurrent(this);

            }

        }

    }

 

    public partial class WebForm2 : BasePage

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            CurrentScriptManager.AsyncPostBackError += new EventHandler<AsyncPostBackErrorEventArgs>(OnAsyncPostBackError);

        }

        void OnAsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)

        {

            CurrentScriptManager.AsyncPostBackErrorMessage = "We're sorry, an unexpected error has occurred.";

        }

    }

No point in invoking the same function 5 times in 10 rows and not making sure the call isn't duplicated for nothing.

 

 

Page 185 - Javascript webservices call timeouts

 

// Javascript

image 

image

 

I'd have to disagree on this one.

There's no point in having two different timeouts: one for the first request and another for the other.

Let's say we have two requests: R1 & R2.

Based on that tip, R1 will have a timeout of 2000MS (2seconds) and R2 will have a timeout of 7000MS (7 seconds).
So R1 times out and R2 returns successfully after 3 seconds.
Why not just give R2 7 seconds to start with?

There's no point in having a first request with a short timeout and second one with a longer one.
It just doesn't give you advantage. If anything, Calls will take longer because some calls will fail on the first attempt (R1) and will succeed only on the second (R2).

However, I do agree with the authors that if R1 times out you should try again.
Double Ajax request over the web (and maybe accessing old-data from a local cache) is a MUST in Ajax development today.

 

 

Page 196 - Manual AJAX Requests

image

The Sys.Net.WebRequest Javascript class is a very important part of the Microsoft AJAX communication layer framework.

Let's say we don't like how Webservice calls work right now, or it doesn't give us enough cross-browser compatibility.
We can write our own AJAX communication framework based on Microsoft AJAX.

Let's look at the class members:

image

image 

The minimu to set is the url property, the oncompleted event and start the Request.
But we can also set the httpVerb (POST/GET), request text body and request headers.

The really interesting part though is the "executor" property.
By default we use the Sys.Net.XmlHttpExecutor class which as the name say: executes request using a XmlHttpRequest transport.

We can write our own executor for browsers which aren't supported by Microsoft AJAX.
Or even write an Executor which enables cross-domain requests using the <script src> browser hack.

This level of abstraction inside the Microsoft AJAX frameworks enables us to develop our own AJAX framework based on Microsoft AJAX.

BTW, do the members of the Sys.Net.XmlHttpExecutor class look familiar?

image

image

Yep, these are the properties for the browser XmlHttpRequest.

So, if a Microsoft AJAX request fails, we can access the Executor and see the raw XmlHttpRequest data:

image

 

 

Page 206 - UpdatePanel render mode

image

 

image

Apparently, Updatepanel can be set using the "RenderMode=Inline" to render out a <span> tag.

 

        <asp:UpdatePanel ID="UpdatePanel1" runat="server" RenderMode="Inline">

            <ContentTemplate>

                <%= DateTime.Now.ToLongTimeString() %>               

            </ContentTemplate>

        </asp:UpdatePanel>

Renders to:

            <span id="Span1">

                18:56:12               

            </span>

 

While the default of RenderMode="Block" renders to a <div> tag.

        <div id="Div1">

                18:56:12               

        </div>

 

I wonder why does the normal <asp:Panel> doesn't have that... (an <asp:Label> which renders to a <span> tag doesn't doesn't render out any children Controls so it's not the same as an <asp:Panel> tag)

 

 

Page 270 - The dangers of UpdatePanel

 image

So, this was pretty inspirational.
UpdatePanel is like an arsenal of tools, gotcha.

You know what else the Swiss have? A mandatory 15 months military draft.
After which they all go home with their personal M16.

If we're starting to talk about "the advanced features of an UpdatePanel" wouldn't this be the time to mention that it should be used only sparsely? That at times it's not a Swiss army knife, but a Swiss army M16? And you might be shooting yourself in the leg with it?

 

 

Page 272 - Manually updating UpdatePanels with Javascript

 image

Yes, the "_updateControls" Javascript function can cause UpdatePanels to perform a partial postback.
It CAN, but SHOULD we use it?

There's no clear answer to this question.

On the one hand, It is the fastest way of getting UpdatePanel to refresh from Javascript and it does work.

One the other hand,  It's invoking a private Javascript function that's not meant for public use. So it's basically a hack.
If it's possible, we should avoid calling private javascript functions.

So how do we force an UpdatePanel to refresh from Javascript "in a good way"?
The easiest thing to do would be to add an <asp:button> to the page, make it an AsyncPostBackTrigger and have Javascript trigger it's click event. 
If you're up to something a bit more complex, you can build your own AsyncPostBackTrigger that exposes a Javascript function you'll invoke.

Either way, I strong heartedly recommend working "within" the Microsoft Ajax paradigm and not outside of it by exploiting hacks. 

 

 

Page 287 - Having a LOL moment

image 

 

 

Page 307 - The $create statement equals

image

Is in fact

image

When I saw the first line, I really did think to myself "why don't they use the Javascript new operator?". The authors actually answered this question on the next page. This really goes to show you the authors of this book are great instructors. The good ones teach something the way they understand it. The great ones, teach something the way the student thinks about it.

image

 

 

Page 338 - Generating $create statements from ASP.Net server controls

image 

I like Script descriptors since they enable us to stop emitting "$create" statements from ASP.Net server controls.

However, I don't like the amount of code that's needed for that.

First, have a look at this example of Javascript "$create" statement.
image

This can be generated from an ASP.Net server controls by using the following ScriptDescriptor:

image

OK, That's quite a lot to write and it's mostly loosely typed. It's a good syntax, not great, but it's OK.

My problem is the WHERE this code is written and the amount of code needed to inject it.

    public class AjaxLogin : Login, IScriptControl

    {

 

        protected override void OnPreRender(EventArgs e)

        {

            base.OnPreRender(e);

 

            ScriptManager manager = ScriptManager.GetCurrent(this.Page);

 

            if (manager == null)

                throw new InvalidOperationException("A ScriptManager is required on the page.");

 

            manager.RegisterScriptControl(this);

        }

 

        protected override void Render(HtmlTextWriter writer)

        {

            base.Render(writer);

 

            ScriptManager.GetCurrent(this.Page).RegisterScriptDescriptors(this);

        }

 

        public IEnumerable<ScriptDescriptor> GetScriptDescriptors()

        {

            ScriptControlDescriptor descriptor = new ScriptControlDescriptor("Samples.AjaxLogin", this.ClientID);

            AddControlIDToScript(descriptor, "UserName");

            AddControlIDToScript(descriptor, "Password");

            AddControlIDToScript(descriptor, "RememberMe");

            AddControlIDToScript(descriptor, "LoginButton");

 

            yield return descriptor;

        }

 

        public IEnumerable<ScriptReference> GetScriptReferences()

        {

            yield return new ScriptReference(Page.ClientScript.GetWebResourceUrl(typeof(AjaxLogin),

                "ScriptControls.AjaxLogin.js"));

        }

    }

First, we implement the "IScriptControl" interface.

Second, we need to implement both it's method - Where to get the Controls JS files and how to initialize them.

Third, we have to inject ourselves both in the Control's PreRender & Render methods. That's something I just don't like. I would have encupsulated this logic in a base control class.
But we can't always do that, have a look from which class are we inheriting from. And we can't even sign up for events from the outside since we have to inject directly into the Render method.

I'm just not that sure this ScriptDescriptor syntax actually saves us from one form of repeatable coding to another.

The Extender Syntax does make a lot more sense though:

    [TargetControlType(typeof(TextBox))]

    public class FormattingExtender : ExtenderControl

    {

        public string HoverCssClass

        {

            get { return (string)ViewState["HoverCssClass"]; }

            set { ViewState["HoverCssClass"] = value; }

        }

 

        public string FocusCssClass

        {

            get { return (string)ViewState["FocusCssClass"]; }

            set { ViewState["FocusCssClass"] = value; }

        }

 

        public string ScriptPath

        {

            get { return (string)ViewState["ScriptPath"]; }

            set { ViewState["ScriptPath"] = value; }

        }

 

        protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)

        {

            ScriptBehaviorDescriptor desc = new ScriptBehaviorDescriptor("Samples.FormattingBehavior",

                targetControl.ClientID);

 

            desc.AddProperty("hoverCssClass", this.HoverCssClass);

            desc.AddProperty("focusCssClass", this.FocusCssClass);

 

            yield return desc;

        }

 

        protected override IEnumerable<ScriptReference> GetScriptReferences()

        {

            yield return new ScriptReference(Page.ResolveClientUrl(this.ScriptPath));

        }

    }

No "PreRender" or "Render" injection does make this more readable.

 

In page 357 the authors once more read my mind and show this table of when to use each tactic.

image

Just note that the extender option is missing. We should always consider building a MS Ajax extender control when we want reusability of "ScriptDescriptors" & "ScriptReferences" between different controls.

 

 

Chatper 10 - Microsoft Ajax Control toolkit

I often develop custom Microsoft AJAX Control Toolkit classes and debug the existing one.
So, I'm pretty familiar with the development modal for MS Ajax control toolkit.

This chapter is a must-read for anyone who needs to understand the MS AJAX control toolkit.

This chapter is the single best-source on MS Control toolkit development. I had to learn the internal development modal based on reading thousands of line of code. This chapter gives the reader a very good foothold on what's going on inside the toolkit without spending count-less hours reading tons of code, unclear blogs posts and semi-coherent internal documentation.

The authors really did a good job on this one. (Only if by being the only ones writing on the topic)

 

For instance, just this attributes table that's used inside the Toolkit goes a long way into helping a novice toolkit developer.

image
image 

 

One more thing that can found at this chapter is a basic explaination on the Microsoft Ajax Control toolkit Animation framework. Let me tell you, I had to read a 200KB Javascript file just to learn this stuff. It's a very good improvement there's finally a good reference for this.

image

 

There's a good example of how the animation framework works in the book.
Say we have a Button and a Panel controls on a page.

   <asp:ScriptManager ID="TheScriptManager" runat="server"></asp:ScriptManager>

 

        <div id="thePanel" style="background-color:#aaa">

            <h2>Click the button to dismiss me.</h2>

        </div>

 

    <asp:Button ID="Button1" runat="server" Text="Click Me" OnClientClick="return false" UseSubmitBehavior="false" />

We want that the button will zoom in 200% when the page loads. When the button is clicked we want the Panel to fadeout elegantly.

    <ajaxToolkit:AnimationExtender ID="AnimationExtender1" runat="server"

                           TargetControlID="Button1">

      <Animations>

        <OnLoad>

            <Scale ScaleFactor="2" />

        </OnLoad>

        <OnClick>

            <Sequence>

                <EnableAction Enabled="false" />

                <FadeOut AnimationTarget="thePanel"

                        MinimumOpacity="0"

                        MaximumOpacity="1"

                        />

            </Sequence>

        </OnClick>

      </Animations>

    </ajaxToolkit:AnimationExtender>

Print screen of the page load a 0 seconds:

image

Print screen of the page load after 2/3 seconds: (when the button scales out)

image

And after the button is clicked the headline fades out nicely:

1. image

2. image

This really reminds me of how Silverlight/WPF animations work. Though it's a bit more Effects oriented then animations oriented.

The really cool thing about all of this is that's it's a quickstart into the animation framework AFTER the book has taught you all the server-side and client-side knowledge you need.

Just by showing this table they save the developer reading the Javascript file that declares this classes:

image
image

 

 

Page 481 - Having Javascript Call-stack when debugging

The authors show the following javascript code:

image

And then how it looks like in the VS2005 Javascript call-stack debugger:

image

They recommend using the following pattern to enable Call-stack javascript function naming:

image

Which leads to:

image

I have to disagree with this way of authoring Javascript files for two reasons:
1. code duplication "person.set_name = person$set$name" is the most obvious bit of text duplication. Overtime we rename something we have to rename is twice. I'm willing to not have Javascript call-stack function names just because of that.
2. The specific syntax the authors use doesn't enable in-class javascript intellisense when working in VS2008. Since the methods are only entered into the class after all methods are written using the "this." operator would have no meaning.

 

 

My sum up

Good book, 4 stars.
Buy it if you can spend 2 days learning level 400 of the Microsoft Ajax framework.

 

Why only 4 stars?
1. The authors tend to talk about trivial topics when there're bigger issues to cover. A good example of when they actually "talked about" each line of code inside the UpdatePanel update process. Nice, but completely useless. If someone needs to know that, he can just read the code himself.
Additionally, There're 2.5 chapters in the book dedicated to the old May 07 AJAX futures release. Mainly about Xml-script and Drag&Drop support. While each of them is "a technology" I'm not sure they're more then a passing note in the history of Microsoft Ajax.

2.  There's something missing when reading this book. It's never quite 100% clear why are we doing what we're doing. It's clear WHAT we're doing, but not WHY. What's the end-goal of this Javascript syntax? of this Ajax enables control?
There's a "big picture to little picture" zoom-in missing.
There's a lot of tech stuff in this book, but how it all comes together is sorely missing.

3. I personally have to disagree with the way the book is structured. The chapters aren't arranged to what I'd consider a logical order. We're jumping back & forth from Javascript to C# and IMHO there're better ways of showing some of the concepts in this book. There's also a lot of confusion in the first chapters about what are the authors trying to show. This is just a passing comment since this once is VERY subjective.

 

Why 4 stars? This book took the seemingly simple task upon himself to teach "Microsoft Ajax".
Which is what? 200KB Javascript files and 700KB .Net DLL file. Not much.
But teaching Microsoft Ajax is really teaching how the Server-side is incorporated into the Client-side and how we make Client-side programming more like Server-side programming.

That's a very big mission - Teaching C# developers how to develop Javascript Object-oriented AJAX code.
An it's an objective this book does very very well. Even if you don't have any Javascript background except the occasion JS function, it even teaches you the basics of Javascript OO.

The good - This book will school you to a good level in Microsoft Ajax, Microsoft Ajax Control toolkit and General Javascript development. If you'll read it you'll be in a great shape. Great, but you won't end up a guru.
The bad - You need patience for this book and that means time. For the amount of time a normal (read: "Non-justin") reader needs for this book, I would expect a bit more. So lower your executions a bit when approaching this book.

 

 

 

Question from Tapuz .Net forum: Speeding up builds with many projects

שאלה:

יש לי Solution שמכיל בתוכו 15 projects. חלק גדול מהזמן אני לא צריך לקמפל מחדש 4 פרוייקטים מתוך ה solution.
האם ישנה דרך לבטל קימפול חלק מהפרוייקטים כשאני עושה rebuild ל solution?

 

תשובה:

שאלה מצויינת והפתרון מאוד תלוי בארכיטקטורת הפרוייקט שלך.

אם הארכיטקטורה שלך היא "עלים של Top tier" אז תוכל להריץ רק את המסלול הרלוונטי לך.
כלומר, אם ה-Solution שלך חושף מספר "שכבות עליונות" (כגון GUI של Winforms, בנוסף Webservice ובנוסף אתר אינטרנט) שביניהם אין תלוית Build יש אפשרות רק להריץ את החלק הרלוונטי מה-Solution (רק האתר, או רק ה-WS או רק האפליקציה החלונאית).
בשביל זה, תוכל ללחוץ כפתור ימני ב-Solution Explorer על הפרוייקט העליון ביותר שאתה רוצה להריץ, ותבחר Debug --> Start new instance. וזה ידאג רק לבנות את הפרוייקטים הרלוונטים שהשתנו להרצה הזו.

image

 

אפשרות לבצע Extension לאפשרות הקודמת היא גם לכתוב Macro קטן שיריץ Start New Instance של הפרוייקט לפי השם שלו, ולחבר את זה לקיצור מקלדת כלשהו. (כדי למנוע את העבודה המיותרת עם העכבר)

אם הארכיטקטורה שלך לא מאפשרת את זה, זה פחות או יותר כאן נגמרות האפשרויות.
יש הרבה מאוד טריקים זולים ל-Build Optimization, אבל רובם לא יקזזו יותר מ-10% מזמן ה-Build וביחד אולי במצב אופטימלי תגיע לשיפור של 25%. זניח יחסית.

האפשרות הכי טובה שלך והיחידה שראיתי שאי-פעם פעלה היא פשוט לשדרג חומרה.
הצוואר בקבוק הגדול בפרוייקטים בסדרי גודל בינוני-גדול (לא ענקיים) הוא ההארד-דיסק וספציפית מהירות הכתיבה והקריאה.
עצם העובדה שהמחשב נאלץ לקרוא את כל הקבצי פרוייקט ואז לכתוב מחדש קבצים מקומפלים - הכמות עצמה היא הבעייתית כאן.
מבחינת כמות ה-KB שנאלצים לקרוא ולכתוב, יש כאן צוואר בקבוק ענק.

הנתון שנהוג להביט עליו כאן הוא RPM (כמות סיבובים) של ההארד-דיסק. מעט מאוד זה 4200, מעט זה 5400 וסביר זה 7200.
הכי הרבה שיש בלאפטופ הוא 7,200RPM.
במחשבי PC אפשר לשים גם הארד-דיסק של 10,000RPM.

אפשרות נוספת היא לקנות RAM Disk קטן (של עד 4\8 גיג'ה שזה יחסית זול) ולאחסן שם רק קבצי פרוייקטים.
המהירות קריאה וכתיבה מההארד-דיסקים האלו הן מטורפות ובמקום "להרחיב" את הצוואר בקבוק (שזה מה שמקבלים משדרוג RPM) כאן הוא נעלם לחלוטין.

בפרוייקטים בסדר גודל ענק יש עוד המון צווארי בקבוק.
כאן כבר הקומפיילר יכול להתחיל לטחון את ה-CPU, כמות המידע יכולה לטחון את ה-RAM וכך הלאה.
הפתרון הנפוץ כאן הוא לשים מכונה חזקה שעושה Contentious Integration ושבונה את כל הפרוייקט וככה אתה מקבל פרוייקט שתוכל לבצע Build באמצעות Start New Instance רק את לפרוייקטים שרלוונטים לך.

 

קישור: http://www.tapuz.co.il/tapuzforum/main/Viewmsg.asp?forum=831&msgid=110841667

שיחות שעושות טוב על הלב

  כרגע קיבלתי שיחה בפלאפון ממספר שלא זהיתי ורציתי לחלוק.

"שלום, קוראים לי כך וכך ורק התקשרתי להגיד תודה על כל המאמרים הנהדרים שכתבת ותכתוב. תודה רבה מכל הלב, עלה והצלח."

 

אז תודה רבה גם לך שאמרת את זה ותודה לכולם שאתם קוראים את מה שאני כותב.

"Prefactoring", By Ken Pugh, O'rielly (2005)

I'm reading "Prefactoring", By Ken Pugh (O'rielly 2005) and I'm jotting down some comments in this blog post about nice stuff in the book. This post is basically meant so I could read it later and remember this stuff, but It's OK if you read it too :)

image

 

 

 

(Page 1 - Overview)


image

Nice concept, but a bit obvious. It's always better thinking of stuff up-front when you've got more experience.

 

 

Page 22-23 - Agile Development

image

image

I really like this metaphor. It stated the most important thing never told about agile: You need to have EXPRIENCE to do it.
It's not an academic concept. Agile is a hardcore real-world concept by people who knows what they're doing.

As the ALT.Net guys say: Running with scissors if for consenting adults.

image

 

 

 

Page 29 - Reuse existing business platforms

image

image

I don't like this concept not one bit.
You, as a software developer, should always reuse the FRAMEWORK efforts of others. But actually taking a real-world existing application and customizing it to your needs is often more difficult then just building from scratch.

Sure, If there're more then 80% similarities then it's a possibility, but otherwise it's a waste of the customer's money and our time.

 

 

 

Page 38 - Abstracting primitive datatypes

image

 

image

Becomes

image

image

This is a really interesting concept.
It's point-less in .Net though as in stand of a "string" type everywhere you'll just have "CommonString" everywhere. And it'll take some work to declare these new primitive types everywhere (with Using alias statements) and "inheriting" the existing string. 

Though I agree with the most important thing asked here - "Is that attribute really just a string?".
It's a good question to think about while designing classes.

 

 

 

Page 49 - Consistency

image

 

 

 

Page 50 - Prefactoring in it's best

image

 

--

 

Page 54 - Error Handling

 

image 

This is especially important in the .Net world where swallowing exceptions is very common. No exception should every get un-logged!

image

 

Everywhere - the "a_something" notation

image 

This just isn't readable to me.

"a phone dial a phone number" sounds like something someone with bad grammar would say.

 

    Phone HomePhone = new Phone("972","03","9504364");

    HomePhone.Dial(JoesPhoneNumber);

This makes much more sense, and is far more readable.

A good name is important.

 

 

Page 72 - Reports as the corner stone of Analysis and design

 

image 

Now, This is new.

I've never heard about this concept before. When I think back on all my customer meeting's it always "how do you want this screen to look like?" or "what data are we getting and where are we showing back?", but never "What's the final end data the system should output?".
This is a really interesting approach, and probably a very good one as it's very customer-oriented and very domain-problem driven.

I'll have to check it out soon when I'm with a customer implementing a new segment of a system.
"What reports do you want to get from this?" is a great first question...

 

 

Off-book: I love this author and this book

 

This is an awesome book, I really like the content, the sample are only OK, but the way the book is written - divine.
I'll have this entire book read in 3 hours. It's amazing what a good tech book author can do.

The author writes everything 3 times: In headlines, in text & graphs and at big "sum up" boxes.
That's a great way to write a book as reiteration over concepts makes them sink in better with the reader.

 

 

Page 86 - Strongly typed

 

image

Saying strongly-typed classes are better then loosely-bound data to a .Net developer is like saying to a pig that flying could be hazardous. We know that, but it still doesn't stop us from the occasional "jumping of the roof in a superman custom".

 

 

 

Page 88 - Inheritance in up front designs

 

image 

I'd like to expend on this issue.
My approach to inheritance is that - Inheritance is a tool for developers to be used to avoid code duplication.
Other people's approach to inheritance - Use it when you have a common problem-domain object.

I like my approach better because it let's inheritance evolve based on the actual development/coding requirements and not just a fancy of the architect.

 

--

 

Page 99 - Where to write methods?

image

I already know this concept, but I like the way it's put.

Let's say you've got the following class:

    public class Person

    {

        public Person(string _firstName, string _lastName)

        {

            this._firstName = _firstName;

            this._lastName = _lastName;

        }

 

        private string _firstName;

        public string FirstName

        {

            get

            {

                return _firstName;

            }

            set

            {

                _firstName = value;

            }

        }

 

        private string _lastName;

        public string LastName

        {

            get

            {

                return _lastName;

            }

            set

            {

                _lastName = value;

            }

        }

    }

And we need to print the person's full name:

        static void Main(string[] args)

        {

            Person myPerson = new Person("Justin-Josef", "Angel");

            Console.WriteLine("Full name: " + myPerson.FirstName + " " + myPerson.LastName);

        }

Since all the data for the full name is found inside the Person class, then it should be the one to handle this piece of business logic.

    public class Person

    {

       ...

 

        public string FullName

        {

            get

            {

                return FirstName + " " + LastName;

            }

        }

    }

 

        static void Main(string[] args)

        {

            Person myPerson = new Person("Justin-Josef", "Angel");

            Console.WriteLine("Full name: " + myPerson.FullName);

        }

 

image 
image

 

 

Page 106 - Responsibility

image 

Every developer should have this tattooed on the inside of his eyelids. I'll let you go first!

 

 

 

Page 107 - Thought provoking...

 

image 

That's a 100% true. How many times do we call "String.Format"? or our own helper methods?
Building one small method the right way, makes it applicable to our entire application as part of the framework.

And we also get the added bonus of having centralized task handling.

 

 

 

 

Page 108


image

 

image

This is interesting since the author uses the excuse of "let's separate concerns" and my excuse for this would have been "duplicating code" and "readability".

Here's a bit of code I wrote just this morning:

        private static void IfPropertyIsDataMemberThenAddJScriptField(StringBuilder sb, Type curTypeToDeclareDataMemberAsJScriptField, PropertyInfo curPropInfoToCheckIfDataMemberAndAddToJscript)

        {

            if (IsDataMember(curPropInfoToCheckIfDataMemberAndAddToJscript))

                sb.AppendLine(BuildJscriptFieldStringFor(curTypeToDeclareDataMemberAsJScriptField, curPropInfoToCheckIfDataMemberAndAddToJscript));

        }

The reason that there're seperation of concerns in this little tidbit of code isn't because I'm an Object-oriented advocate, it's because I needed to use the "IsDataMember" logic in two different places and I had to use the "BuildJscriptFieldString" in multiple places.

Picking it up where the author left it - A "policy" would probably repeat itself and so will the "implementation" of the policy.

 

 

Page 107 - Well, I just did that...

image 

If you read the code sample from the last segment, you've seen I'm a big fan of "big names" notation.

When it's time to name something, I just ask "What is this? What is doing here? What am I going to do with this?".

 

 

Page 116 - Random comment

I was looking over this little line of code:

image 

Is this really better then saying the following?
Customer renter = CustomerCollection.FindBy(1);

 

When we write up the function it looks like this:

    public class CustomerCollection

    {

        public Customer FindByCustomerId(int CustomerId)

        {

            //

        }

    }

Aren't we really duplicating the "CustomerId" text around?

What if we change the meaning of the parameter from CustomerId to some composite primary key?

    public class CustomerCollection

    {

        public Customer FindByCustomerKey(CustomerPrimaryKey CustomerKey)

        {

            //

        }

    }

We have to change all the places in bold.

Isn't this really shot-gun surgery? Changing one place forces us to change multiple places...

 

The alternative syntax is:

        public Customer FindBy(int CustomerId)

        {

            //

        }

This is slightly better in terms of code duplication, but intellisense for this class is far worse then if we had the full method name.

When looking over the basic intellisense for this class, which method is clearer to you that gets a CustomerId and returns a Customer instance?

image 

 

 

Page 153 - Customers from hell

 

image

I said it once and I'll say it again - some people should not be allowed to talk with developers.

You can tell how's this going to end...

What would you do in this case?

I would just tell the customer "I understand your concern. We will implement this feature when you get from vacation. Have a good one!". He would say "But we need this!", And I would say "You need *something*. unless you're going to tell me what, no even the best developer on the planet can implement it. We will await your safe return." 

I've had this conversation on many occasions.

 

 

Page 160 - Splitting interfaces?

image 

Hmmm... There's an NDepend query just waiting to happen there...
"List all Interfaces/classes based on how many methods aren't used by all the classes which use the interface/class". So a class/interface with the most non-common methods to be used by all the interface/class consumers will show up first.

 

 

Page 165 - What now?

image

image

What now? *puzzled look*
A what not found exception?

Earlier in the book, the author talks about three kinds of errors in an application:

image
image

Numbers (1) and (2) deal with "business rules have been violated" and "bussiness rule have not dealt with a scenario".
Both of them, should never ever cause an exception to be raised.

A zip code not being found isn't an "exception worthy" error, it's a business rule that's being violated.
In stand of throwing an exception here, the developer should first check if the business rule is valid in the "Business logic layer" and then have the GUI do something.
Not throw an exception!

Exceptions are meant for exceptional conditions.
The server is on fire, the DB has been hacked, a code-monkey has eaten through the network cables. Not "whoops, invalid user input".

 

 

Page 171 - LOL

image

In accordance with this sentence, I made the following diagram that shows how easy it is to really debug an application:

image 

My conclusion is a simple one - All applications should contain 0 lines of code.

 

 

Page 177 - Another LOL moment

image

 

 

Page 193 - Magic numbers

 

image

This is a very important concept in Refactoring - don't let "magic numbers" into your application.

Let's have a look at this class:

image

We've got all sorts of well-known numbers listed here.

Each day has 24 hours with 60 minutes each hour and each minute has 60 second each.
Well, Do 365 days have 365 * 24 * 60 * 60 seconds? Yep.
Do 4 years have 4 * (365 * 24 * 60 * 60) seconds? Not exactly, since each 4 years there's a leap year with an additional day (Feb 29th).

 

Same goes for the number of days in a week (7 days each week), the value of Pi and the gravitional pull of the earth (9.81).

All these numbers stand for "magic numbers" which might work for us when we write the code. But not necessarily when the system is up and running per the user's specification. So we should make sure not "to spread" these numbers around.

image 

The author of the books also mentions using external data sources which are maintainable to the customer, like XML:

image
image 

 

 

Page 244 - Epilogue

image

 

 

My sum up.

 

It's a good book. Buy it if you've got the time to read it.
Basically, It's 250 pages of real-world problem-solution approach that covers the highlights of code Refactoring.

Refactoring in the end is all about "Writing better code", this book just takes the concept to the extreme.
It gives non-textbook situations and shows you how to think about creating the best possible design as early as needed.

As one point, The author has shown a conversation between a customer and a developer about "Classes". That's intense even by my standers.

Bottom line: The book is well-written, has a very fluid & professional tech writing style, contains good examples and talk about real-world concepts. It's a defendant 4 star book IMHO.

It's not a 5 star book since It's just not long enough and at sometimes the samples are over-tedious and can become unclear.

 

 

Question from Tapuz .Net forums: Installing ASP.Net 2.0 Providers to a Sql Database with aspnet_regsql

שאלה:

איך אפשר לגרום ל-ASP.Net 2.0 עם ה-Providerים השונים שלו לרוץבשביל מספר אתרים שיש לי רק Instance אחד ומספר מסדי נתונים?

 

תשובה:

כברירת מחדל ה-ASP.Net Providers יוצרים לעצמם מסד נתונים בשם aspnetdb.mdf ב-App_data של האתר, אבל זה לא האפשרות היחידה.

ניתן להריץ את ה-aspnet_regsql.exe שמגיע עם דוט נט 2.0 והוא ידאג להתקין את הטבלאות הרלוונטיות איפה שתגיד לו.
כברירת מחדל הוא יושב ב-

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regsql.exe

 

image

יש שתי אפשרויות להרצת הכלי: עם פרמטרים או בלי פרמטרים.

שמריצים את כלי עם פרמטרים נריץ אותו ה-CMD (דרך Start --> Run -- > Cmd ונגיע לתיקיית הפריימוורק או דרך ה-Visual Studio 2005 Command prompt). יש הרבה מאוד אפשרויות להרצה דרך ה-CMD.
פירוט מלא אפשר לראות ב-ASP.NET SQL Server Registration Tool (Aspnet_regsql.exe).

למשל אפשר לפרט את פרטי ההתחברות למסד נתונים (מחרוזת חיבור, שם מחשב, שם מסד, שם משתמש וסיסמה ועוד רבים).

image

image

כמו כן, גם אפשר לפרט איזה Providerים נרצה בדיוק שיותקנו:

image

אם כבר מדברים על הכלי הזה, חשוב להזכיר שבאמצעותו גם אפשר להתקין את הסקריפטים של Sql Caching Dependency לסיקוול 2005 או אם נרצה להעביר את ה-Session שלנו שישמור מידע במסד הנתונים סיקוול.

למשל הנה הפקודה להתקנת Membership Tables ו-Role Manager Tables בסיקוול על המכונה הלוקאלית במסד בשם Northwind עם חיבור למסד באמצעות המשתמש המחובר כרגע ב-Windows.

aspnet_regsql.exe  -E -S localhost -D Northwind -A rm

ה-E מייצג אימות באמצעות המשתמש המחובר כרגע, ה-S מייצג את השרת, ה-D מייצג את המסד נתונים וה-A אומר להתקין Role Provider ו-Membership.

ניתן גם להריץ את הכלי מתוך Windows בלי פרמטרים ואז יפתח חלון גרפי שמאפשר לעשות את ההתקנה דרכו. (פשוט להפעיל את הקובץ דרך Explorer)

image

image

image

image

חשוב לשים לב שבכלי הגרפי מותקנים כל ה-Providerים הסטנדרטיים ואין אפשרות לבחור מה יותקן.

כמו כן, אם אין באפשרותך להריץ בעצמך את הכלים על האתר המרוחק, באותו תיקייה בדיוק ישנם סקריפטי ה-SQL המרוצים בסופו של דבר.
image

image

 

אם כבר אנחנו בתיקיית הפריימוורק ומפטפטים על Providerים, נחזור להתחלה ונזכר מה הבעיה.
כברירת מחדל ASP.Net 2.0 מתקין את ה-Providerים בתיקיית App_data במסד aspnet_db.mdf.
ניכנס לתקיית config בתיקיית הפריימוורק ונפתח את הקובץ machine.config.

    <connectionStrings>

        <add name="LocalSqlServer" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient"/>

    </connectionStrings>

נוכל לראות שברירת מחדל יש ConnectionString בשם LocalSqlServer שמוסיף קובץ ב-aspnetdb.mdf בתיקיית ה-App_code (וזה נוצר אם הוא לא קיים).

נביט למשל על ה-Membership Provider:

        <membership>

            <providers>

                <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="LocalSqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="1" passwordAttemptWindow="10" passwordStrengthRegularExpression=""/>

            </providers>

        </membership>

אפשר לראות שכברירת מחדל ה-Membership Provider משתמש במחרוזת חיבור הזו של aspnetdb.mdf.

וזאת הסיבה להגדרות ברירת מחדל שיש לנו שאנחנו עובדים ב-ASP.Net 2.0 לאיפה יוגדרו ה-Providerים אם לא הגדרנו בעצמנו.

 

קישור: http://www.tapuz.co.il/tapuzforum/main/Viewmsg.asp?forum=831&msgid=109668386

Justin's new Gun + Videos of Justin shooting

Everyone who reads my blog knows I'm not a big fan of personal posts.
It's my firm belief that developers who read this blog want quality technical content. 
However, This is slightly relevant to .Net and very cool (IMHO).

 

Presenting - my new gun!

image

And a zoom up on the barrel would show the inscribed text better:

 image 

Yep, I've inscribed "Justin time" on the side of my new gun :)

The gun is a BUL M5 IPSC competition.
image

Here are a couple videos of me practicing with my new gun: