Search This Blog

Friday, October 27, 2006

Contract Coding

Thanks to Damon Armstrong for this article.

Contracts and scope definition

You’re called a "contractor", right? As such, it seems that you should have an actual contract, for the sake of propriety if nothing else. The reality is, however, that most contractors start contracting without ever actually making an official contract, or even fully defining the scope and deliverables for the project they are undertaking (guilty as charged!). Clearly, this can lead to serious problems down the line.

Project scope definition

One of the first things you need to do is to define a clear set of objective deliverables for the project. Normally, you define deliverables in a 'scope' document, which outlines the extent of the work you are agreeing to complete. You can also think of the scope document as a high-level 'design' document on which your client signs off – just like a contract.

When you create your scope document, you are essentially defining what needs to be done in order for the project to be considered 'complete'. Outline each item that you are going to complete, and attempt to be specific about what 'complete' means. If you are building a website, make sure to identify all of the pages in the site and the specific functionality for each page. The more detailed you are, the better off you are if you have a disagreement with your client over part of the project.

Also, remember to include a statement that indicates you are only responsible for items specifically designated as deliverables in the scope document. This helps protect you from any assumptions the client makes, but which he forgets to tell you about. For example, if you deliver an e-commerce site and your client comes back and says that you are responsible for all the product data entry, you can point them to this clause in the scope document and tell them that, since the data entry was not a deliverable, you are not responsible for its completion. If you want to be doubly-protected, you should also include a section outlining specific project items you are not going to deliver. This may seem a bit redundant, but specifics are always better than generalities.

Alongside the scope document, you also need to prepare a formal contractual agreement for the work you are about to undertake.

Writing up the contract

There are many tangible benefits to be gained from establishing a written contractual agreement. Hashing out a contract forces you and your client to outline all of the terms of your engagement, and it legally binds both to the fulfillment of those terms (at least, it does if you do it right). If you complete all the work outlined in the contract and your client fails to remunerate you in the method specified, then you have a means by which to pursue payment in court. Of course, it also means that you need to do a good job of outlining specifics, because ambiguity can only harm you.

So, the question is: what do you need to have in a contract? Here are some of the things that you will definitely want to consider:

Project deliverables

As described in the previous section, you and the client should formally agree and sign off on a scope and deliverable document, which can then be explicitly referred to in the contract.

Project timelines

You need to define how both sides handle time-sensitive situations and deadlines. Is there a deadline for finishing the project? Is there a penalty for finishing the project late? A bonus for finishing the project early? And, perhaps most importantly, what happens when the project timeline shifts because the client fails to provide a time-sensitive deliverable?

I’ve seen too many clients say they need something in a month, wait three weeks to give you what you need to start on the project, and expect you to have it done in a week. Always include something about delaying the project timeline in response to delays for items on which you depend, but the client fails to provide. You will be amazed at how quickly you can coax your client into getting things done when they know there are defined consequences for delays. You may also want to specify how you are going to bill clients during a period when you are waiting on a dependency.

Compensation

You need to define all aspects of how you will be compensated for your work on the project. Are you paid based on an hourly rate? Are there limitations on the number of hours you can bill in a given time frame? Is it a fixed-bid project? How, when, and to whom do you submit invoices? How much time does the client have to pay an invoice once it is received? What happens if the client fails to pay an invoice?

Travel time / expenses

If you need to travel out to the client for any reason, can you bill your travel time? Can you expense the mileage? And how do you handle other ad hoc expenses that come up during the course of the project?

Prerequisite needs

If there is something that you know you will need, in order to be successful on the project, make sure you include it in the contract. For example, if you expect to have VPN access to their network, or need a specific piece of hardware or software, then outline it specifically. This helps you avoid assumptions about your environment that may hinder your ability to complete a job on time and on budget.

Third-party software / licenses

