Andrew Rondeau

Software Developer, Audio Enthusiast

It’s well-known in the software engineering field that it’s hard to recruit software engineers. Once, a recruiter once complained to me that most software engineers ignored introductory emails. (In contrast, they told me that typically other professions have a much higher success rate.)

I will try to explain why most software engineers ignore recruiters.

TLDR: Most of the time, responding to a recruiter ends up being a waste of my time: The recruiter stops responding, the interview stinks, or I end up not wanting a job. The job market is too frustrating to interact with recruiters unless I am actively looking for a job.

Recruiter SPAM

I get a lot of spam from recruiters who never read my resume. These generally fall into these categories

  1. Unskilled office work that involves a computer
  2. Jobs that I am qualified for, but require relocation
  3. Jobs where I have little experience in the technology stack

In all cases, I wonder if anyone actually looked at my resume before sending me an email.

These emails aren’t “honest mistakes,” either. They are clearly widely sent out, and lead me to believe that someone is just sending out hundreds or thousands of emails without checking that the people they are sending them to are good matches.

This is a problem. SPAMming job postings to a poorly chosen audience is merely recruiters pushing their work onto others. Reviewing resumes is work, and it takes a lot of work on the part of a recruiter to find appropriate candidates. When I’m a job seeker, reviewing job postings is quite time consuming. Recruiters shouldn’t push their job into my inbox.

Unfortunately, the SPAMiness of recruitment emails makes me less likely to respond to a recruiter who has personally reviewed my resume or LinkedIn profile.

How to fix this:

  • Review the resume and/or Linkedin profile of each candidate you approach
  • Make sure the outreach email contains some personal details that prove that you’re not SPAMing
  • Only approach candidates who will need to relocate when there is a relocation package; and mention that package in the initial outreach email.

Many Recruiters Are Difficult to Work With

I’ve lost count of the number of times I’ve emailed back and forth with a recruiter, only for the thread to go cold with no response.

Some recruiters don’t understand the asynchronous nature of email, and request meetings, via email, on short notice.

Some recruiters call me while I’m in the middle of my job and expect me to drop what I’m doing to hear about their new job. (I no longer list my phone number on resumes.)

Often, it’s impossible to ask critical questions about the job.

Sometimes the recruiter’s initial email doesn’t provide any information about the job, beyond a vague location and the programming language. This is not enough information to decide if a job is worth applying for.

Many recruiters don’t know enough about software development to accurately match candidates to jobs. It ends up being guesswork for them, and it’s hard to know, when speaking with the recruiter, if I’m a good candidate.

How to fix this:

  • Never, ever, let an email thread drop. Politely end email threads when you will not continue with a candidate.
  • Assume that candidates need 24 hours, or more, to respond to any email.
  • Be knowledgeable about software development
  • Never cold call software engineers

Some Recruiters are Just Ploys to Collect Personal Information

Recently (early 2022,) recruiters started contacting me on LinkedIn about “A Software Engineering Position in Boston, MA.” Instead of providing a link to a job description, the link is for me to sign up for a hiring network. There is always a claim that, if they find me interesting, they will follow up.

I always flag these as SPAM. I don’t believe that these recruiters represent real jobs.

I will not sign up for any website merely to read a job description. I also don’t want to join another career network. I’m already on LinkedIn and get plenty of emails outside of LinkedIn.

Recruiters don’t know “The Rules”

In general, the way that hiring a software engineer works is:

  1. An introductory phone call with the recruiter or hiring manager; or both
  2. A technical screening. This used to be a phone call, but it’s now evolved to use a web-based coding platform or screen sharing
  3. A full interview

The purpose of the introductory phone call and technical screening is to ensure that there is mutual interest between the candidate and company; that the candidate is competent; and to confirm that the candidate has required technical background. Bypassing these (introductory call and screening) ends up wasting a lot of time, because for software engineering, most candidates fail. Either there isn’t mutual interest, or the candidates fail the technical screening.

