|
|
These blog entries are written by industry experts and leaders. We consider this content to be a good read for any software developer or web technologist.
March 2009 - Posts
-
Model is one of those overloaded words in software. Just saying the word model can produce a wide range of expectations depending on the context of the conversation. There are software process models, business process models, maturity models, domain models, security models, life cycle models – the list goes on an on. Nerds love abstractions, so it’s not surprising that we have so many models to choose from. Let’s talk about a specific model – the model in model-view-controller. What is it? How do you build one? These are the types of questions a developer will ask when working with the ASP.NET MVC framework. As Simone Tokumine points out in his post “.NET MVC vs Ruby on Rails”, there isn’t any direct and specific guidance from Microsoft: .NET MVC is actually .NET VC. It is an attempt to replicate the Actionpack components of Rails. There is nothing included aside from a folder labeled “Models” to help you with your persistence later and domain modeling. The scenario isn’t unique to the MVC framework. Microsoft has a long history of leaving the model of an application open to interpretation, and this stance is both a blessing and a curse. A blessing because we can build models to meet the distinctive needs of every application imaginable, and we can use a variety of tools, frameworks, patterns, and methodologies to build those models. However, the curse is that many of us never look outside of the System.Data namespace. Populated DataSets and data readers are the models in many applications, even when they aren’t the best fit. Enter the Entity One reason that DataSets dominate .NET development is because they are featured in the majority of samples and documentation, particularly for ASP.NET Web Forms. In contrast, ASP.NET MVC samples typically feature business objects as models. Even the new MSDN documentation says: Model objects are the parts of the application that implement the domain logic, also known as business logic. It’s not surprising then, to see many people using domain objects, business objects, and entities produced by LINQ to SQL or the Entity Framework as model objects.
Do business objects and entities really make the best models?
This is the question I'd like to explore by sharing my opinion and gathering feedback over the course of two more blog posts... 
|
-
The ASP.NET Connection show in Orlando was a fantastic event. Thanks to everyone who came to a session. Here are the slides and demos for everyone who asked for them. What ASP.NET Developers Should Know About JavaScript Download. In the last half of this session we re-factored a dashboard type application with an eye towards using properly abstracted JavaScript code. The dashboard page was loosely based on the code from my Extreme ASP.NET column in the March MSDN Magazine: Charting with ASP.NET and LINQ. Part of the refactoring process was removing all signs of JavaScript from the .aspx file to achieve the separation of behavior and markup that defines “unobtrusive JavaScript”. If you give JavaScript the focus it deserves, it can love you back. Other links: Advanced LINQ Queries and Optimizations Download. LINQ is inherently more about productivity and expressiveness than performance. We talked about how to avoid unnecessary performance penalties with LINQ, some non-obvious optimizations, and the first optimization you should make - optimizing for readability. Other links: Databinding With Silverlight Download. A little Blend, a little XAML, a little Visual Studio. Links: 
|
-
My Toolbox column in the April 2009 issue of MSDN Magazine is available online. The March issue of MSDN Magazine has a focus on the Web and my reviews in Toolbox follow suit and include:
- The Microsoft Chart Controls - Did you know that Microsoft has released a free, robust set of charting controls for both WinForms and ASP.NET applications developed using the .NET Framework version 3.5? With this control suite you can add pie charts, line charts, bar graphs, and a host of other chart types to your .NET applications.
- Snippet Designer - Visual Studio 2005 introduced code snippets, which are task-oriented blocks of code that can include replaceable regions. In a nutshell, a code snippet can be used to inject common code blocks, such as the stock code for sending an e-mail message, or the skeleton of a try/catch block. Unfortunately, Visual Studio does not include much in the way of tool support for building these code snippets. Snippet Designer, an open-source project hosted on CodePlex.com, provides a straightforward user interface that integrates with the Visual Studio IDE and makes creating and editing snippets a much more intuitive and pleasant experience.
- Blogs of Note - Sara Ford: Sara Ford is a Microsoft employee who, over the years, published 382 tips on getting the most out of Visual Studio. Her blog serves as a great resource of Visual Studio tricks and tips. Spend an afternoon pouring through her old blog entries, and I guarantee you that you'll learn a few new things about Visual Studio.
The Bookshelf section reviewed two books: More Effective C#, by Bill Wagner, and Refactoring SQL Applications by Stephane Faroult and Pascal L'Hermite. An excerpt of Effective C# follows:
More Effective C# assumes the reader is already familiar with C# and language features like generics, LINQ, multithreading, and so on. You won't find any discussions on what generics are or the syntax for lambda expressions. Instead, the book states a specific guideline, such as "Distinguish between IEnumerable and IQueryable data sources," and then provides a deep and detailed discussion on the why of the guideline with illuminating prose and helpful code snippets. And each guideline stands on its own and can be read and digested without having first read other guidelines, meaning that you can jump around to what guidelines interest you the most or are the most relevant for your current projects. ... More Effective C# is a must-read for experienced C# developers who are already familiar with C# language features such as generics, extension methods, lambda expressions, anonymous types, and LINQ, but who want guidance on how best to use these features.
Enjoy! - http://msdn.microsoft.com/en-us/magazine/dd569763.aspx
As always, if you have any suggestions for products, blogs, or books to review for the Toolbox column, please send them to toolsmm@microsoft.com.
|
-
JavaScript has made some improvements in its “state of the art” over the last several years, despite your best attempts to ignore the language. Yes, you. The language hasn’t changed, but the tools, practices, runtimes, and general body of knowledge have all grown and matured. Yes, it’s still a dynamic language, and we all know that you think dynamic languages are more dangerous than a loaded gun, but you can’t ignore the language any longer. JavaScript is everywhere. Why, just the other day I turned on “Who Wants To Be A Millionaire?”, and what did I see? Here are some signs that you might be behind the times. 1. If you still mix JavaScript and markup … <head>
<script type="text/javascript">
function doStuff() {
alert("boo");
}
</script>
</head>
<html>
<body onload="BLOCKED SCRIPTdoStuff();">
...
</body>
</html>
… you should read up about unobtrusive JavaScript. In addition to the performance benefits of keeping script in a .js file that a browser can cache, you also separate your presentation concerns from script behavior and allow yourself to focus on writing better script.
2. If you still use document.getElementById and assign functions to onclick … var header = document.getElementById("header");
header.onclick = headerClick;
… then you really need to start using one or more JavaScript libraries. There are many great libraries available – just look around. They help isolate you from variations in the browser environments, increase your productivity, and allow you to write more maintainable code.
Other obsolete patterns:
3. Using document.all or document.write
4. Using global variables and global functions
5. Rolling your own browser detection code
6. Debugging with alert messages
Once you learn modern JavaScript idioms and tools, you’ll never look back at these old anti-patterns. 
|
-
A friend recently had to replace some electrical outlets in her house because they stopped functioning. There was so much corrosion built up between the aluminum wiring and the outlet contacts that the outlets quit working (which is much better than the alternative - catching on fire). Did you say aluminum wiring? During the classic rock era of the 1960s and 70s, aluminum wiring became a popular replacement for copper wiring in the USA. Due to a copper shortage, aluminum was cheaper than copper and allowed electrical contractors to lower construction costs. I was quite shocked to hear about aluminum wiring in her home, I’ve only seen copper myself, but according to the CPSC there were ~2 million homes with aluminum wiring by 1974. Over the years, a number of problems with aluminum began to surface. Aluminum wiring is more brittle than copper, and much more likely to oxidize, corrode, and overheat. Aluminum wiring just isn’t as safe as copper wiring* and is now banned in the electrical codes of many jurisdictions. Aluminum wiring lives on in many houses, however, because it’s expensive to swap out a piece of embedded infrastructure like wiring. Hindsight is 20/20 Engineering is always about tradeoffs. But many times we start using a technology, tool, or methodology because it appears to save us time or money. It’s only later that we can see the problems clearly. My question for you is: What do you think is the “aluminum wiring” inside today’s software? What have we adopted recently that we’ll look back on in 3 years and say “ouch”. Here are a few candidates to start the conversation (based on an informal poll of random developers I accosted): - Mock objects
- Fluent APIs
- Declarative programming
- Anything that isn’t a UI but requires a visual designer to create or edit
* If you are replacing outlets with aluminum wiring coming in, please, please, please be sure to use an outlet made for aluminum. They are more expensive, and the young clerk at the store will try to sell you an outlet for copper wire, which can be a fire hazard. 
|
-
Our esteemed House of Representatives passed a resolution earlier this week, designating today - March 14th - National Pi Day. This is an American-centric 'holiday,' as we colloquially denote our dates in MM/DD format, hence March 14th is 3.14, the first three digits of Pi. Most other countries start with the least significant date part and work their way to the most significant - DD/MM/YY - which would mean the International Pi Day should fall on the 3rd day of the 14th month (hrm) or the 31st day of the 4th month, i.e., April 31st (hrm, again). Of course, God-fearing computer scientists denote dates from the most significant to the least, always using four digits for the year - YYYY/MM/DD - which would place Computer Scientist Pi Day on May 9th, 3141 if you were being flexible on parsing the month and day and allowing either one or two characters.
As we all learned in elementary school, Pi is the ratio between the area of a circle and its radius, squared, or the ratio between the circle's circumference and its diameter, and approximates 3.14159. One of the shortcomings of mathematical education in our schools is that math is initially introduced in a way that suggests that its rules and results are handed down by some oracle. Furthermore, children are taught that learning math involves mindless memorization. I think this turns a lot of kids against math; they end up thinking that it's some stuffy, boring pursuit that is of little interest. But there are interesting ways to present math, and ways in which the child discovers first hand why certain things are the way they are. And explaining why Pi approximates 3.14159 is a great example of a more involved and interactive form of math education.
My daughter is 6 months old, but one day I plan on sharing the following math discovery with her. I don't know when this would be age appropriate. The first part - computing Pi as a ratio of the circumference and diameter - only requires understanding of division, and I imagine it could be introduced around age seven or eight. The second 'experiment' involves areas and necessitates understanding exponentiation and square roots, and would probably have to wait until age 10, or so.
Start by drawing some circles (with a compass) and talking about the components of the circle - the circumference, the area, the radius, the diameter. It's pretty clear that there's some relationship between these components. A bigger radius means a larger area and a longer circumference. Next, get out some string and measure some of the circles' circumferences. It becomes clear that a circle with twice the radius has twice the circumference. But given just the radius, can one arrive at the circumference? There is some missing number that we need to arrive at this, and this can be approximated empirically: using the string, measure out the circumference for a circle and then hold the string up to a ruler. Divide this measurement by the diameter and you should arrive at a value that approximates Pi. Using this newly discovered number, tackle the problem the other way around - starting from a known diameter, what should the circumference be? Compute it, then measure it with the string and see how the values align.
Can we devise some ratio between the radius and the area? When in doubt, get out the graph paper! Start by deciding on a radius and then determine what points on the graph paper are bounded by a circle with said radius. I'm not sure the best way to explain this to the pupil in a way that isn't along the lines of, "This is the way it is," but the square at coordinates (x,y) on the graph paper is bounded by the circle if the square root of x2 + y2 is less than or equal to the radius. Using that knowledge, visit each square on the graph paper and apply the formula. If the square root is indeed less than x2 + y2 then shade in the square, otherwise leave it empty. After enumerating the squares, count up the shaded ones and divide that total by the radius squared. And, lo!, the result is eerily similar to the number we were getting when dividing the circumference by the diameter. Repeat the graph paper process a couple times with larger radiuses. As the radius gets larger, the area is computed more accurately as the edges of the circle are less jagged. Consequently, the ratio of the area and the radius gets more and more refined and close to the true value of Pi.
And if my daughter enjoys computers and likes spending time giving them instructions (fingers crossed), the final part of the lesson would be to have the computer do the grunt work for us. Why spend all afternoon shading in graph paper squares when a computer can shade in millions of squares for us in seconds? Here's a snippet of C# that approximates Pi.
const int r = 10;
int A = 0;
for (int x = -r; x < r; x++)
for (int y = -r; y < r; y++)
if (Math.Sqrt(x * x + y * y) <= r)
A++;
Console.WriteLine("Enjoy a slice of {0}", Convert.ToDouble(A) / Convert.ToDouble(r * r));
You can adjust the value of r to see how the approximation becomes more refined. For example, when r = 10 the approximation is 3.15. With r = 100 it's 3.1415. Of course, too large of a radius results in an overflow, which is a great segue into a discussion on how computers represent numbers!
|
-
I oftentimes have a student or client remark, “I love how technology X does Y! However, I don't like X because it does Z.”
I don't know what else to say other than, “Ok,” or “I concur,” because after all, that's what computer science, and perhaps all of engineering, is all about - tradeoffs. There is no silver bullet. There is no panacea. Solutions are created to solve a specific problem, but the solution has shortcomings or deficits in other areas. That's life as a software developer.
If there were a silver bullet, if some technology existed that solved all the problems with no shortcomings elsewhere, we'd all be out of a job.
|
-
When my jQuery code doesn’t work, it usually means I’ve done something terribly wrong with my selectors. Thus, my first rule of debugging code that uses jQuery: Make sure the selector is actually selecting what you want selected. I can liberally apply rule number one before fiddling with event handlers and method calls that come later, because it’s easy to do and saves me time. Step 1: Navigate to the page with a problem and open FireBug.* Step 2: Type your opening selector in the command bar of the console. Step 3: Verify the object length is > 0 If you need to take a look at the objects you’ve selected, then a little console logging inside FireBug goes a long way. $("div > a").each(function() { console.log($(this).text()) })
I hope this tip saves you as much time as it has saved me!
* Technically, any JavaScript execution environment will work, like the Visual Studio immediate window, but the FireBug / Firefox combination is simple and works every time. Another one I like is the jsenv bookmarklet from squarefree.com. 
|
-
Spark is a view engine for the ASP.NET MVC and Castle Monorail frameworks. I’ve been wanting to try this creation by Louis DeJardin for some time, but ScottW pushed me over the edge with “If you are using ASP.Net MVC, you owe yourself to spend some time with Spark”. The Spark documentation makes it easy to get started, and the source code and examples are even more valuable. There are quiet a few tutorials for Spark floating around, but I wanted to call out what appears to be a well hidden secret in the samples: the client rendering of views. In short, the client rendering produces JavaScript you can invoke on the client to render the same HTML you see when rendering a server-side partial view. This means you can happily fetch JSON from the server and use it to produce HTML without duplicating the server-side template logic on the client. As an example,let’s say you have the following partial view to render the employees inside a department: <div id="employees">
<table>
<tr>
<td>ID</td>
<td>Name</td>
</tr>
<viewdata department="Models.Department"/>
<tr each="var employee in department.Employees">
<td align="right">
${employee.ID}
</td>
<td>${employee.Name}</td>
</tr>
</table>
</div>
Notice how in Spark you can weave C# into the markup without breaking the flow of the HTML.
Next, let’s say you wanted the ability to refresh just this partial section of your view by asynchronously fetching data from the server. A first step would be to create a controller action that returns a Spark JavascriptViewResult. public ActionResult ShowEmployees()
{
return new JavascriptViewResult {ViewName = "_ShowEmployees"};
}
This action tells Spark to generate some JavaScript code from the _ShowEmployees partial view (the one we see above). The JavaScript will know how to create the same HTML as the server side view. Since this action produces JavaScript, you'll want to add a <script> in your main view that references that action endpoint. (this is reminiscent of how ASP.NET AJAX produces WCF proxies
in JavaScript that know how to invoke service endpoints on the server, except client rendering isn’t about services – it’s about sharing a
data binding template logic between the client and server). <content:head> ... <script type="text/javascript" src="~/Department/ShowEmployees"></script> </content:head>
What you’ll receive in your view is a JavaScript object with a RenderView method, and the RenderView method knows how to take your view model (as JSON data) and create the same HTML as the server-side partial view. Combining this generated JavaScript object with jQuery’s AJAX capabilities is straightforward. $.getJSON(
"/Department/Refresh/" + $("#id").val(),
function(data) {
var content = Spark.Department._ShowEmployees.RenderView(
{ department: data });
$("#employees").html(content);
});
The above code gets a JSONified version of your view model from the server and passes it into RenderView. RenderView returns the HTML we can use to update the UI. Clever!
For more on Spark, check out Lou’s blog. 
|
-
Phil and Scott (and the other Scott) announced the open source Nerddinner.com project and their free ASP.NET MVC eBook today. Actually, the free eBook is a single chapter of 185 pages, which is at least 50 pages longer than any chapter in Tolstoy’s War and Peace (and over half the size of my entire workflow book). Amazing. In any case, I was looking through the code this evening and a thought struck me. You can divide the nascent world of ASP.NET MVC developers into two camps: The people who use strings don’t love to use strings – they just use them to get work done. But the people who hate strings really hate strings. They’d rather be caught using goto label than ever type a string literal, and they exterminate string literals from as many places as possible. The views in Nerddinner.com are full of strings: <p>
<label for="Title">Dinner Title:</label>
<%= Html.TextBox("Title", Model.Dinner.Title) %>
<%= Html.ValidationMessage("Title", "*") %>
</p>
The “Title” string is significant – it has to match up with the name of a controller parameter or the name of a model property when data movies in and out of the controller. A typo in the view, or in a model, can create bugs. Compare the “stringy” views to the views in another open source MVC application - CodeCampServer: <%=Html.Input(a => a.AttendeeID)%>
<%=Html.Input(a => a.ConferenceID)%>
This is another example of using LINQ expressions to implement “reflection without strings”. A typo here yields a compiler error. The technique is quite powerful and implementations are popping up everywhere, including inside the MVCContrib project.
Errors can be caught with either approach, but you can catch errors earlier and perform safer refactorings if you take Nancy Regan’s advice and Just Say No (to magic strings).
I’m curious – which approach do YOU prefer? 
|
-
There has been a lot of excitement in the community about the new ASP.NET MVC framework that is about to ship (literally any day now – announcement coming soon). As with anything new, people are also asking for more tutorials/samples/documentation that cover how to get started and build applications with it. Over the last few months I’ve been helping to contribute to an ASP.NET MVC book that Scott Hanselman, Rob Conery, and Phil Haack have been writing for Wrox. The book is now in production, and will be available to buy in stores soon (you can pre-order it on Amazon today). I wrote the first chapter of the book – which is a 185 page end-to-end tutorial that walks-through building a small, but complete, ASP.NET MVC application from scratch. The agreement I made with Wrox was that I’d write it for free in return for them also making it available as a free PDF download. I’m excited to announce that you can now download this free end-to-end tutorial chapter (it is a 14mb PDF file). It’s licensed under a “Creative Commons Attribution No Derivatives” license – which means you can share, distribute, print, or hand it out to anyone. NerdDinner ASP.NET MVC Tutorial The tutorial starts by using the File->New Project command in Visual Studio to create a brand new ASP.NET MVC project, and then incrementally adds functionality and features. Along the way it covers how to: - Create a database
- Build a model with validation and business rules
- Implement data listing/details UI on a site using Controllers and Views
- Enable CRUD (Create, Update, Delete) data form entry
- Use the ViewModel pattern to pass information from a Controller to a View
- Re-use UI across a site using partials and master pages
- Implement efficient data paging
- Secure an application using authentication and authorization
- Use AJAX to deliver dynamic updates
- Use AJAX to add interactive map support
- Perform automated unit testing (including dependency injection and mocking)
The application the tutorial builds is called “NerdDinner”. It provides an easy way for people to organize, host and search for new topic-based dinners online: Scott Hanselman has been hosting NerdDinners for years, and came up with the idea of building the tutorial around an application that facilitates this. He is also now hosting a live custom-skinned version of the application at www.nerddinner.com) Download Links Hope this helps, Scott P.S. The book is entering production now and so is officially in un-edited status (meaning professional editors haven’t gone through it yet). We’ll update the PDF with any important edits once the text is final. P.P.S. And yes – this is one of the reasons my blog has been more quiet than normal the last few months. Expect more regular blog posting again soon once I recover from this. :-) 
|
-
Today marked the start of Daylight Saving Time (DST), the day of the year with the most missed airline flights.1 There's an esoteric ASP.NET issue that centers around Daylight Savings, and affects websites both at the very start of Daylight Savings and at the very end. ASP.NET's forms authentication feature assigns a forms authentication ticket to a user once they sign in, with the ticket serving as an identity token. This ticket is, by default, stored as a cookie on the user's browser and is sent back to the web server on each subsequent request to the site until it expires. The ticket's expiry is specified both in the Set-Cookie header and within the ticket itself. The expiry specified within the contents of the ticket is an absolute time that the ticket expires in terms of the web server's time zone. Can you see the problem? When DST starts or ends the expiry in the ticket remains constant, but the web server's clock is shifted. For a person signing on right near the start or end of DST, the the ticket is either rendered expired an hour earlier than expected or an hour later than expected.
I describe this issue in Forms Authentication Configuration and Advanced Topics, one of the tutorials in my Website Security Tutorials series:
The expiry stored in the authentication ticket is an absolute date and time value, like “August 2, 2008 11:34 AM.” Moreover, the date and time are relative to the web server’s local time. This design decision can have some interesting side effects around Daylight Saving Time (DST), which is when clocks in the United States are moved ahead one hour (assuming the web server is hosted in a locale where Daylight Saving Time is observed). Consider what would happen for an ASP.NET website with a 30 minute expiry near the time that DST begins (which is at 2:00 AM). Imagine a visitor signs on to the site on March 11, 2008 at 1:55 AM. This would generate a forms authentication ticket that expires at March 11, 2008 at 2:25 AM (30 minutes in the future). However, once 2:00 AM rolls around, the clock jumps to 3:00 AM because of DST. When the user loads a new page six minutes after signing in (at 3:01 AM), the FormsAuthenticationModule notes that the ticket has expired and redirects the user to the login page. For a more thorough discussion on this and other authentication ticket timeout oddities, as well as workarounds, pick up a copy of Stefan Schackow’s Professional ASP.NET 2.0 Security, Membership, and Role Management (ISBN: 978-0-7645-9698-8).
Happy Programming!
[1] This is a total guess, but based on some emperical evidence from a sample size of one. Back in 2001 I would have missed a flight on the day Daylight Savings Time started had my girlfriend at the time (now my wife) had not called me that morning to ensure that I was aware of the time change.
|
-
All successful software projects resemble one another; each failed project fails in its own way.
|
-
Debugging code is a lot like the scientific method. Most importantly, both involve careful measurements and analysis of the resulting data. Be wary of the developer who is quick to announce the cause of an error. When an error occurs, a developer's first thought should be, "What data to I need to collect to better understand and analyze this error?" A less experienced developer is one whose first thought is, "Maybe the cause of the problem is (the database query|session timeout issues|invalid user input|etc.)?" This latter approach leads the developer down a series of dark alleys, many of which are dead ends.
Another important component of debugging and science are control groups and experimental groups. For the results of a scientific experiment to be sound, the researcher must have a control group that is not experimented upon, and an experimental group that differs from the control group by only one variable, namely by the "thing" that is being tested. In debugging, constructing the control group involves reproducing the error. If the QA department reports that an error occurs when entering a value longer than 50 characters into the Billing Address textbox on CheckOut.aspx, the first step in debugging is to visit CheckOut.aspx and enter an input longer than 50 characters into the Billing Address textbox to ensure that the reported error occurs. Likewise, the same steps should be repeated after the bug is fixed to help ensure that the fix has indeed solved the problem at hand.
Additionally, when debugging the practitioner must be careful not to taint the observations with his own preconceived notions or bias. The history of science is littered with examples of scientists who knowingly or unwittingly let their personal beliefs or the current societal mores color the data and influence their analysis. Johannes Kepler, the famous German mathematician and astrologer who penned the three laws of planetary motion, is a great example. Kepler started his astronomical career by using astronomical measurements to describe the motion of planets in our solar system. Although Kepler subscribed to Corpernicus's heliocentric model - that the sun was the center of the solar system rather than the Earth - he held to a rather convoluted theory that the planets orbited the sun based on different 3-dimensional polyhedra according to the Platonic solids. Kepler's problem was, in part, that he was approaching the problem backwards. Rather than taking the data at his disposal and asking, "What arrangement of the sun and planets would most sensibly explain these astronomical observations," he asked, "Can I construct a model that fits with the observations yet still maintains a semblance to the work done by the ancient Greeks and upholds my personal theological beliefs?" Fortunately, Kepler eventually abandoned his initial forays and came upon the a much simpler and, more importantly, a correct theory that proposed elliptical orbital paths with the sun as a focus.
A developer can fall victim to biasing observational data just as easily as Kepler did. A developer might be accustomed to bugs originating from a particular module, or from the code of a particular coworker. While such information is useful when deciding what data to collect, it is important to not let these preconceived notions influence the analysis of the data. While it may be mathematically probable that a particular error originated from a certain buggy module, don't ignore data that would suggest otherwise.
A corollary to Kepler's story is Occam's razor: that the simplest hypothesis is usually the correct one. If you find that you need to concoct an elaborate and complex scenario to explain the cause of the error, chances are you're barking up the wrong tree. More briefly, don't think too hard.
All this being said, debugging and science involves more than the mechanical process of gathering data and methodically interpreting it. There is an art form to the practice, and a certain wiliness and level of insightfulness that comes with much practice. But don't forget that the overwhelming bulk of any successful debugging session or any successful scientific experiment is keen measurement and straightforward, analytical interpretation of the data.
|
|
|
|