If you know that you need to use any third-party software, you should outline who is going to pay for those tools, and who will own the licenses for them when the engagement is over. Even if you are not planning on using third-party software, it may help to have a clause in your contract that states that the client is responsible for paying for any third-party tools that are deemed necessary for the project. And then you will need to define how 'deemed necessary' is determined, because you do not want it to be ambiguous.

Communication

If you want to keep your sanity, be sure to define the process by which the client contacts you with questions, concerns or additional information about a project. If you do not want the client calling you during the day while you’re at your real job, then put it in the contract. To drive home the point, you can even put in a clause that allows you to charge them a premium if they do call you during a restricted time.

Maintenance

Almost every project you work on will have bugs, but you cannot provide indefinite support for an application. Make sure that you outline, in your contract, how you plan on handling maintenance with your client. This is a touchy subject, because clients quickly find issues with an application once it is deployed, and usually want those fixed as part of the original cost of the project. Normally, you will want to include the cost of a few maintenance hours in the original cost of the project, so you can stick around and fix problems for a little while after deployment. But you also want to protect yourself from a ceaseless stream of minor requests like changing the text of a label from this to that, moving a textbox from here to there, using a different shade of blue as a background, etc.

Liability

Cover your butt. I’ve heard of clients going after developers for a myriad of reasons, like lost employee productivity or even lost revenue due to glitches in software. There are a lot of things that can happen on a project and you need to have a broad-sweeping statement that attempts to cover the unforeseen. The more specific you can be about the things that can go wrong, the better off you are. For example, if you are building a billing system, then you should probably have a clause indemnifying you of the cost of any lost revenue due to billing errors, system down time, and so on.

Anything is better than nothing when it comes to contracts, so writing a contract yourself is a far better option than having nothing to go on at all. But you should be keenly aware of the fact that a professional contract lawyer is far more qualified than you are at writing contracts, so you should seek assistance from one, to help you write a solid contract. Writing contracts is a mysterious journey into the complex art of legal prose, most aptly scribed by a professional who actually understands the ramifications of what they are putting to ink. You may think your contract writing skills are akin to the works of Thoreau, but when you come up against a really good lawyer, you will quickly find they are more on par with Curious George gets his Ass Handed to Him In Court. Normally, you can ask a lawyer to write up a fairly generic contract that you can use for most of your engagements, so it’s well worth the investment.

Layers of Protection

A wise man also once told me that a contract is just an invitation to a fight. If you get to the point where you need to enforce something in your contract, then you need the help of the court system. And that course of action normally requires spending a lot of time, energy, and money on the legal process. So it’s also good to avoid a protracted legal battle by protecting yourself in other ways.

Full up-front payments

One way to make sure you get paid for your work is to get paid before you start working! However, negotiating a full up-front payment is a fairly difficult task, because it creates a risk reversal for the client. Instead of you taking on the risk of not getting paid for your work, the client takes on the risk of not getting the work for which they have paid. Some companies are willing to take that risk if you have a good reputation and they trust you. Some companies are so desperate for help that they will agree to anything. You should always check into a desperate client to see the source of their desperation. It may be that they need someone quickly and are willing to pay up-front to secure a qualified contractor. It may be that the project is a complete mess and they cannot get anyone in their right mind to touch it. Knowing their reasoning can help you determine if a project is really worth your time and effort.

One downside to accepting a full up-front payment is that some clients may feel cheated when you declare a project complete while there are lingering issues which the client feels you should resolve. But it’s far better, in this situation, to have the money in hand, because this is the point in time when some clients would refuse to pay you until you fixed those issues. It also illustrates the need for appropriate project scope definition, outlining what deliverables are covered in your fees and how to handle maintenance after finishing the project.

Partial up-front payments