I’ve encountered a few recruiters who ignore “the rules:”

  • In one case, the recruiter claimed, “we don’t get phone calls, we get interviews.” The “interview” was no different than a phone screen, and wasted my time due to travel.
  • Another time I worked for a company where HR didn’t know “the rules” and scheduled day-long interviews with incompetant candidates. We could have saved these candidates their day off with a simple phone call.

I’ve learned to keep these kinds of recruiters on a short leash, and either walk away or disengage.

How to fix this:

  • Be familiar with general industry best practices in hiring
  • Don’t bypass critical parts of the hiring process: Determining mutual interest and introductory technical screenings save everyones’ time

I Won’t Move

Many recruiters approach me for jobs with absurd commutes, or for jobs that require that I relocate.

I’m no longer in my 20s, no longer single, and unable to move whenever I want to.

I live in a home that I built with the intention of living in it for a long time. I’m married to a wonderful wife who has her own career, I have kids, friends, and extended family. We aren’t going to move every time I change jobs.

I’ve been a telecommuter, with occasional office visits, since 2014. It’s worked out great, and the situation works out great for many other software engineers. When I see that a company is hostile to telecommuting, I interpret it as having control issues, or a desire to babysit.

How to fix this:

  • Make sure to map out how long it will take a candidate to commute to an office. (Google Maps lets you estimate travel time during different times of the day.)
  • Make sure to acknowledge if a candidate will have to move, or have a commute longer than 30 minutes
  • Explain telecommuting policies / relocation packages in the initial email
  • Explain to employers that hybrid telecommuting is needed to widen the search radius to engineers who live too far away to commute

The Pay is Probably Low

Software Engineering salaries are all over the place. I generally assume that most recruiters reaching out to me are trying to hawk lower-paying jobs.

With few exceptions, I will only pursue a job if I believe it will be a ~20% pay increase from my current job.

Software is an economic multiplier: I once heard that my 4 month project saved a company a million dollars a year. Because the software I write has substantial economic value, I expect a fair portion of the rewards.

How to fix this:

  • Only accept recruitment jobs that are at or above median pay
  • Give a salary range in the initial outreach email
  • Remember that software is an economic multiplier

Interview Prep and Take Homes are Time Consuming

I have firsthand experience interviewing candidates for software engineering positions. It’s greuling. A big problem, when hiring, is that most candidates who come into the interview aren’t capable of doing the job. Even worse, when we hire the wrong person, the situation becomes more frustrating and grueling than the interview process.

The industry handles this by attempting to carefully screen candidates, often through a series of take home exercises, detailed technical exercises to perform in the interview, and extensive interview preparation exercises.

Interview preparation and take-home exercises compete with the time I have for my family and other commitments. Interviews during business hours require that I fib to my current employer about my whereabouts.

How to fix this:

  • Make the job appealing before I need to invest precious time
  • Have me meet with the hiring manager on the phone or videoconference before time consuming activities
  • Make sure to explain this process in the initial contact email

The Company Probably Rejects Most Candidates

This isn’t something I admit that often.

Software engineering interviews are notoriously fickle, for so many reasons that I could write another article about all the problems I’ve encountered interviewing. In summary, for every good interview I’ve encountered, I’ve also had poorly explained questions, questions that require that I know some obscure algorithm, or interviewers who want to prove that they’re smarter than me. Sometimes I wonder if the interviewer has some bias.

When interviewing candidates, a common piece of wisdom is to reject when in doubt. I’ve interviewed a few “maybes” that I rejected. This is because it’s easier to “move to the next candidate” instead of putting up with a bad hire. I’ve also seen hiring an excellent candidate fall through because the hiring manager screwed up the process.

Aside: We really need a Credentialing Process

Many professions have a credentialing or licensing process to smooth over situations like this. My wife is a pediatrician, and the jobs she sees posted can only be applied to by credentialed pediatricians. She does not have to prove competency during the interview process.

