Review of Dale Carnegie’s “How to Win Friends and Influence People” for programmers

Programmers and IT people are often shunned for being shy, timid, fearful, or just in general – we are being thought of someone who have no social (soft) skills. If you can in any way identify with this sentiment – you definitely would be rewarded deeply for reading this book and implementing the suggested tips in your own life. But let us start at the beginning – who is the author, who is he known for, and so on, and then I will tell you why you should deliciously digest this book.

First of all, Dale Carnegie is an innovator of a new genre of books that are called “self-help” books these days. Such books feature short chapters with a life lesson at the end of them. This makes it very approachable for programmers who might have a short attention span or not have much energy, or time after programming for the whole day. It is worth mentioning that Carnegie was so popular and known that even Warren Buffett, a well known businessman, used to hang (or still does) on his wall a certificate that he finished his courses when Carnegie was still around. So if it appeals to people like Warren Buffett very much, it would help you a lot as well. Let me introduce to you a few chapters and tell you how they would help you.

Foremost, being proficient in negotiation tactics is a very useful and critical skill for everyone, not just salesmen and managers. We, as programmers, are sometimes shy, undervalue ourselves when looking for a job and do not ask for a proper wage. This work of art will help you get rid of that imposer’s feeling. I think that understanding the critical people skills presented in this publication and implementing them in your real life will deeply change your understanding of human interaction mechanics. Negotiation is essential when you are trying to make another person think like you. This is why Carnegie aptly named a chapter “Twelve Ways to Win People to Your Way of Thinking” which is dedicated to teaching you methods how to achieve this goal. For example, you probably never thought about the technique to “let the other person feel like that idea is his or hers”. Presenting an idea to someone like it was thought by themselves makes them more likely to accept it because that person feels like it is theirs. There are even 11 more ways presented in “How to Win Friends and Influence People”. This kind of advice is what makes this book great and they are all useful to you as a programmer. Hopefully, learning them will give a rise to having your wage substantially increased.

Furthermore, one thing for sure is that programmers are notorious for being egoistic. I feel that this book teaches how to be a humble, understanding, and a thoughtful person. It strongly encourages to be honest and always consider all problems or thoughts from the perspective of the other person. For example, in part 2, “how to make people like you”, Dale Carnegie specifically wrote a chapter which specifically inspires you to become a good listener and encourage others to talk. Author argues, I agree and you probably too with the assertion that people like talking about themselves, about their hobbies, about their days and so on. You cannot win a person’s mind to your way of thinking without listening to them and making them feel good. Or in other words, “don’t kick over the beehive if you want the honey” which is another quote from other chapter. Thus, this book will help you kick out the bad habits that we usually have as programmers.

Not to mention the very simple, understandable English used in the book. It appeals to the layman so it is especially approachable to anyone. In general, this piece of work is not philosophic, don’t need to think much – you ought to just apply the principles explained in the book. However, it might not be for you if you are looking for deep discussion about why people behave in one or other way and about topics such as sociology. The courses organized by Dale Carnegie himself were attended by all kinds of people – from salesmen to ordinary plumbers so it had to appeal to the lowest common denominator which is that they were all normal, hard-working people who are looking to improve their social skills to furthermore reach a bigger point in their careers or to become leaders in their respective fields. Personally, I think that this perfectly OK for books like these and reduces the list of reasons why you should not read this book by one more thing.

On the other hand, obviously not everything is rainbow and roses. This book has some downsides too. I thought that some examples were seriously out-dated and not applicable to the current world. For instance, in part one, “fundamental techniques of handling people”, an example is introduced of a “famous” quarrel between the two USA presidents Theodore Roosevelt and William Howard Taft. It really isn’t known at all anymore, especially it is not known for people who do not live in the USA and this just makes the reader feel like they are missing some details. Moreover, some reviews on other sites say that the examples are so bad that it is only worth reading the “in a nut-shell” sections at the end of each chapter. But I don’t think they are that bad – some of the examples are really great and illustrate the point that the author is making very well. Also, some advice seemed repetitive and just presented from the other perspective. Exempli gratia, in part three Dale Carnegie says to “Be sympathetic with the other person’s ideas and desires”. It is similar or almost identical to the advice given in part two: “Be a good listener. Encourage others to talk about themselves” . I think that being a good listener already involves sympathizing with the person that you are having a conversation with. You could find more examples of these issues. However, they are not very noticeable and do not distract from the main ideas of the book.