A more common alternative to a full up-front payment is a partial up-front payment. This reduces the overall feeling of risk for a client, because they are not paying for everything up front. Most businesses understand the importance of an initial investment in a project, as a way of demonstrating a commitment, both to the project itself and to maintaining a healthy client-contractor relationship. When defining partial payments, you need to outline the specifics of how such payments are to be made. Normally, the client pays an up-front amount and then makes additional payments as you provide them with project deliverables. This creates a cycle in which you finish a part of the project and are paid for that part. It also sets up an easier environment for billing your client for additional work that arises in the middle of a project. If they want to add something to the project, or keep you on longer for maintenance purposes, then you can simply schedule additional payments for the additional work.

Maintenance and buckets of time

Most contractors accept a project, thinking that they are going to write some software, send it to the client, get a paycheck, and be done with it forever. But that is rarely the case. Business processes change over time and, when they do, your client may need to update your application to account for that change. And guess who they are going to call! Sometimes the requested changes are so significant that you can simply treat it as a completely new project. Often, however, you will get a client who has lots of little changes that come up sporadically. One tactic for dealing with this situation is to establish a maintenance time-bucket.

In this situation, the client pays you for a certain number of maintenance hours (say 5 hours). They can call you and request any changes that they want and you can deduct the time you spend on the fix from the time-bucket. When it starts getting low, the client simply refills the time-bucket by paying you for another set of hours.

Another suggestion is to establish an initial maintenance time-bucket for your project, and explain the concept to your client. Tell them that you will be available for this many hours after the project, and that, if they want to retain you for minor fixes, they can refill that bucket as needed. It’s a seamless way to move from project completion into a maintenance billing cycle.

Binary-only deployments

You may not be able to protect yourself by negotiating an up-front payment on each project, but you can still protect your development efforts with other strategies. When you compile a project, your easily readable source code is reduced to an economically indecipherable jumble of machine language. So, one option for protecting your code is to give your clients only the compiled form of your work. Binary deployments allow the client to interact with your work and even deploy it into a production environment, but also allow you to retain a bargaining chip if the client fails to pay you for the work you have completed. Most applications have bugs and eventually need changes, so the source code is important for the client to ultimately acquire.

Licensing and trial periods

Although source code is important, some clients can still find ways to abuse a binary-only deployment scenario. I spoke with one contractor who deployed his solution, only to have the client turn around and demand that he add additional reporting functionality to the application before they would pay him. It put him in a bad situation because, if he walked away, the client could continue to use his application as it was, or until they found someone else to rebuild the system, using his work as an example. You may even encounter some clients who lose their sense of urgency and, once they have a working solution in place, drag their feet when it comes to paying you. So how do you protect your binary-only deployment? By programming your application to quit working after a certain trial period!

Adding trial-period support into your application can be as simple or complex as you choose. You could add a full-blown licensing system to your application that checks a license key to determine if your software has been paid for or should run in trial mode. You could throw if-then statements around important sections of code that disable the application after a certain date. If you choose the latter, which is the cheapest and least difficult route, I highly recommend centralizing your date-checking logic so you can easily disable the date checks. If you have scattered checks throughout your application, then you are bound to miss one of them and incur the wrath of an angry client when the application they paid for suddenly stops working.

You may also want to consider targeting specific pieces of functionality instead of the application as a whole. For example, if you build a web application that has a customer-facing front-end and a back-end system that the business uses to manage the website, consider disabling the back-end system before disabling the front-end. Disabling the back-end system does not affect the customer’s ability to make purchases, but it does affect the client’s ability to process those orders. When you re-enable the back-end system, the client can process the backlog of customer purchases without losing any sales during the downtime. It’s an effective means of getting the client’s attention, without making too much of a negative impact on the client’s bottom line.

Never use trial period protection as a last-ditch act of revenge against a client who fails to pay you for your services. You will damage your reputation, and you may leave yourself legally liable for losses the client may incur as a result of their application suddenly ceasing to function. Always outline the trial period in your contract to let the customer know, in advance, that a trial period exists and exactly when the trial period expires. You should also refrain from displaying inappropriate comments to the client when your trial period expires. It may seem like fun to write a nasty message about how they should have paid you, but simply informing the user that the application is unavailable is much more advisable. Remember, if you mess up and accidentally display the expired trial message, it’s much easier to explain away an 'Application Unavailable' message than an expletive-laced tirade.