Compared to interview prep, take-homes, or complicated interview questions, I’d much rather get credentials. It’s a better time commitment to earn credentials that I can use for any job interview; and it works out for the company’s favor because they don’t have to figure out if I’m competent.

How to fix this:

  • Try to find some kind of a proxy for credentials
  • Recruiters: Develop your own technical screening process so you can screen a candidate once and let them interview at multiple companies

I Might Not Like the Job / Company

Job interviews are a two-way street; I’ve bowed out of a few job interviews because I believed I wouldn’t like the job. Unless I’m desperate, I’m not going to risk leaving my current job if I have any suspicion that a job I’m interviewing for is going to be a difficult environment.

How to fix this:

  • Carefully screen the hiring managers that you recruit for

Conclusion: Let’s talk the odds

When Syncplicity hired me, my manager told me that they phone screened 100 candidates, interviewed 10, and I was the first one they were comfortable hiring. (I then went on to make us an industry leader.) In my experience, this was accurate. We rejected many candidates on the phone screen, and many on the on-site.


  • Fail the interview: There is a 1% chance of getting an offer from a phone screen with a manager
  • Recruiter drops the ball: There’s a high chance a recruiter won’t respond back to me
  • Won’t accept the offer: There’s a high chance I won’t like the job, or the pay will be too low

Thus, in my estimation, responding to a recruiter outreach has less than a 1% success rate for landing a job. It’s a fool’s errand.

That’s why software engineers don’t respond to recruiters. We have better things to do!

This blog entry is a response to a question I got in a stack overflow post: How to get non-current thread's stacktrace? [In C# / .Net] Specifically, I was asked if there were alternatives to the originally-obsolete solution:

The author of the solution, who also writes the renowned LINQPad, recently revised his answer. I'd use care with following Joe's suggestion in shipping code, because what works correctly in a tool like LINQPad may not be appropriate for the environment that your application runs in. Specifically, Joe's suggestion may not work in the various sandboxes, non-admin, ect, environments that .Net applications frequently run in.

A bit about my background. For almost a decade I was the desktop client lead for Syncplicity, a file synchronization product similar to Dropbox, OneDrive, and Google drive. While I led the desktop client, we were the most performant and scalable product on the marketplace. The desktop client was a highly multi-threaded C# desktop application. I have quite a lot of experience developing and debugging multithreaded .Net applications.

I'm assuming the person who asked me for alternatives to getting another thread’s stack trace wants to log collect debugging information; or otherwise needs to fix some threading issues.

Is the Stack Trace for Logging?

I wish in .Net that it was very easy to get another thread's stack trace, because then it would be significantly easier to diagnose certain kinds of bugs like deadlocks and other situations where a thread is blocked. Then it would be easier to include defensive “bug detector” code to log what a thread is doing if it holds a lock for too long! Depending on your application's environment, you can't always create a process to obtain a stack trace.

Unfortunately, the quick answer to “are there alternatives”, is that a multithreaded application needs a good logging strategy. The logger should always include the thread name, and thread ID. If you use async code, include Task.CurrentTaskId. Multi-server applications will also need to include the process ID, and the server instance number. Log4net can be configured to include these. Do not configure the logger to include stack traces, except in controlled debugging environments, because logging stack traces in every logging statement incurs extreme CPU overhead and performance will suffer.

When examining logs, filter based on the thread ID, or Task.CurrentTaskId for async code. (And filter on machine ID and process ID for distributed code). This will provide a sequential list of each logging event from the thread. It may be necessary to add logging statements in troublesome areas of code to give yourself hints about what to search for in your logs.

It may be occasionally useful to include a stack trace (Environment.StackTrace) in carefully selected logging statements. Consider restricting logging stack traces to either debug builds or via some kind of a configuration setting. (Remember, logging a stack trace incurs a high performance penalty.)

