This blog entry is about how I solved the problem where I was no longer able to enter the BIOS using F2 on my Intel NUC D54250WYK.
The problem started when I upgraded my BIOS from 22 to 25 and enabled SecureBoot. Once I did that, the NUC would boot directly into Windows without showing the NUC boot logo nor the F2/F7 prompt.
This is not an uncommon problem. In my case, it took a combination of solutions to solve the problem.
First, the fact that the NUC logo wasn't showing was a clue that the NUC BIOS wasn't detecting the monitor properly. Apparently there's some sort of detection for the monitor to support 1024x768. This detection seems flaky. I tried the DisplayPort connector on two separate monitors without success.
The solution for this problem was to use an Apple mini-DisplayPort to DVI adapter to go from mini-DisplayPort on the NUC to DVI on the monitor. Once I connected the monitor in this manner, the boot screen showed up immediately. I got the idea from this article, which recommended mini-DisplayPort to HDMI.
The 1024x768 detection is particularly problematic if you are connecting the NUC to a TV or through a receiver. In these cases, you may need to connect to a "real" computer monitor.
The next problem was the SecureBoot prevented the BIOS from showing. To solve this it was necessary to enter Maintenance Mode, as described at https://communities.intel.com/message/190524.
Monday, March 17, 2014
Intel NUC - Three flashes and won't boot
This blog entry is about how I solved the problem where my Intel NUC D54250WYK wouldn't boot after I upgraded my BIOS from 22 to 25. (I should have paid to attention to the note that said, "Don't install this if you don't need it." However, I was installing Windows 8.1 and I wanted to make sure I had the latest fixes.)
The symptom was that the NUC would turn on, would flash three times, wait a few seconds, flash three times, and then turn off.
I was running the NUC with 16GB of DDR3 1866 (PC3 14900) Laptop Memory. This memory is faster than most users run, but recent versions of the BIOS are documented as supporting this speed of RAM.
I tried taking out one of the DIMMs, which had worked for me in the past. However, this didn't work this time. (If you try this, make sure you take out the correct DIMM. The NUC will operate on one DIMM, but this configuration is only supported for one of the two slots.)
Eventually I just left the NUC alone for half an hour in its reboot cycle. It eventually booted successfully and the problem did not come back.
Followup, Oct 2014: My system would crash every couple of weeks after I wrote this article. I finally ran Windows memory tests, which failed. I changed the NUC BIOS to slow down the memory and it worked fine after that.
The symptom was that the NUC would turn on, would flash three times, wait a few seconds, flash three times, and then turn off.
I was running the NUC with 16GB of DDR3 1866 (PC3 14900) Laptop Memory. This memory is faster than most users run, but recent versions of the BIOS are documented as supporting this speed of RAM.
I tried taking out one of the DIMMs, which had worked for me in the past. However, this didn't work this time. (If you try this, make sure you take out the correct DIMM. The NUC will operate on one DIMM, but this configuration is only supported for one of the two slots.)
Eventually I just left the NUC alone for half an hour in its reboot cycle. It eventually booted successfully and the problem did not come back.
Followup, Oct 2014: My system would crash every couple of weeks after I wrote this article. I finally ran Windows memory tests, which failed. I changed the NUC BIOS to slow down the memory and it worked fine after that.
Sunday, January 13, 2013
Outlook 2010: Fixing "An object could not be found"
I just wasted most of a day troubleshooting Outlook 2010 giving me the error message, "The operation failed. An object could not be found." I'd like to thank Malik Shadid, who wrote a long and very useful blog post that pointed me to the tools below that helped find the solution.
Important: There are MANY things that can cause this error, most of which I'm not remotely qualified to diagnose. Therefore, I cannot answer questions about these procedures. This post describes my experiences, yours may be quite different.
The symptoms were as follows:
To help find the Autodiscover file, there's an applet in the Exchange PowerShell called test-outlookwebservices that will give you ther URL, as well as telling you whether the server responds to basic "are you alive" tests. It's documented on this TechNet Page. Here's an example:
Id Type Message
-- ---- -------
1003 Information About to test AutoDiscover with the e-mail address Administrat
or@abc.local.
1007 Information Testing server jupiter.abc.local with the published name http
s://jupiter.abc.local/EWS/Exchange.asmx & .
1019 Information Found a valid AutoDiscover service connection point. The AutoD
iscover URL on this object is https://jupiter.abc.local/Autod
iscover/Autodiscover.xml.
1006 Information The Autodiscover service was contacted at https://jupiter.abc
.local/Autodiscover/Autodiscover.xml.
1016 Success [EXCH]-Successfully contacted the AS service at https://jupiter
.abc.local/EWS/Exchange.asmx. The elapsed time was 31 millis
econds.
1015 Success [EXCH]-Successfully contacted the OAB service at https://hamme
r.abc.local/EWS/Exchange.asmx. The elapsed time was 0 millis
econds.
1014 Success [EXCH]-Successfully contacted the UM service at https://jupiter
.abc.local/UnifiedMessaging/Service.asmx. The elapsed time w
as 31 milliseconds.
1006 Success The Autodiscover service was tested successfully.
https://jupiter.abc.local/Autodiscover/Autodiscover.xml
This yielded the an error 600 with the following content:
<?xml version="1.0" encoding="utf-8" ?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
<Response>
<Error Time="20:34:08.3587762" Id="147247660">
<ErrorCode>600</ErrorCode>
<Message>Invalid Request</Message>
<DebugData />
</Error>
</Response>
</Autodiscover>
A half hour of research indicated that the "600" error actually meant that it was working, but it wasn't authenticated. So the above result was actually good.
I tried the same URL from two client computers. It gave the same result in both cases. So all of this looked okay.
https://www.testexchangeconnectivity.com/
After starting the Analyzer, click the Client tab, download the file and install it.
The results of this finally showed me the problem, which was that autodiscover.abc.local wasn't resolved by DNS. I put that domain in the HOSTS file, tried the Connectivity Analyzer again and... it failed again. But it got further than last time.
I chased down the errors by clicking the little arrows under each error message in Analyzer. By drilling down, I discovered that it didn't like that my server certificate was for jupiter.abc.local instead of *.abc.local. Fortunately Outlook doesn't care about this, so Outlook works even if the Connectivity Analyzer does not.
The other domain names I mentioned at the beginning of this article also had to be in the HOSTS file, so that effort wasn't wasted.
If it's successful, you can switch to the XML tab and see the Autodiscover.xml file.
Important: There are MANY things that can cause this error, most of which I'm not remotely qualified to diagnose. Therefore, I cannot answer questions about these procedures. This post describes my experiences, yours may be quite different.
The symptoms were as follows:
- Outlook would give the "object could not be found" error when trying to download the Offline Address Book (OAB) from the Send/Receive | Send/Receive Groups | Download Address Book.
- Attempts to create a new profile in Outlook would hang for at least several minutes.
- Outlook 2007 and 2010 talking to Exchange 2007, all on a LAN.
- The LAN is a small business LAN that had a new provider and a new firewall/router.
- Exchange was running under Hyper-V.
- Configured for direct RPCs, not RPC-over-http.
- The OAB did not have the latest changes from the GAL.
- The OAB had worked before the new router.
- The problem appeared on multiple computers.
- Outlook would connect and download mail/contacts/calendar successfully.
HOSTS file
My next step was to check for DNS resolution. My domain was "abc.local" with the server name being "jupiter.abc.local". For the purpose of testing, I added abc.local, jupiter.abc.local, and jupiter to the HOSTS file in C:\Windows\System32\Drivers\Etc. After doing this, I pinged the host by the various names to make sure it worked. (You do not need to reboot after updating the HOSTS file.) Unfortunately, this didn't fix it either.PowerShell
At this point it's important to understand that the OAB is a rather strange beast that sometimes uses a different set of protocols (and ports) than MAPI. The OAB can get the connection information from the Autodiscover.xml file, so it's critical that the Autodiscover.xml file be accessible, even in a small test environment. The actual process used to track down the AutoDiscover file is quite complex, as Malik describes in his TechNet blog.To help find the Autodiscover file, there's an applet in the Exchange PowerShell called test-outlookwebservices that will give you ther URL, as well as telling you whether the server responds to basic "are you alive" tests. It's documented on this TechNet Page. Here's an example:
[PS] C:\Documents and Settings\JimB>test-outlookwebservices | format-table -wrap -autosizeId Type Message
-- ---- -------
1003 Information About to test AutoDiscover with the e-mail address Administrat
or@abc.local.
1007 Information Testing server jupiter.abc.local with the published name http
s://jupiter.abc.local/EWS/Exchange.asmx & .
1019 Information Found a valid AutoDiscover service connection point. The AutoD
iscover URL on this object is https://jupiter.abc.local/Autod
iscover/Autodiscover.xml.
1006 Information The Autodiscover service was contacted at https://jupiter.abc
.local/Autodiscover/Autodiscover.xml.
1016 Success [EXCH]-Successfully contacted the AS service at https://jupiter
.abc.local/EWS/Exchange.asmx. The elapsed time was 31 millis
econds.
1015 Success [EXCH]-Successfully contacted the OAB service at https://hamme
r.abc.local/EWS/Exchange.asmx. The elapsed time was 0 millis
econds.
1014 Success [EXCH]-Successfully contacted the UM service at https://jupiter
.abc.local/UnifiedMessaging/Service.asmx. The elapsed time w
as 31 milliseconds.
1006 Success The Autodiscover service was tested successfully.
600 Error
To eliminate any firewall or routing issues, I first tried opening the Autodiscover URL in the browser on the server itself.https://jupiter.abc.local/Autodiscover/Autodiscover.xml
This yielded the an error 600 with the following content:
<?xml version="1.0" encoding="utf-8" ?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
<Response>
<Error Time="20:34:08.3587762" Id="147247660">
<ErrorCode>600</ErrorCode>
<Message>Invalid Request</Message>
<DebugData />
</Error>
</Response>
</Autodiscover>
A half hour of research indicated that the "600" error actually meant that it was working, but it wasn't authenticated. So the above result was actually good.
I tried the same URL from two client computers. It gave the same result in both cases. So all of this looked okay.
Connectivity Analyzer
Malik's blog also pointed me to a tool called the Microsoft Exchange Connectivity Analyzer (beta). (Requires .Net 4.5.) Get the tool from:https://www.testexchangeconnectivity.com/
After starting the Analyzer, click the Client tab, download the file and install it.
The results of this finally showed me the problem, which was that autodiscover.abc.local wasn't resolved by DNS. I put that domain in the HOSTS file, tried the Connectivity Analyzer again and... it failed again. But it got further than last time.
I chased down the errors by clicking the little arrows under each error message in Analyzer. By drilling down, I discovered that it didn't like that my server certificate was for jupiter.abc.local instead of *.abc.local. Fortunately Outlook doesn't care about this, so Outlook works even if the Connectivity Analyzer does not.
The other domain names I mentioned at the beginning of this article also had to be in the HOSTS file, so that effort wasn't wasted.
Test E-mail AutoConfiguration
The next step was to go to a client and use an undocumented feature in Outlook 2007/2010 to test the Autodiscover resolution. Ctrl-right-click the Outlook notification icon on the right in Windows. Select Test E-mail AutoConfiguration. Enter your Exchange email address and your password. Make sure Use AutoDiscover is checked. Click Test.If it's successful, you can switch to the XML tab and see the Autodiscover.xml file.
Wrapping Up
Finally I backtracked to find out why changing the router broke everything. It turns out that the old router was configured to forward all DNS requests to the Windows Server, which knew how to resolve *.abc.local to the proper server. Anything else was forwarded to Google's DNS. (Google's public DNS servers are blisteringly fast and are definitely worth using. Their IP addresses are 8.8.8.8 and 8.8.4.4)Sunday, July 15, 2012
5 Tips for Curing Feature Creep
[I wrote this article in 2000 and it was published in the Visual C++ Developers Journal. This article has always been one of my favorites and it's no longer available on the web. So I'm reposting it here for posterity.]
Longtime software engineers know that feature requests are as inevitable as the daily tides. These requests are usually made by impassioned people who preface their requests with statements such as, “I’m sure this will be easy,” or “I know you can squeeze this in for me.”
1. Avoid Saying No
All of these are typical engineering answers (or excuses, depending on your point of view). But the goal is to focus developers on corporate business priorities, so you need to try another solution. Appeal to the developer’s profit side. Developers may not always understand business, but they usually have a keen interest in their own financial stake.
If you made any of the preceding statements, you’ve already succeeded in uniting the rest of the room against you. It will be almost impossible to avoid the feature request. Instead, speak their language by asking, “What’s the revenue potential?” The sales person will name some figure, for example, two million dollars. Now ask, “How did you arrive at that figure?” If the sales person can’t offer a convincing argument, everyone else in the room will do the arguing for you.
Longtime software engineers know that feature requests are as inevitable as the daily tides. These requests are usually made by impassioned people who preface their requests with statements such as, “I’m sure this will be easy,” or “I know you can squeeze this in for me.”
Most textbooks say you can combat feature creep by performing
comprehensive up-front planning, creating detailed time estimates, and
establishing a track record of on-time delivery to back up your claims when you
try to control the feature set. This method works great, assuming you have a
specification to design against, you have the time to do a detailed design, and
you have developers good at estimating. In many companies I’ve worked with,
particularly at the startup stage, these conditions don’t hold true. In this
article I’ll talk about why people make feature requests, and I’ll give you
five tips for successfully managing feature creep that can be used in the
typical imperfect organization.
1. Avoid Saying No
This tip is easy to put into practice, and you’ll be surprised
how far it gets you. Instead of saying “No” to people and putting them on the
defensive, give them a positive answer instead. People like to
get their way, and when something prevents that, it upsets them. If you’re a
manager, consider how you’d feel if you asked a subordinate to do something
reasonable and that person said “no” to you. You’d probably be irritated and
have to spend the next few minutes curbing your temper to try and figure out
why the employee is so difficult.
Now, consider how others in the organization feel about development. They make what they consider a reasonable request (it may not be from development’s point of view, but they don’t know that), and development reacts by saying, “No. There isn’t time.” If you’re representing development and you make such a statement, you’ve put the other person on the defensive, left no room for negotiation, and set the stage for a hostile conflict.
Now, consider how others in the organization feel about development. They make what they consider a reasonable request (it may not be from development’s point of view, but they don’t know that), and development reacts by saying, “No. There isn’t time.” If you’re representing development and you make such a statement, you’ve put the other person on the defensive, left no room for negotiation, and set the stage for a hostile conflict.
Instead, try this
answer, “I think development can do that by either dropping features X and Y or
by scaling down the feature you described.” With this type of answer, you’ve told
them how you can put the feature in as well as given them the choice of what
tradeoff to make, thereby giving them a psychological feeling of control. Both
alternatives may be poor, but at least you’ve left room open for discussion.
And you never said “no.”
Don’t confuse providing
alternatives with saying “yes.” Say what
you can do, even if it bears no resemblance to what you are being asked for. You
may not be able to generate these alternatives off the top of your head, so
don’t hesitate to ask for a couple days to study how the request will affect
you . Let people know you need the additional time,
then get back to them when you say you will.
If you’re comfortable
playing politics, you can sometimes conveniently “forget” about features you don’t
think make sense. Tell the person you’ll get back to them about the feature,
then don’t get back to them. If the request really was important, the person
will remind you about it, and if it wasn’t, he or she will forget about it.
However, you can only get away with this if you have a consistent track record
of following up when you say you will.
I can think of many
meetings that would have been a lot more pleasant for me if I’d learned a long
time ago to avoid saying “no. Saying “yes” makes you appear a more reasonable person and you guide the discussion instead
of controlling it.
2. Make Decisions Based On Business Goals
Remember, engineers don’t think like people in other departments.
This leads to serious communication gaps between departments. Often, the people
requesting a feature speak “business,” the development representative speaks
“techie,” and the two sides can’t make the other understand their positions.
The CEO ends up arbitrating, but because the CEO also speaks business,
development loses. As this scenario repeats, the development manager loses more
and more credibility and eventually fails, by not delivering the massive number
of requested features on time, even though the manager never agreed to the
features or the schedule in the first place.
The textbook way to
solve this problem is to hire program and product managers whose job it is to
understand both the business side and the technical side. Outside of textbooks
and large organizations, these jobs often fall to the senior people in
development who have little or no training in business.
Resolving this problem
requires you, the developer, to learn to speak business. If you don’t explain
your position in a way the rest of the organization understands, it will be
very difficult to break out of the vicious cycle described previously. The rest
of the organization considers software development a black art, where worker
bees can churn out any amount of code in no time at all, if they’re pushed hard
enough. Engineers know it doesn’t work this way, but trying to explain this
rarely works.
As a first example of this technique, let’s look at a situation
where it might be applied inside development. It’s Monday morning and another
developer wanders into your office. Plunking down onto the nearest flat
surface, he says, “I’ve been thinking about our rendering code all weekend, and
I think I can make it 50 percent faster with about three days of work.” So which
of the following do you tell him?
·
That’s a great idea, faster is always better.
·
Absolutely not, there’s no time budgeted.
·
“If it’s really important to you, you can do it
after hours.”
·
“That section of code is already working and we
don’t want to destabilize it.”
All of these are typical engineering answers (or excuses, depending on your point of view). But the goal is to focus developers on corporate business priorities, so you need to try another solution. Appeal to the developer’s profit side. Developers may not always understand business, but they usually have a keen interest in their own financial stake.
The first point is that you shouldn’t say no to the
developer. However, instead of offering alternatives,
teach the developer the process of making the decision. How about an answer
such as, “You’ve obviously put a lot of thought into your proposal, but I know
you’ve shown a lot of enthusiasm about our company’s upcoming IPO. How would
making that change get us closer to that objective?” You force the developer to
analyze the reasons for the change, provide the metric for making similar
decisions, and demonstrate how that metric personally impacts the developer.
This technique won’t
work with all developers, but it is important that it should work for
architects and other developers who handle important parts of the project. If
the technique doesn’t work, you might want to question whether that developer
can make decisions in the company’s best interest.
I’ll make two final
comments about deciding based on
business goals. First, in some applications, such as air traffic control
software, protecting human life is more important than the bottom line. Second,
good business decisions depend on having a central strategy and sticking to it.
For example, if your application is for XML text markup, then adding SOAP
support probably doesn’t make sense. Even though SOAP is linked tightly with
XML, SOAP is for interoperability, not for text markup.
3. Use a Prioritized Master Feature List
Detailed lists are a cornerstone of engineering. A master list of
all feature requests can be an important tool in controlling feature creep. If
you’re following a formal development methodology, you should have the
beginning of this in a Marketing Requirements document. However, if you are a
typical small company, your process may be somewhat more ad hoc.
The secret to the list is to keep it prioritized. It doesn’t need to be perfectly ordered, just
categorizing each item as 1 to 5 is probably enough, with 1 the most important
and 5 the least important. You can prioritize development resources by having
developers work first on the priority 1 and 2 features. Once these are finished, move on to the quick and easy priority 3 and 4 features.
Ultimately, development will probably ignore most priority 4 and 5 features.
You’ll discover that
everyone will try to put everything into the highest priority, but here is
where speaking the business language pays off. As the design phase moves into
the implementation phase, and feature requests start rolling in, you need to
have a conversation with senior management that goes something like this:
“Do you agree our goal
is increased revenue?” Unless you’re a nonprofit company, senior management
will almost certainly agree. (Note to techies: a business can have valid goals
other than revenue, such as increased market share or increased profits, but a
company typically focuses on just one goal, because multiple goals can
conflict. For this discussion, I’ll use revenue as the goal.)
You next question is,
“Is it therefore reasonable that any changes to features be based on the
feature’s impact on revenue?” Again, it will be difficult for management to
disagree. Note the pattern of agreement we’re creating here.
“Is it therefore
reasonable that, given that development can’t do everything, we prioritize our
features based on the feature’s ability to increase revenue?” This statement is
the clincher. It is very difficult for management to disagree with the chain of
logic you’ve created. Once you’ve had this discussion, you can use management’s
own words to control it. The only other discussion point is how much revenue a
feature should be able to bring in before designating it a Priority 1. This is
a business decision, so you can stay out of it.
To see the prioritized
list in action, consider this situation: In the lunch-time status meeting, one
of the sales people has come back from a show where she has gathered dozens of
hot leads. One lead is for a large deal with a Fortune 50 company, and closing the
deal would be an important milestone for the product. The only problem is that deal
requires four new features, one a major change. Predictably, the CEO is excited
and wants to know how engineering can “Help out” to bring in this customer. Which
of the following should you respond with?
·
The developers are already working weekends.
·
Feature freeze was last week, and it’s too late
for a change.
·
It was already agreed that those features would
be in version two.
·
This has happened over and over again, and you
won’t add yet another feature for a customer who probably won’t buy anything
If you made any of the preceding statements, you’ve already succeeded in uniting the rest of the room against you. It will be almost impossible to avoid the feature request. Instead, speak their language by asking, “What’s the revenue potential?” The sales person will name some figure, for example, two million dollars. Now ask, “How did you arrive at that figure?” If the sales person can’t offer a convincing argument, everyone else in the room will do the arguing for you.
When the CEO agrees it’s
worth moving forward on the feature, you say something like, “It sounds like
the possibility of closing is only 25 percent. Therefore, I’ll prioritize this
feature at $2M * 25 percent=$500,000.” Sales organizations commonly use this
technique to project future revenue, so there’s no reason development can’t use
it, too. A rule of thumb is that the possibility-of-closing percentage never
goes above 75 percent unless a contract is actually signed. It is very
difficult for others in the room to argue with this logic, and the final dollar
value defines the feature’s priority.
Notice you never
mentioned development’s schedule or manpower. This is important. The moment you
start talking about development’s schedule, you also have to start talking
about estimates, and estimates are controversial and difficult to defend. If
possible, avoid discussing estimates. It’s often better to accept the new
feature and then quietly drop something (or several things) to the bottom of
the priority list. If someone asks why the feature isn’t in a release, you can
reply that the revenue potential for the feature wasn’t high enough, and again
avoid discussing engineering schedule and estimates.
Unfortunately, this
technique may indicate you need to add a feature at the last minute, and the
CEO doesn’t want to slip the release. The easiest way to handle this is to
capitalize on everyone’s belief that engineering can’t adhere to a schedule.
Instead of saying you don’t have enough time, say the estimates for the task
are too uncertain, and you aren’t confident you can finish it on time. From a
risk-management point of view, you believe it would be better to finish what
you have, then do a small point release with that one feature. Business people
understand risk, and you’re again speaking their language.
4. Understand the Root Requirement
There is a big difference between what someone wants and what someone
needs when they make a feature request. This happens because of a lack of
understanding about how to effectively link a real-world solution to a
technical solution. Therefore, when a developer meets with a nontechnical
person to talk about a feature, the developer must first understand the
nontechnical requirement driving the feature request before determining the
technical solution.
Here’s an illustration.
At the end of the day, the product manager stops you on your way to the car to talk
about a magazine review of a competitor’s product and the new “must-have” items
reviewers expect in that kind of product. The product manager believes the new
product you’re working on needs these features for “parity,” and he wants to
have a meeting with you tomorrow to talk about adding these features. Before
the meeting the next morning, you could prepare notes about:
·
Why magazine reviews are useless.
·
How far the release date needs to slip to add
those features.
·
How many people you’ll need to hire to implement
those features.
·
What features the product manager recommends
should be dropped to make room for new features.
At least two of these
responses represent ideas from this article, but none is the right answer. The
solution is to go through each feature, determine the end-user requirement
driving that feature, then see if you already have the feature, but no one knew
about it, or if you have an alternative solution to get the same result.
For example, say that
one feature request from the magazine article is to “support FTP.” Many reasons
might drive such a request. Because the FTP protocol is built into many
libraries, adding FTP support might not be hard, but no work is still quicker
than a little work. By going back and reading the magazine article yourself,
you might discover the competitor’s product needs FTP support do file transfer
through firewalls. However, maybe the application you’re building already supports
HTTP file transfer. Because http goes through firewalls even more easily than
ftp, it would not be necessary for you to add support for FTP. You can now explain
to the product manager that you are already able to meet the spirit if not the
letter of the requirement. Scratch one feature request.
Another example might be
a feature request to “support XML.” Such a broad, ambiguous description could
require years of development work. You might assume that only a developer could
properly interpret what “support XML” means. In this example, further
discussion with the product manager reveals the requirement is simply to be
able to say on the box that the product supports XML. You ask the product
manager what she means by “support.” And the answer is, “I don’t know. I just
need to be able to put those words on the box.”
Now, you probably think this
is stupid. However, XML is a big buzzword right now, and lots of people have
heard of it. It’s likely someone comparing products on the shelves at CompUSA
might buy a box with a big “Now supports XML” sticker, even if that person has
no idea what XML is and has no plan to use it! So, your job is to technically
decide what “supports XML” means, and to decide the minimum amount of work you
can get away with. XML is evolving so fast that anything you do will be out of
date before it ships, so one strategy might be to create something simple and
see how customers react. This is dramatically different than a requirement to
“successfully interoperate with three popular B2B, XML-based application
servers” that a statement like “supports XML” might mean.
5. Plan Your Development Strategy
All too often, despite your best efforts, so many features get
stuck into the product development can’t finish it in time. You can combat this
by changing your development strategy. In most organizations, the strategy is to
determine the feature set, pick a ship date, then, when the date is missed,
keep slipping the date until the feature set is finally finished. I’ll call
this the “feature-driven” strategy. Unless your organization is actually
skilled at project estimating (and, judging by the number of slipped dates in
the industry, few are) this strategy rarely works.
An alternative to the
feature-driven strategy is the date-driven strategy. In a date-driven strategy,
whatever you have on a certain date, you ship. This strategy has logic behind
it. In most cases, a date is chosen for a good reason. Perhaps it’s the end of
the quarter, perhaps investors are reviewing the company, or perhaps a customer
has a “drop dead” date for certain new features. In all these cases, developers
need to recognize that hitting the date is often more important then completing
all the features. Sales prefers to have something to sell, even if it isn’t
perfect, rather than nothing at all. So, the solution is to change the
development strategy so the company can ship something on any given date.
The key change to the
development process that this strategy requires is ensuring that features as
they’re built. In too many organizations, development does months of feature
development, then tests for bugs during a huge “bug bash” at the very end,
which invariably takes much longer than anyone expected. A date-driven strategy
calls for lots of little “bug bashes” along the way to keep the product as
stable as possible. With this strategy, when the deadline rolls around,
development can offer the organization two realistic alternatives—ship on time
with a limited feature set, or slip the ship date and add more features.
Remember, with two alternatives, you avoid saying no!
Development often
presents these alternatives, but frequently unsuccessfully, because the
development process doesn’t allow for shipping on time with a limited feature
set. If you leave bug fixing to the end, you can’t estimate how long they’ll
take to fix, so you can’t ship on time, even if you leave many features are
left out. By finding and fixing bugs as you go, you can actually offer these two
alternatives and be able to deliver on either of them.
To follow this strategy, it is an absolute requirement to maintain
the prioritized feature list to make sure the features you do deliver are the ones that will have the greatest impact on revenue
or market share.
Today’s reality is that the computer industry is changing very
rapidly and successful companies must be able to change direction on a dime. To
stay competitive, a company must have the flexibility to add features as a
product is developed. Ultimately, you don’t “win” if you successfully fend off
all feature requests that appear after the design phase is over. In a
product-based company, you win by doing whatever grows the business, enhances
market share, and/or drive revenue. Computer science classes rarely teach this
fundamental point, but it is important to remember when managing feature creep.
Being successful at doing this is much more a matter of working
with people and understanding business needs than it is of maintaining detailed
schedules and estimates to prove your points. At the end of those never-ending meetings,
the most important result is that other people feel good about themselves and
the decisions that were made. They don’t care about why you’re right—they care
about why they’re right. If you can consistently make people feel good about
themselves, you’ll always be a hero.
Monday, January 16, 2012
Windows 7 Forgets My Multiple Monitor Layout
For the last several months I've had trouble where every time I rebooted, my second monitor would become the default and my primary monitor would stop working. I think this started when I upgraded drivers, but I'm not positive. I've searched and searched for a solution to this, including reversing cables, adjusting the multiple monitor settings in Windows 7, and various obscure registry entries - but nothing worked.
The really strange thing was that Windows showed the login screen on my main monitor and the problem didn't happen until after I logged in, when the secondary monitor would suddenly become my primary. This symptom provided the key to the problem. After you log in, the nVidia Control Panel overrides your Windows display settings, so you must make sure that everything is set the way you want in the nVidia Control Pane.
To solve the problem, I did this:
The really strange thing was that Windows showed the login screen on my main monitor and the problem didn't happen until after I logged in, when the secondary monitor would suddenly become my primary. This symptom provided the key to the problem. After you log in, the nVidia Control Panel overrides your Windows display settings, so you must make sure that everything is set the way you want in the nVidia Control Pane.
To solve the problem, I did this:
- Opened nVidia Control Panel > Display > Set up multiple displays.
- Dragged the displays to the proper location.
- Checked all of the displays.
- Right-clicked on the desired primary monitor.
- Selected "Make this the Windows primary display."
- Clicked Apply in the bottom right.
Tuesday, November 29, 2011
Base64 for Unicode UTF16
Recently I needed to store a JPEG file in a Unicode UTF16 string. In UTF8 or ASCII, this is a trivial problem - use base64 encoding. But base64 encoding, which is 75% efficient for a single or multibyte character set, drops to 37.5% efficiency with double bytes - which means that the storage required for my JPEG data would almost triple. Since I had to store potentially thousands of images in memory simultaneously, this was a problem.
I ran across a great blog entry by Markus Scherer about a technique called Base16k. This seemed to be exactly what I needed, so I translated the JavaScript sample code into C++.
Note that this technique is designed particularly for UTF16. You will lose the efficiency if you write it to a file as UTF8. If you use UTF8, then don't use Base16k. Use base64 instead.
You can download the source code and sample project from:
I ran across a great blog entry by Markus Scherer about a technique called Base16k. This seemed to be exactly what I needed, so I translated the JavaScript sample code into C++.
Note that this technique is designed particularly for UTF16. You will lose the efficiency if you write it to a file as UTF8. If you use UTF8, then don't use Base16k. Use base64 instead.
You can download the source code and sample project from:
Friday, October 28, 2011
Convert a Locale Name to LCID in C++
I've spent most of the afternoon today figuring out how to convert a locale name, such as "en-US", into a locale identifier (LCID). Locale names are also called RFC 1766 language codes, or ISO 639 language names. As it turns out, this is easy to with the function LocaleNameToLCID(), but this function does not exist in Windows XP.
Microsoft provides a redistributable library that adds this functionality for XP, but it's 2MB and yet another module to install. Since my entire installation is 4MB, this isn't an option for me. You can read about that library in the article Mapping Locale Data on Downlevel Systems. In that article, they discuss the function DownlevelLocaleNameToLCID().
For handy reference, Microsoft provides a list of Language Identifier Constants and Strings on MSDN.
If you then need to convert the LCID to a CODEPAGEID, you can use this call to retrieve the code page for a particular LCID:
Additional information on this topic can be found on The Old New Thing blog, including a discussion of using the MLang library.
Microsoft provides a redistributable library that adds this functionality for XP, but it's 2MB and yet another module to install. Since my entire installation is 4MB, this isn't an option for me. You can read about that library in the article Mapping Locale Data on Downlevel Systems. In that article, they discuss the function DownlevelLocaleNameToLCID().
For handy reference, Microsoft provides a list of Language Identifier Constants and Strings on MSDN.
If you then need to convert the LCID to a CODEPAGEID, you can use this call to retrieve the code page for a particular LCID:
GetLocaleInfo(lcid, LOCALE_IDEFAULTCODEPAGE, ...)
Additional information on this topic can be found on The Old New Thing blog, including a discussion of using the MLang library.
// This is a version of LocaleNameToLCID() that works on Windows XP.
// On Windows Vista or later, it automatically delegates to the
// built-in version of LocaleNameToLCID().
// This function is not case-sensitive.
// Tested with Unicode builds only, not tested under ANSI builds, but should be pretty close.
// Example value for szLocale is "en-US"
LCID CompatibleLocaleNameToLCID(LPCSTR szLocale)
{
CString strValue(szLocale);
CStringW wstrValue(strValue);
static bool bDone;
LCID (WINAPI * pfnLocaleNameToLCID)(LPCWSTR, DWORD);
if (!bDone)
{
bDone = true ;
*(FARPROC*)&pfnLocaleNameToLCID = ::GetProcAddress(GetModuleHandleA("Kernel32" ), "LocaleNameToLCID" );
}
if (pfnLocaleNameToLCID)
return LocaleNameToLCID(wstrValue, 0);
CComPtr<IMultiLanguage> iLang;
HRESULT hr = iLang.CoCreateInstance(CLSID_CMultiLanguage);
LCID lcid;
if (SUCCEEDED(hr) && SUCCEEDED(iLang->GetLcidFromRfc1766(&lcid, (BSTR)wstrValue.GetString()))) {
return lcid;
}
return LOCALE_USER_DEFAULT;
}
Subscribe to:
Posts (Atom)