Informing your clients of all protective measures

You should expressly outline any measures you plan to take to protect your work (such as binary deployments, trial periods etc) in the contract, and discuss them with your client at the beginning of a project. By outlining the specifics, you help protect yourself from legal liability in the event that the client feels your protective measures damaged their business in some way. If you suddenly inform the client of such measures at the end of the project, then you are much more likely to get yourself into trouble and upset your client.

In conclusion

Remember, the most important thing you can do as a contractor is to establish an actual contract with your client. Effective communication is essential for a project to run smoothly. The process of hashing out a contract forces you to communicate openly with your client about topics most people seem too squeamish to bring up in normal conversation. Money and failure seem to be taboo subjects, but the finality of a contract makes it easy to discuss delicate financial matters and what happens if anyone fails to live up to their side of the bargain. Every client you encounter is going to be a bit different, so use your judgment in determining the best approach for payment options and source code protection.

You could read the original article by Damon Armstrong, in this link:
http://www.simple-talk.com/opinion/opinion-pieces/contract-coding-ensuring-your-client-pays-up/
Thanks to Damon Armstrong for providing this wonderful insight on this subject.

Check Your SQL Server Identity

We expect developers to be able to create stored procedures, write moderately complex SQL statements, and even the occasional trigger where needed. One question I like to ask goes something like this:

"Let's take a scenario using SQL Server 2000 where I'll be passing in two variables (firstname and lastname) to a stored procedure. That procedure should insert them into a table called TEST that has columns also called firstname and lastname. Table TEST has a primary key column named ContactID which is an integer and is also marked as an identity column. How would I obtain and return the primary key for the row just inserted?"

Stop for a moment and see if you know the answer. Do you know how to create the stored procedure? Obtain the value? Return it to the calling application?

A fair question to ask me is - why is this important? For me, it's a fundamental test to see if someone has worked with data in anything beyond a trivial way. Take the standard order/order detail scenario - how do you insert the details if you don't have the primary key of the order? And while you may have had the luck (good?) to work on a system with natural keys, not every system uses them and identities are the most common way of solving key generation in SQL. More importantly, if you ever do work on a system where identities are used and you rely on @@Identity, you could get some very unusual results at some point in the future when someone adds an auditing trigger. It's not a deal breaker question, but it's an interesting one to lead them into a conversation about dealing with related tables.

I get a variety of answers and most of them are shall we say less than optimum. Almost everyone figures how to insert the values and knows to use either an output or return value, but almost everyone trips on the identity portion.

Wrong Answer #1 - Select max(contactid) from Test. This is wrong because it assumes that no one else will be inserting a row. I suppose you could make it work if you used the right isolation level, but doing that will most likely reduce your concurrency. It's also doing more than you need to.

Wrong Answer #2 - Select top 1 contactid from test order by contactid desc. This is wrong for the same reasons described above.

Wrong Answer #3 - Select the row back by querying on other data you inserted into the table, essentially saying that you inserted an alternative primary key made of one or more columns. This would work if your data supported it and guaranteed that those values were indeed unique. Still not a good idea.

Wrong Answer #4 - In this one they almost get it right. They suggest using @@Identity which will work of course (with caveats), but when I ask them if they are any concerns with this technique, I usually get one of the following:

- No, there are no concerns

- You have to query it quickly because it is a database wide setting and you have to get the value before someone else inserts a row into any table in the database.

- Yes, it retrieves the last identity value for the session which is usually the value you want, but could be incorrect if you had a trigger on TEST which inserted rows into another table that also had an identity column. In that case you'd get the identity value from that table instead of TEST (Note: this correctly describes the behavior @@identity exhibits).

