Cocoa app - security issue - objective-c

I've a question about a good way to protect a bit my cocoa app from piracy. I know that this is impossible!
So, in my app I've an isRegistered() method that runs every time the user launch the app.
This is called from the applicationDidFinishLaunching: App delegate. So if this method returns true, the app continues to execute the code, otherwise an Alert appears saying that the app is not registered and there are xx day to buy a license.
This is a good way? Because, I have no experience in this.
Thank you in advance for your help!
SOLVED
First of all, thanks to everybody! I think the same thing: any copy protection can stop the piracy. I'm trying only to solve this little bug, even if I know that someone will crack my app again.
However, it's true - the best thing is to improve the app and not waste the time to try make the piracy protection more efficient.

The solution you describe requires almost no expertise whatsoever to crack. It is trivial to change your isRegistered() function to always return true. Thus, the effort required to circumvent your protection is a tiny fraction of the effort you would have to spend implementinging all the infrastructure to support users purchasing registration codes.
In other words, you're not getting a good return on investment. There is some debate over whether the return on investment implementing piracy protection (rather than improving your product) is ever good enough (because you pit yourself against people who have nothing better to do than prove they're cleverer than you).
One good way to redress the balance of return on investment is to use pre-existing code such as AquaticPrime. That way, at least you won't have spent so much time chasing rainbows :)

I am not in shrink-wrapped software business but my friend is. And his observation after 10 years of selling his product was that it makes no sense to create too sophisticated protection because always some one will hack it. You are alone and world is infinite. It is better to invest time/money in improving your software than working on copy protection.
Also keep in mind that around 10% of will never steal and other 10% will always try. Just make sure that those 80% is able to buy your product without any other mayor obstacle. Than you could ignore those nasty 10%. Actually it is a quote from Joel Spolsky IHMO.
So your solution seems to be completely OK from technical point of view and just stay with it.

it's almost never worth implementing your own anti-piracy system, because you'll almost always spend a lot of effort on something which can then be broken very easily. Rely on a shared implementation - in this case a framework like AquaticPrime (lots of people on the macsb mailing list recommend that one) - and you're effectively relying on the framework being good enough to protect your own app as well as all the others.
The code signing framework on Leopard and later allows you to sign your code such that if it's ever tampered with, it will refuse to run - see the documentation of the kill option in the manpage.

This is a good question. Having read the answers, I think what BitDrink was really getting at was this: we know that an isRegistered() function is dead simple to hack. With the understanding that any protection system eventually will be hacked, what are some strategies for writing a function that's harder to hack than an isRegistered function that returns a boolean?
Fundamentally, any copy protection system will eventually have something that looks like this:
if (program is registered)
let the program continue
else
nagging message
end
Any hacker with a copy of GDB will eventually find that first line and write a tiny little patch to strip it out. Most copy protection systems focus on security through obscurity, i.e. making that line hard to find. You can also make this system more robust by signing the binary and checking the signature, but you'll just add another hoop for the hackers to jump through. They'll eventually find your public key and change it to their own public key so they can replace your signature. However, I believe this will significantly slow them down. Leopard offers a code signing utility, but I don't know if it can be used to prevent incorrectly signed applications from running at all.
There's no perfect solution to this problem, but there are two main things to remember:
your registration system will be broken. There is absolutely no way around this.
your reigstration system is a barrier between the user and your program. You should optimize for the (hopefully majority of) legitimate users and make this as easy to do as possible.

Related

Hardware Serial Number Discussion. Licence protection