All in all, it is a great book for programmers. But just because of the negatives that I have listed, I would rate it a shining 9 out of 10. You would not waste time by picking it up as your next read and it would greatly influence your person character development to the positive side. With programmers becoming more and more equal in skill, the people skills are what makes someone shine. This may sound like an advertisement but you should not hesitate and pick this book up whenever you can in the future. It is one of those must-reads. If there is one thing that you will definitely take away from this book is that you will learn how to emphasize with your conversation partner and generally improve your manners.

Making Unwinding Functions in C Simple: Do Not be Afraid of Using Gotos

Intro

Today I wanted to talk about unwinding and releasing resources in C functions. Let’s begin by stating that there are three main techniques for handling errors in the C programming language. Sometimes more than one technique may be used. Here is a list of them:

  • You must test the value functions return. Abnormal value indicates that some kind of error has happened and a normal value indicates that it was successful;
  • There is an external variable whose value you must check. For example, the POSIX variant of this is to have an variable called errno that changes to 0 when nothing bad happened and it has some kind of other value when an error occurs;
  • You pass a pointer to a function. The function changes the value of the variable it points to or even calls it with certain arguments if it is a function pointer depending on the result.

I have not mentioned one method but some people use atexit(3) to register functions that will be called at the end of a program which will release resources. However, this is unusual so I have not included it in the list.

This is very much related to our topic because when an error occurs, you will have to handle it. That process includes releasing the resources which were acquired before in the function. Especially if you are deep down in your function and then an error occurred, the choice that you make in how to release the resources will matter a lot so it is important to make the correct decision.

In C++ you have the destructors and so on but how are you going to do that in C?
Are you going to sprinkle all of your error paths with:

free(foo);
free(bar);

and so on? It might be your first choice to go down this route but I think a viable and preferred alternative to this is using gotos and labels. Obviously, they should be used very cautiously. It is a very powerful tool so there is a lot of peril involved and ways to abuse it so you have to be absolutely careful. For simple cases when you don’t have to release any resources a plain return works well but it is a different situation with multiple resource acquisitions. Compared with other methods, using gotos doesn’t force you to duplicate the error paths, the code distracts less from the normal path, and it is more readable. You can’t imagine how this could be true and you cannot believe me? Let me prove to you that you should use gotos in these more complex situations!

Tutorial: using gotos for cleaning up

First, you should begin by naming the goto labels according to the resources that it frees. You want to be able to discern which resource exactly is going to be freed. Also, because goto labels may be used for other purposes other than resource clean-up, it is a good idea to prefix the goto labels with “err_” to indicate that its purpose is for releasing resources when an error occurs. Due to the fact that you will have different labels for different resources that they release, they should only contain one statement after it before the next label or the final return, and only do what it actually says.

Some good examples of names: err_release_view, err_free_list, err_close_lsocket, and so on.

Order the labels in such order that resources which are acquired first are at the bottom. The order of labels which release the resources should be in the inverse order of which they were acquired.

Now whenever an error occurs, use goto to jump to that label which will release the resources that were already gotten. As a rule, you can remember this: always jump to that label which releases the most recently acquired resource. This rule makes it easy to remember.

It may remind you of the defer mechanism in Go and other programming languages where the programmer can specify a list of functions with certain arguments which will be called as soon as the function goes out of scope. We are essentially emulating the same thing with gotos. Just that the C version requires a bit more attention and carefulness.

Example code comparison

To show how readability could be improved by using this method I will present one function from the Linux kernel source code and how it was changed. This function was improved courtesy of Tobin C. Harding. Thanks!