Right Answer - Use Scope_Identity() because it's SQL 2000, use @@Identity in SQL 7, and return the result as an output parameter (return value typically reserved for error conditions). Using @@Identity represents a possible bug in the future if auditing were deployed and it used an identity column as well.

Now let's run a couple tests to prove that the right answer is really correct:

create database IdentityTest

use identitytest
create table TEST (ContactID int not null identity (1, 1), firstname varchar(100) null, lastname varchar(100) null)

insert into TEST Default Values
select @@Identity

This will return the value 1. Repeating it will return 2.

insert into TEST Default Values
select Scope_Identity()

This will return a value of 3.

Now let's start by proving that @@Identity can cause strange behavior. We'll create a history table first that has a new identity column, then we'll add an insert trigger to TEST.

create table TESTHISTORY (HistoryID int not null identity (1, 1), ContactID int not null, firstname varchar(100) null, lastname varchar(100) null)

create trigger i_TEST on dbo.TEST for insert as

set nocount on

insert into TESTHISTORY (ContactID, FirstName, LastName) select ContactID, FirstName, LastName from Inserted

Now let's test what happens:

insert into TEST Default Values
select @@Identity

Returns a value of 1. Inspecting TEST shows that the last row we inserted had a value of 4, the only row in TESTHISTORY has a historyid = 1.

insert into TEST Default Values
select Scope_Identity()

( Corrected as correctly pointed out by adk in the comments)
Returns a value of 5.
Inspecting TEST confirms this, and confirms we inserted a second row into TESTHISTORY. Now let's start testing what happens if someone else inserts a row into TEST while we're busily working away in our stored procedure. Using the existing connection, we execute the first part:

insert into TEST Default Values

If we check the table we see that we just inserted row 6. Now open a second connection and execute the same statement:

insert into TEST Default Values

Check the table reveals we just inserted row 7. Now go back to the original connection. We start with someone we know should return the "wrong" result and it does, the value 3.

select @@Identity

Now let's try scope_identity(). If all went well, it should return 6, not 7!

select Scope_Identity()

And it does, supporting the Right Answer detailed above. I know this is SQL trivia, the kind of stuff I think you shouldn't have to delve into, but if you're going to use the platform you have to know how it works. Take this back and quiz your developers, you'll be treating them to some professional development and you may save yourself a large headache one day too.

You could read the original article in this link:
http://www.sqlservercentral.com/columnists/awarren/checkyoursqlserveridentity.asp
Thanks to Andy Warren for this article

Wednesday, October 11, 2006

Using Profiler to Identify Poorly Performing SQL Server Queries

Identifying Long Running Queries is First Step

At this step in the SQL Server performance audit, you should have identified all the "easy" performance fixes. Now it is time to get your hands a little dirtier and identify queries (including stored procedures) than run longer than they should, and use up more than their fare share of SQL Server resources.

Slow running queries are ones that take too long to run. So how long is too long? That is a decision you have to make. Generally speaking, I use a cutoff of 5 seconds. In other words, any query running 5 seconds or less is generally fast enough, while queries that take longer than 5 seconds to run are long running. This is an arbitrary decision you have to make. In the company where I work, the report writers, who are the ones who write most of the queries that are run against our databases have a different standard than I have. They only consider a query to be long running if it takes more than 30 seconds to run. So, one of your first steps is to determine what you think a long running query is, and then use this as your standard during this portion of the performance audit.

We don't have unlimited time to tune queries. All we can do is to identify those queries that need the most work, and then work on them. And if we do have time, then we can focus on those queries that are less critical (but still troublesome) to the overall performance of our SQL Servers. Also keep in mind that sometimes, no matter how hard you try to tune a particular query, that there may be little or nothing you can do to improve the performance of a particular query.

Before You Begin

For this part of the performance audit, you will be using the SQL Profiler tool that comes with SQL Server. As this article focuses on how to perform a performance audit, and not on how to use tools, it is assumed that you know how to use SQL Profiler. If you have not used it before, check out the SQL Server Books Online to get you started on the basics of how to use it.