Important: Any kind of logging, especially stack trace logging, will change timing of race conditions and deadlocks. Assuming that your bug is some kind of a threading issue, the logging you add could trigger a “Fermi's paradox” situation where you either reproduce the bug more, or less frequently, based on how you log!

If you are directly creating threads, it's very useful to name your threads, and include the thread name in your logs. This makes it very easy to track down the specific thread in your log.

If you are able to reproduce your problem when running your code inside of the Visual Studio debugger, when you break into the debugger, you can see a list of all your threads (and tasks). This also allows you to see each thread's stack trace! (Yay!) Assuming that you're logging the thread ID (and/or task Id), it should be very easy to find the specific thread that you are trying to debug.

Some Other Helpful multithreaded Techniques

If you are having problems with deadlocks or general threading issues, here are some additional strategies:

  • If you have a critical method that has a lot of callers, and could block for too long, add a string argument to the method. Give each call to the method a unique name. In your method, set a timer to log the string if the call takes longer than what you consider reasonable.
  • Encapsulate your shared state so that it is prohibitively difficult to access it outside of a lock. For example, your shared state could be encapsulated in an object that is only accessible through a lambda. Then the object should have protections that prevent calling it from a different thread or holding on to the object outside of the lambda.
  • Take the time to learn about programming with immutable values. If you have shared state, but the object itself is immutable, then it's safe to read from any thread without a lock. (Your code still needs to handle stale state.)
  • If you are having problems with deadlocks, consider replacing the lock keyword with a pattern that includes timeouts. These exceptions can help you diagnose deadlocks, or at a minimum, allow you to gracefully recover from such a situation. For example:

Don’t Make Novice Mistakes

Now if you are trying to get a thread stack trace because you need to communicate among threads or wait for a thread to get into a particular state…Well… That's a novice mistake! (And depending on what you're doing, it might be time to admit you've gotten over your head!) Locking, monitors, wait handles, task completion sources, queues, fibers, mutexes, semaphores, critical sections, and other ways of coordination among threads are advanced programming techniques. Although I encourage you to learn, I really do recommend that you have a couple of years experience under your belt, or be in a more advanced computer science class, before you do multi-threaded programming in a professional setting.

Ok, but, really, is there a way to get another thread’s stack trace? (Without creating another process)

But if you really need to get another thread's stack trace at runtime when you don't have a debugger available, this is prohibitively difficult. I will try to explain why to the best of my ability.

I'm going to assume that you know a decent amount of multi-threaded programming, and that sharing state, specifically data structures, among running threads is very difficult. One thread just can’t safely read another thread’s data structures unless they are designed to be thread-safe; or locking is used. Often, allowing one thread to read another thread’s state incurs a performance penalty. An experienced software engineer can weigh the performance trade-offs of different approaches, such as locking versus lock free data structures. It's my professional opinion that designing .Net’s stack so that a stack trace can be read in a non-blocking manner will cause a prohibitive performance degradation to the entire .Net framework.

This is why a thread needs to be suspended in order to get its stack trace from another thread. Why calling something like Thread.Suspend is problematic is more difficult for me to explain, because I have never worked with the internals of .net and the operating system. This response probably explains it best:

I do suspect that a very talented programmer could figure out how to modify .Net to allow getting other threads' stack traces at runtime without relying on an additional process. (After all, the garbage collector does walk the stack!) It would be very interesting to hear from one of Microsoft’s developers to know if this is feasible, and what kind of tradeoffs this would incur.


So there you have it: Use a logging strategy that includes information about each thread. Try to reproduce the bug inside a debugger, because the debugger will give you the stack trace of all threads. Make sure you have the experience to implement multi-threaded programming correctly. (Or be willing to admit that you've gotten over your head.) Given that .Net’s garbage collector walks threads’ stacks, I do wish that .Net allowed getting another thread’s stack trace for diagnostic purposes.