I am working on some application wich will get HDD serial number and then i will use that HDD serial number for licence (cd-key) registration with product. Now the problems wich i can come to:
User have 2 HDD's and once my application gets its serial from first HDD it will register with it so what if user later changes order of HDD's? if the seccond HDD becomes a Master and the first one becomes slave? could be solved with getting both and combine them togather but what if later he removes one then? :D
What if user's HDD dies and he buys new one? Is still same pc only another HDD. So the licence wont be walid anymore just because is another HDD.
Is it possible to fake it? Example i am using VB.net 2010 and application is working on framework(.net) so there is some "dll" wich is responsible to get the serial of HDD so would be possible to replace this "dll" (crack it) so it returns some hardcoded serial of hdd?!?
Could be possible to get processor serial? that would be much batter but could it be done? and does the processor have serial, i mean probably have but is it possible to get it? and same question as abowe could it be faked through changing "dll" or something?
anny other suggestions or experiances?
I seen there are more questions like this but couldnt find some answers so now i ask here!
------ EDITED/ADDED: -------
As talked below i forgot all .net can be decompiled in few secconds! so...
Making own installer. Why?
if i make an installer in wich you enter serial and only if serial is ok to use then install software so what it does? it extracts my software to your computer and again you have ".net" exe wich you can easely decompile and make a crack for it so where is point in making installation with serial!? or if my software is "protected" with some obfuscator so then installation with serial is unneded here i could then simply include serial registration in my software and using some booleans store registered=1||0
i got email from one person here, btw. duno where you got my mail :) and he says some smart things and why some of you people dont respond to my question and this discussion and what he says is this: "scared that others will see my code and how bad it is." so then people just dont want to spent time on this. well thats not problem i know my code is big "minestrone", big mess much words(variables) some on english some on croatian so on well my software is working thats important and i know i suc* we all suc* everyone knows something(more or batter) that the other one. anyway, thats not problem, problem is that i dont want that the software is open source lets say my software is "photoshop" and now someone downloads click there and there and have the whole code and can easely copy paste change few things and no problem he made good application :)
custom compiler? anyone have experiances? would it be ok for some time? :)
what other solution or language would be good to use in future to avoid this "open source" .net! i been looking around so for vb.net, c#, c++ is all based on .net so is all same. vb6 wich i love again same thing. they all can easely be decompiled! what language could not be so easy to decompile? should i switch to assembler? :D i joke, i hope! :p
maybe i just too much stressed up, much work! duno you decide :)
PLEASE READ MY QUESTION AND PLEASE DONT ANSWER ME SOMETHING LIKE "PIRACY CANOT BE STOPED BLA BLA" AND THINGS LIKE THAT. THAT WASNT MY QUESTION! THANK YOU!
Sorry on bold big latters but some people read just title and then answer stupidities! If you want talk about it then read question and write otherwise dont post some stupidities please
Let me first answer your questions:
If the order of the HDDs changes, your application could still find that serial number within the system. However, in either case I would resort to a scheme where I use the device of the system partition or so.
If the HDD dies, the user will be in trouble. There is no good solution to that as long as you insist on your source for the uniqueness of the user's system: i.e. the HDD serial.
It's absolutely possible, yes. At different levels, though. A cracker would always choose the simplest method.
Yes. I'm afraid that will only work with unmanaged code, though. See Wikipedia. And yes, this could be circumvented again by DLL placement (see my comment on the question).
Now let me give you an advice that worked fine for me. Use the SID of the machine account (not to be confused with SYSTEM, which has a well-known SID). And before you counter with NewSid (which, by the way has been retired by MS), this is much more effort to change, especially in domain environments and can have very nasty and unforeseen effects. Therefore if you want to tie your application to a Windows installation, the SID will be sufficient. The SID has the same advantages as a UUID you could create, but it's not as easy to manipulate as a UUID that you store in the registry or a file.
Oh, and before I forget to mention it. Yes, even using the SID can be "cracked" in various ways. But it balances convenience for the user with your demand for security.
Yes, you have to be aware of that. You'll need several fall back methods to take care of this
You have to be aware of that as well.
Everything is fakeable with some energy behind it. However, why fake such an id if you simply can manipulate the program itself? All .net code can be disassembled and manipulated
I think this is possible as well, but would have the same problem behind it.
Other suggestion:
Just because there is piracy, don't make the experience bad for your customer. Use something that is reuseable (like a serial number or keyfile), invest in a good obfuscator to make it harder for somebody to inspect your code, but beyond all: Make your application stand out so people buy it. And even though you didn't ask for it, I have to say it - you can't stop piracy by enforcing orwellian-like surveillance of your program. This will drive customers away as it is a pain in the *ss to work with your application. With a serial or keyfile you still have some sort of protection, the customer likes it because it is easy to use, he doesn't have to call you/write a support ticket if his computer fails or the stars align unfavourable. Pirates will break it eventually, but your customer is happy, and that is what counts.
Anything you rely on which is in userland can and will be spoofed if it is worthwhile to the end user/attacker. So locking the licence to an HDD serial number will not put of attackers, but it will seriously upset your customers.
The same goes for processor serial numbers - it is too easy to pop some code inline to change what your application will read.
Your only reasonable bet will be dongles - ie specific hardware, or a way to get them to register and run with an online connection, so you can validate them using elements you control (although in saying that, if your app is high enough value, expect the dongle to be hacked/replicated too!)
Your biggest problem may be overdoing the security - if you get it wrong in any way you will alienate your customer base.
People regularly upgrade failed hard drives, or those which are too small, as well as most other components in their computers. If you stop them using your product, even for a couple of days, they are likely to look elsewhere!
You can do what you are suggesting, but there are issues. What you are suggesting is called "machine binding" in the licensing world. There are commercial tools that do this for you (disclaimer: I work for one such provider Wibu-Systems). What YOU are proposing has some pros and cons:
Pros: requires no separate hardware (dongle), you can roll your own, easy solution to implement at a basic level.
Cons: can be cracked in a matter of minutes, will create problems for users when they change the HW config or move the app to a new PC, rolling your own will introduce the oppty for new bugs in an area you apparently have no prior experience with.
Why not use a commercial solution? Would you write your own setup program, too? How about your own compiler, linker, and debugger?