Before you begin using Profiler to capture the query activity in your SQL Servers, keep the following in mind:

  • Don’t run the Profiler on the same server you are monitoring, this can noticeably, negatively affect the server’s performance. Instead, run it on another server or workstation, and collect the data there.

  • When running the Profiler, do not select more data than you need to collect. The more you collect, the more resources are used to collect them, slowing down performance. Only select those events and data columns you really need. I will make recommendation on exactly what to collect shortly.

  • Collect data over a “typical” production time, say over a typical 3-4 hour production period. This may vary, depending on how busy your server is. If you don’t have a “typical” production time, you may have to collect data over several different periods of a typical production day to get all the data you need.

When you use Profiler, you have two options of how to "set it up." You can choose to use the GUI Profiler interface, or if you like, you can use the built-in Profiler system stored procedures. While using the GUI is somewhat easier, using the stored procedures to collect the data incurs slightly less overhead. In this article, we will be using the GUI interface.

What Data to Collect

Profiler allows you to specify which events you want to capture and which data columns from those event to capture. In addition, you can use filters to reduce the incoming data to only what you need for this specific analysis. Here's what I recommend:

Events to Capture

  • Stored Procedures--RPC:Completed

  • TSQL--SQL:BatchCompleted

You may be surprised that only two different events need to be captured: one for capturing stored procedures and one for capturing all other Transact-SQL queries.

Data Columns to Capture

  • Duration (data needs to be grouped by duration)

  • Event Class

  • DatabaseID (If you have more than one database on the server)

  • TextData

  • CPU

  • Writes

  • Reads

  • StartTime (optional)

  • EndTime (optional)

  • ApplicationName (optional)

  • NTUserName (optional)

  • LoginName (optional)

  • SPID

The data you want to actually capture and view includes some that are very important to you, especially duration and TextData; and some that are not so important, but can be useful, such as ApplicationName or NTUserName.

Filters to Use

  • Duration > 1000 milliseconds (1 seconds)

  • Don’t collect system events

  • Collect data by individual database ID, not all databases at once

  • Others, as appropriate

Filters are used to reduce the amount of data collected, and the more filters you use, the more data you can filter out that is not important. Generally, I use three filters, but others can be used, as appropriate to your situation. And of these, the most important is duration. I only want to collect information on those that have enough duration to be of importance to me, as we have already discussed.

Collecting the Data

Depending on the filters you used, and the amount of time you run Profiler to collect the data, and how busy your server is, you may collect a lot of rows of data. While you have several choices, I suggest you configure Profiler to save the data to a file on you local computer (not on the server you are Profiling), and not set a maximum file size. Instead, let the file grow as big as it needs to grow. You may want to watch the growth of this file, in case it gets out of hand. In most cases, if you have used appropriate filters, the size should stay manageable. I recommend using one large file because it is easier to identify long running queries if you do.

As mentioned before, collect your trace file during a typical production period, over a period of 3-4 hours or so. As the data is being collected, it will be sorted for you by duration, with the longest running queries appearing at the bottom of the Profiler window. It can be interesting to watch this window for awhile while you are collecting data. If you like, you can configure Profiler to automatically turn itself off at the appropriate time, or you can do this manually.

Once the time is up and the trace stopped, the Profiler trace is now stored in the memory of the local computer, and on disk. Now you are ready to identify those long running queries.

Analyzing the Data

Guess what, you have already identified all queries that ran during the trace collection that exceed your specified duration, whatever it was. So if you selected a duration of 5 seconds, you will only see those queries that took longer than five seconds to run. By definition, all the queries you have captured need to be tuned. "What! But over 500 queries were captured! That's a lot of work!" It is not as bad as you think. In most cases, many of the queries you have captured are duplicate queries. In other words, you have probably captured the same query over and over again in your trace. So those 500 captured queries may only be 10, or 50, or even 100 distinct queries. On the other hand, there may be only a handful of queries captured (if you are lucky).