Here is the first version which does not use gotos at all:

static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p, unsigned long size, void (*complete_handler)(void *arg1, void *arg2), void *arg1, void *arg2)
{
  struct tx_device_buffer *sp;

  if (priv->dev_state < DEVICE_STATE_BOOT) {
    kfree(p);
    if (complete_handler)
      (*complete_handler) (arg1, arg2);
    return 1;
  }

  if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) {
    /* in case of buffer overflow */
    DPRINTK(1, "tx buffer overflow\n");
    kfree(p);
    if (complete_handler)
      (*complete_handler) (arg1, arg2);
    return 1;
  }

  sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qtail];
  sp->sendp = p;
  sp->size = size;
  sp->complete_handler = complete_handler;
  sp->arg1 = arg1;
  sp->arg2 = arg2;
  inc_txqtail(priv);

  return 0;
}

The version with goto:

static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p, unsigned long size, void (*complete_handler)(void *arg1, void *arg2), void *arg1, void *arg2)
{
  struct tx_device_buffer *sp;
  int rc;

  if (priv->dev_state < DEVICE_STATE_BOOT) {
    rc = -EPERM;
    goto err_complete;
  }

  if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) {
    /* in case of buffer overflow */
    DPRINTK(1, "tx buffer overflow\n");
    rc = -EOVERFLOW;
    goto err_complete;
  }

  sp = &priv->tx_dev.tx_dev_buff[priv->tx_dev.qtail];
  sp->sendp = p;
  sp->size = size;
  sp->complete_handler = complete_handler;
  sp->arg1 = arg1;
  sp->arg2 = arg2;
  inc_txqtail(priv);

  return 0;

err_complete:
  kfree(p);
  if (complete_handler)
    (*complete_handler) (arg1, arg2);
  return rc;
}

As we can see, the code is much more readable and the two error paths are not duplicated. The judicious use of gotos avoids the perils of producing spaghetti code. Also, don’t worry: this not the only case. The Linux kernel source has an uncountable number of such examples. It makes the code much more readable once you get used to this convention. Not to mention that the Linux kernel is one of the biggest, most complex C projects around. So you know that the developers wouldn’t make a decision to use such code constructs which would increase the complexity of the code even more.

One more thing – this cleanup code is simple and clean but imagine a situation where it is much more complex. What if something extra was done in the error path if, for example, closing a socket failed and some extra sub-system had to be informed or some other actions had to be performed? That would be quite some extra code in each path. In this case, the goto method would be so much more attractive.

Conclusion

Using gotos in your C code to clean up after errors have occurred is similar to the defer mechanism in Go. Having clean-up code in one place which may be called completely gets rid of code duplication in error paths. This in part makes the code more readable because the reader won’t be distracted by the error handling code which could possibly obscure the real path. Also, there is less possibility of errors because potentially much less code is duplicated. The gotos can be abused easily so you should be very cautious and follow the tips given in this article.

Bonus: your compiler might have an extension to help out with this

Some C compilers have extensions which help with resource cleanup. For example, the popular gcc supports the cleanup attribute which applies to variables which have automatic storage duration. If you apply this attribute, gcc will run a function with that variable as the argument. Any return value is ignored. Example usage:

void cleanup_free(void *p)

{
  free(*(void **)p);
}




void foo(void) 
{
  char __attribute__((cleanup(cleanup_free))) *bar;
  bar = malloc(128);
} 

This extra function is needed because if ordinary free(3) would be written then it  would receive a char** and, obviously, free(3) doesn’t know that it should be dereferenced one time first. If you compile this function and run it with valgrind then you will see that no memory was leaked. This is also useful with close(2) and other similar functions. However, there is one downside – if you want more granular control of what happens if, for example, close(2) fails then it is impossible with this because any return value is ignored silently.  Check out your compilers’ documentation if there is support for this kind of thing. Obviously, you should consider the alternative of writing portable code first.
Please comment if you find any errors or just want to discuss this.