Code readability and UI design balance

I have worked a lot on improving how my code runs (and it's "beauty"), but when is the time to stop fixing, and start working on the UI?
Microsoft (in my opinion) seems to go with the nice-code, while Apple goes with nice UI (although Apple's developer examples do have very nice code).
I'm bad at balancing, when is it the time to work on one or the other?
Make it work, then make it elegant, then make it fast.
If the user doesn't like the program, the quality of the code is irrelevant. Once the user likes the program, then code quality becomes more important. And by "like" I mean a good user experience where the program doesn't crash, fulfills the need that the user has and adhere's to the Principle of Least Surprise.
Note I say "more important" because code is not something the user sees or is interested in. Code quality and "beauty" is important to developers because it's what they see of the program and what they hand over to other developers.
I remember reading something some time ago comparing (in general terms) software developed for the windows platform and software developed for OS X. In general terms it said that windows programs tended to be developed by developers who didn't spend too much time on the UI or thinking about the user experience. Their concentration was getting every piece of functionality they could think of into the program without any thought about it making sense. Mac OS X on the other hand tended to be developed by people concentrating on the user experience first and solving their problems. So it didn't necessarily have as much functionality, but what it did have was directly associated with what the user needed and was easy to use.
So when is it time to stop and think about the UI? The fact that you have asked the question makes me think it's time to stop right now. If anything I'd suggest that even before writing any code you should have drawn out a basic UI and worked out what sort of user experience your program is going to provide If you cannot work that out, you don't want to wasting time writing code because you will never use it.
Thats not to say I think code "beauty" is irrelevant. I spend time on making sure my code is well written, easy to follow and looks "good". But that's after I've figured out the UI and because I've had a lot of experience with cleaning up other people aweful code :-)
This is an incredibly broad question, and the answer is entirely a function of what you're building, why, and for whom.
Some random bits of conventional wisdom that I agree with:
If you're building broadly-applicable consumer software (e.g. for Mac or iOS), then the UI is a critical component of the application. Spend lots of time on it. :) Work with designers. If your software looks like crap, no one will want to use it. (Assuming nobody's going to make them: see next point.)
If you're building internal or enterprise tools, UI polish is probably less important.
Even if you're a one-man (or woman) operation, think of engineering as distinct from "product management". Product management is the thought process that determines what the software should do, and how it should work (and look). Engineering creates the reality, but has different tradeoffs. These are sometimes in conflict, which is hard to handle if you're one person, but try to wear different hats.
In all cases, your code should work, for some reasonable definition of work.
If it's ugly because it's hacked together, you're likely to run into accuracy/correctness problems sooner than if you construct it methodically. It will also be harder to maintain. The tradeoff here is almost never worth it. As you gain experience, you'll more naturally write clean code from the start, even if it's "scratch" code. You'll save time in the long run this way, and not be faced with later wholesale attempts to improve its beauty.
If you're on a team, or working with others, clean code is even more important. Find out if there are any "local" coding conventions, and work closely with colleagues.
As far as improving "how code runs", if you mean performance optimization, don't do any of that until you're sure you need to. Write the simpler code first, even if it's slower. It's likely that it won't be slow enough to matter.
Special case: if you're writing a game, long-term maintainability is less important, because they tend to be "throwaway" at some level. YMMV.

When you write your code, do you deal with errors proactively or reactively?

In other words, do you spend time anticipating errors and writing code to get around these potential issues, or do you write the code as you see fit and then work through any errors on an issue by issue basis?
I've been thinking a lot about this lately and I'm very much a reactive person. I write my code, give it a whirl, go back correct error and repeat until application works as expected. However a friend of mine offered that he spends time thinking how each line is interpreted and fixes errors before they occur.
I must point out that re-active is pure PRE-live. I definitely make sure my application is working before it goes live.
There should always be a balance.
Too many error checking is slow and leads to garbage code. Not enough error checking makes your program crash on edge cases which is not very good to discover after having it shipped.
So you decide how reliable some piece of code should be and implement error checking accordingly. Some test utility can be not very reliable - less error checking. A COM server meant to be used by a third party search service in deep background should be super reliable - much more error checking.
I think asking this in isolation is kinda weird, and very subjective, however there are obviously a bunch of techniques that permit you to do each. I tend to use these two:
Test-driven development (this would seem to be proactive)
Strong, static typing (reactive, but part of a tight iterative development cycle, as in, it's enforced by my ML compiler, and I compile a lot)
Very occasionally I swerve into the world of formal verification of programs. That's definitely "reactive", but if you think a little more up-front, it tends to make the verification easier.
I must also say that I value a lot of up-front thought in programming. The easiest way to avoid bugs is to not write them in the first place. Sometimes it's inevitable, but often a little more time spent thinking about the problem can lead to better-quality solutions, and then the rest can be taken care of using the kinds of automated methods I talked about above.
I usually ask myself a bunch of what-ifs when coding, like
The user clicks the button, what if they didn't select a date?
The user is typing in the search box, what if they try to type html in there?
My label text depends on a value from a shared drive, what if it's not mapped?
and so on. By doing this I've found that when the application does go live, there are a ton fewer errors and I can focus on fixing more obscure bugs instead of correcting conditions that should have been in place to begin with.
I live by a simple principle when considering error-handling: garbage in, garbage out. If you don't want any garbage (e.g. invalid input) messing up your software, you have to find all the points in your software where it can get in and handle it. Of course, the more complicated your software is, the harder it is to find every point of entry, but I feel that the more you do up front the less reactive you will need to be later on.
I advocate the proactive approach.
I try to write the code in that style which results in maintainable and reliable code
I use the defensive programming techniques to prevent stupid errors in code due to my loss of attention and similar
I design the database model according to the fortress principle, SQL code checking for results after each singular operation
I think of potential problems that can happen with that part of the code and I account for that. Not for every possibility but for major ones I can think of right now.
This usually results in software operating rather smoothly. At times it even surprises me but that was the intended goal, so here we are.
IMHO, the word "Error" (or its loose synonym "bug") itself means that it is a program behavior that was not foreseen.
I usually try to design with all possible scenarios in mind. Of course, it is usually not possible to think of all possible cases. But thinking through and allowing for as many scenarios as possible is usually better than just getting something working as soon as possible. This saves a lot of time and effort debugging and redesigning the code. I often sit down with pen and paper for even the smallest of programing tasks before actually typing any code into my editor.
As I said, this will not eliminate all errors. For me it pays off many times over in terms of time spent debugging. Another benefit is that it results in a more solid and maintainable design with fewer bugfixing hacks and special cases added on later. But in any case, you will have to do a lot of debugging after the code is done.
This does not apply when all you want is a mockup or rapid prototype. Also practical constraints such as deadlines often makes a thorough evaluation difficult or impossible.
What kind of programming? It's impossible to answer this in any general way. (It's like asking "do you wear a helmet when playing?" -- well, playing what?)
At work, I'm working on a database-backed website. The requirements are strict, and if I don't anticipate how users will screw it up, I'm going to get a call at some odd hour of the day to fix it.
At home, I'm working on a program ... I don't even know what it'll do yet. I can't deal with 'errors' because I don't know what 'an error' is in this context, because I don't know what correct behavior is going to be. The entire purpose of the program can and frequently does change on a timescale of minutes to hours, so even a couple minutes spent thinking about errors this early is a complete waste of time. (It's even worse than browsing SO, since error-handling adds lines of code.)
I guess the only general answer is "I do what makes sense in terms of saving time in the long term", which is, after all, the whole reason to use machines to do work for us.

What should a tester report?

I have a web site I am building for a client. I now have a tester on the project with me.
I feel testers are needed. REALLY! I cannot test my own code. I also appreciate the value of a new set of eyes. But what desires reporting?
It is easy to say everything should be reported, but I don't have someone between me and the tester to filter out the unimportant requests. The tester does not know the system nor the target user well. She is assigning me tasks and not the project manager. I think this will change soon, but until it does, what do you recommend? There seems to be a believe that our users have NEVER used the interent before at all, and they are as dumb as rocks.
The problem I am having is that EVERYTHING the tester suggests is being accepted automattically and assigned to me.
I have many cases that make me drop my jaw and say "Really? Are you serious? This deserves to be a issue?"
Ex: Need to add text at top of page that says "* = Required" for required fields.
Have you ever felt this way? How did you deal with it?
For now, I am just doing as I am told, but I am making it clear I do not agree.
It sounds to me like your tester is doing the right thing. You can't assume any level of user expertise when testing an application. If a user can break something, they will.
You and your tester need to work out a severity scale. The outliers (those that anybody with Internet experience could probably work around/would never hit) would be considered low priority and sit on the back burner until you knock out the high priority items.
...never the less, those outliers should still be logged because they can definitely come back to bite you in the ass in the end.
You need to add priorities for your issues. This will allow you to do the important issues first, and cosmetic issues last. Here is example priorities from Jira:
Priority 1 - a reproducible crash; issue blocking any further testing or development of a specific feature; loss of user's persistent data; huge memory leak
Priority 2 - a major issue that must be fixed before the product is released; prevents users from using a feature; negatively affects partner; significant memory leak in frequently used functionality
Priority 3 - a minor issue that should be fixed before a product is released; does not prevent users from using a product; highly visible usability issue; small memory leak in rarely used functionality
Priority 4 - a purely cosmetic issue; doesn't affect functionality
Actually it sounds like your tester is doing the right thing (and the text for "* = required" is a very good idea).
In addition to the suggestions about prioritizing reports, I would suggest that you categorize the reports as to whether they refer to user experience or functionality.
You and the tester will never exactly agree on what "needs" to be reported. Just set the priority on issues correctly, and get on with fixing the high-priority stuff first.
One thing you absolutely do not want to do is to discourage the tester from filing bugs. That'll come back to bite you when something ships totally broken, and they say "I thought that was just how it worked".
Do make sure that you're communicating the development schedule and status properly, so they don't waste time testing features that aren't sufficiently complete.
I would report to the client what each change will cost in terms of time and money. Things that are legitimate bugs you'll probably need to fix on your own time (unless your contract says otherwise). Things that are design / subjective issues you should be able to assign a cost to. Let the client know what it is going to cost them and they can decide if they want to proceed or not.
Hopefully you've got some sort of a project specification that the client has signed off on so that you know when the project is complete and what sort of things are not included in the project scope. If not, you might have a bit of a fight on your hands. For changes that you think are outside of the project scope, you might need to compromise - maybe bill them at a cheaper rate or split the cost with them. If you're in that situation it's a good learning experience to get everything documented in the project specification so that there is no question about what falls outside of the project scope. I've been there - one experience like this is enough to teach you to put more work into your specifications.
Report everything and triage. After a bit of time, she'll start to understand what gets past triage and what doesn't. Humans can learn; teach.

How can I think like a user? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
We're neck deep in a project right now, schedules are tight (but reasonable). Our general strategy is to get a strong beta done, release it for testing, and get feedback from our testers.
Quite frequently, we're being hit by small things that spiral into long, time-costing discussions. They all boil down to one thing: While we know what features we need, we are having trouble with the little details, things like 'where should this message go' and 'do they need this feedback immediately, or will it break their flow, so we should hold off'?
These are all things that our testers SHOULD catch, but
a) Each 'low priority' bug like this drains time from critical issues
b) We want to have as strong a product as possible
and
c) Even the best testing group will miss things from time to time.
We use our product, and we know how our users use the old version...but we're all at a loss as to how to think like a user when we try to use the new version (which has significant graphical as well as underlying changes).
edit - a bit more background:
We're writing a web app used by a widely-distributed base of users. Our app is a big part of their jobs, but not the biggest (and, of course, we only matter to them when it doesn't work). Getting actual users in to use our product is difficult, as we're geographically distant from the nearest location that serves as an end user (We're in Ohio, and I think the nearest location we serve is 3+ hours away).
The closest we can get is our Customer Service team (who have been a big help, really) but they don't really think like the users either. They also serve as our testers (it really motivates them to find bugs when they know that any they DON'T find may mean a big upswing in number of calls). We've had three (of about 12 total) customer service reps back here most of the week doing some preliminary testing...they've gotten involved in the discussions as well.
Watching someone using the app is a huge benefit to me. Possibly someone who is not entirely familiar with it.
Seeing how they try to navigate, how they try to enter information or size windows. Things we take for granted after creating/running the app hour after hour, day after day.
Users will always try and do things you never expected and watching them in action might bring to light how you can change something that might have seemed minor, but really makes a big impact on them.
Read Don't make me think.
Speaking generally, you can't. There's not any way you can turn off the "programmer" part of your brain and think like a user.
And you're right about (c), testing groups don't necessarily catch all the bugs. But the best thing you can do is get a testing group comprised of real, honest-to-goodness end users, and value their feedback. Draw further conclusions from their general comments.
If you want to know how your users will see your system, the closest you can get is usability testing with real users. Everything else is just heuristics and experience, and is also subject to error. There's no such thing as a bug-free product, but you should be able to get a "strong" product with usability testing.
Buy a cheap, easy to use video camera and record your testers using the app. Even better, get some people unfamiliar with the app. to use it and video them. It's relatively cheap, and you'd be surprised what it will highlight.
I like policy of "eating your own dog food"("http://en.wikipedia.org/wiki/Eat_one's_own_dog_food). It brings you one step closer, because you become a user, although you might think like one.
Try to use your app when you are very hurry (e.g. you have someone who waits for a dinner).
You will see all this little things because you have to wait, you have to go back to the mouse of the keyboard, etc.
And also, make your wife use it. Or your mother.
Another useful test : help someone to use it, by phone. If he can't find the button with your directions, that's probably a bug.
The important thing is to get enough information that you yourself can become a "user". Once you do that you can answer most questions yourself.
The way I always do this is to go talk with them about what they need to do, what they typically do, and how they use their current tools to do it. Then (very important) sit with them while they do it. Make sure you get on with them well enough that you can come back to them with questions about how they handle edge cases you think of later (often the answer will be the appalling "we go around the system manually for that").
I will almost always notice something they are doing that is a royal PITA that they didn't bring up because they are used to having to do that and don't know any better. I will always notice that their %90 typical workflow isn't the easiest workflow the tools provide.
You can't really rely on plain old-fashioned requirements gathering by itself, because that is asking them to think like a developer. They generally don't know what is possible to do with your software, what is easy, and what is hard. Also they typically have no clue on GUI design principles. If you ask them for design input they will just tell you to put any new control on their favorite page, until the thing looks like a 747 control panel.
The problem is often that even the users don't know what they want until they are actually working with the software. Sometimes, a small oversight can be a big usability problem, sometimes a well thought out function that was requested by many users sees only little use.
My suggestions to decrease the risk of not implementing the right usability features:
Take a look at users actually doing their day to day work. Even if they use another software or no software at all. You will be able to determine the artifacts they often need to get their job done. You will see what data they frequently need. Concentrate on the artifacts, data and workflows most used. They should be the most usable. Exotic workflows may be a bit more time consuming for the users than often used workflows.
Use working prototypes of the GUI to let users work through a realistic workflow. Watch them and note what hinders them and what works well. Adjust your prototypes accordingly.
If an issue arises in an often-used part of your software, it is time to discuss it now and in details. If the issue concerns a seldom used part, make it a low priority issue and discuss it if you have the time. If issues or suggestions are low priority, they should stay low priority. If you can't determine if solution A or solution B is the best, don't run in circles with the same arguments over and over. Just implement one of the solutions and see if the beta testers like it. The worst thing you could do is waste time over tiny issues, while big issues need to be fixed.
A software will never be perfect, because the viewpoints of users differ. Some users will think that a minor problem breaks the whole application. Others will live with even severe usability issues. People tend to lend their ear to those who argue the loudest. Get to know your users to separate the "loud" issues from the important ones. It takes experience to do this, and sometimes you will make wrong decisions, but there is no perfect way, only one of steady improvement.
If you can, set aside a certain amount of usability development resources for the rollout phase of your software. Usability issues will arise when people start working with it in a real production environment. Sometimes it is not important to present the perfect software, but to solve issues quickly as they arise.
The flippant (yet somewhat accurate) answer to how to think like a user is put a knitting needle in your ear and push really hard.
The longer response is that we as programmers are not normal and I mean that in a good way. I scratch my head at the number of people who still run executables they receive from strangers in emails and then wonder how their computer got infected.
Any group of people will in time develop their own jargon, conventions, practices and expectations. As a programmer you will expect different things from an operating system than Joe User will. This is natural, to be expected yet hard to work around.
It's also why BAs (business analysts) exist. They typically come from a business or testing background and don't think like programmers. They are your link to the users.
Really though, you should be talking to your users. There's no poitn debating what users do. Just drag a few in and see what they do.
A usability test group will help.. tests not focused on discovering bugs, but on the learning curve of the new design, made by a group of users, not programmers.
I treat all users like malicious idiots.
Malicious because I assume all users are going to try and break my code, do stuff that is not allowed, avoid typing in valid data, and will do anything in their power to make my life hell.
Idiots because again I can't assume they will understand simple stuff like phone formats, will run away screaming if presented to many choices, and will not make any leap of faith on complicated instructions. The goal is to hold their hand the entire way.
At the same time, its important to make sure the user doesn't realize you think they're an idiot.
To think like a user, be one. But are these actually bugs that your testers are reporting? Or are they "enhancement requests"? If the software behaves as designed per requirements and they just don't like the way it operates, that's not a bug. That's a failure of requirements and design. Make it work, make it rock solid, make it easy to change and you'll be able to make it what your users want.
I see some good suggestions here, especially observing people trying to use you app. One thing I would suggest is to look at the order in which things are presented to the user on paper forms (if they use these to do data entry from) and make the final data entry page mimic that order as closely as possible. So many data entry errors (and loss of data entry speed) are from them having to jump around on the page and losing their place. I did some work for a political campaign this year and in every case, entering data was made much more difficult because the computer screen did things in a differnt order than the paper inputs. This is particularly important if the form is one that can't be changed (like a voter registration form, a campaign has to use what the state provides) to match the computer screen. ALso be consistent from screen to screen if possible. If it is first Name last name on one form, making it last name first name on the next will confuse people and guanteee data entry errors.
If you are truly interested in understanding users though I strongly suggest taking a course in Human factors engineering. It is an enlightening experience.
The 'right' way to do this is to prototype (or mock up) your new interface features, and watch your users try to use them. Nothing is as enlightening as seeing a real user try to use a new feature.
Unfortunately, given most projects time and resources, this is not possible. If that is the position you are in I would recommend you discuss in the team who has the best grasp of usability, and then make them responsible for usability decisions - but that person will need to regularly consult real users to make sure his/her ideas are consistent with what the users want.
I'd suggest doing some form of usability testing; I've participated in such in the past, and found them quite useful.
If you were writing a ticketing system, for example, bring up tasks, and ask questions like "how would you update this ticket" or "what do you expect to happen if this button is clicked".
You don't necessarily need a full application, either, in some places screen shots can be used.
You could take the TDD/BDD approach and get the users involved before beta, having them work with you on refining requirements as you write your unit tests. We're beginning to incorporate some of those trends into our current project, and we're seeing fewer bugs in the areas where we have involved the users earlier.
There is no "think like a user" technique, get your hands on someone who knows nothing of the project and throw what you have done at them.
It's the only way to see how the look + feel + functionality present themselves to the end user.
Once you shocked that person who knew nothing of the product, listen to all of their idiotic (or so you think they are) complaints, fix them, arrange every silly cosmetic thing they point out (either by fixing the UI or by improving whichever documentation you had)..
and after you have satisfied the person you chose to look at your app from zero knowledge on the subject first round, pick another ...and another... until they stop being shocked when they see it, and they don't get stuck on.. "ok.. what does this do?" kind of phases.
You (as a member of the project, be it the project manager, developer, etc) will never think like a user is my answer to that question.
Old saying: You can make something "fool proof" but you can't make it "Damn-fool proof".
Additionally: When you make something "idiot proof" the world invents a better idiot.
Other than that, I agree with what everyone else said.
Ask someone with absolutely no knowledge, insight or programming experience to use the program and try to figure out every function of the program.
People who would NEVER use such a program are most likely to find bugs.
See it as a new Safari user (or FF) who tries to put the URL inside the search field...
As a programmer you guess no-one would be that stupid (or, well.. unknowing), but people actually sometimes find themselves in these situations. As a programmer, we miss these things.