Whether you have just a handful, or a lot of slow running queries, you next job is to determine which are the most critical for you to analyze and tune first. This is where you need to set priorities, as you probably don't have enough time to analyze them all.

To prioritize the long running queries, you will probably want to first focus on those that run the longest. But as you do this, keep in mind how often each query is run.

For example, if you know that a particular query is for a report that only runs once a month (and you happened to have captured it when it was running), and this query took 60 second to run, it probably is not as high as a priority to tune as a query that takes 10 seconds to run, but runs 10 times a minute. In other words, you need to balance the length of how long a query takes to run, to how often it runs. With this in mind, you need to identify and prioritize those queries that take the most physical SQL Server resources to run. Once you have done this, then you are ready to analyze and tune them.

Analyze Queries by Viewing Their Execution Plans

To analyze the queries that have captured and prioritized, you will need to move the code to Query Analyzer in order to view the execution plan, so that it can be analyzed. As the focus of this article is on auditing, not analysis, we won't spend the time here to show you how to analyze specific queries.

How you move the code to Query Analyzer for analysis depends on the code. If the code you have captured is Transact-SQL, you can cut and paste it directly into Query Analyzer for analysis. But if the code you have captured is within a stored procedure, you have to do a little more work, because the Profiler does not show what the code in the Stored Procedure looks like, but only shows the name of the stored procedure, along with any parameters that were passed along to it. In this case, to analyze the query in Query Analyzer, you must go to the stored procedure in question, and cut and paste the code to Query Analyzer. Then, assuming there were parameters passed to it, you will have to manually modify the code from the stored procedure so that it will run with the parameters found when it was captured by Profiler.

Now the time-consuming chore begins, and that is the analysis of each query's execution plan to see if there is any way the query can be tuned for better performance. But because you have now identified and prioritized these problematic queries, your time will be much more efficiently spent.

SQL Server Query Performance Audit Checklist

SQL Server Job Checklist

Your Response

Have you identified all long running queries?


Have you prioritized the queries?


Have you reviewed the execution plans of the above prioritized queries?



Enter your results in the table above.

You could find the original article in this link:
http://www.sql-server-performance.com/sql_server_performance_audit10.asp

Monday, October 09, 2006

Missing Icons and Bad Links or Invisible Links or Script Error in MSDN

I recently had a problem with MSDN Library files, where most of the links produced a script error and the top links, which point to more resources or examples were found to be missing.
I tried re-installing and the same problem occurred.
And then I found the solution to it in the following link.
Missing Icons and Bad Links in MSDN - MSDN Forums:

Or else you could check out the solution down below in the words of the solution provider, Bri.


I have run into this "missing link" problem as well in MSDN versions Oct 2001 and earlier. I recently worked with MS Developer Support to alleviate this issue. Over the course of 2 days we found the proverbial "needle in a haystack" fix. All you have to do is change the following registry setting (Put the following text in a .reg file and run it if you wish):


Windows Registry Editor Version 5.00


[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{ADB880A6-D8FF-11CF-9377-00AA003B7A11}]
"Compatibility Flags"=dword:00000000

It's always amazing to me how small -- and invisible -- a fix is to problems like these!

--------------------------------------
For a step-by-step explanation:
1. Open your regsitry editor. Start --> Run --> Type in regedit
2. Go to the following Key
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{ADB880A6-D8FF-11CF-9377-00AA003B7A11}
3. Right Click on "Compatibility Flags" and select "Modify"
4. Type 0 in Value Data (zero)

Hope this was useful.

I don't know why this problem occurred though.
Maybe it maybe due to the fact that I had installed an IE update or I had installed and removed beta version of Visual Studio .net


Please visit my other blogs too: http://edwardanil.blogspot.com for information and http://netsell.blogspot.com for internet marketing. Thanks !!