The first introduction to refactoring for many programmers comes when a senior developer on the team takes a look at what they have written, yells some expletives and starts deleting blocks of code that has probably taken them days to write. After a few such incidents, these programmers start understanding what DRY means. Unfortunately, some of them do not realize that refactoring does not end with eliminating repeated code.
The goal of refactoring is not simply to reduce the lines of code, it is to make the code easier to work with in the future. This may sometimes mean writing more lines of code. You might take 5 lines of code and generate 15 lines by creating additional functions or objects. But if you have done it right, the extra lines of code will allow to write code faster in the future.
This goal is sometimes obscured when you start out with bad code written by someone else. You can achieve great savings in code by centralizing code, or replacing functionality using a third party package. In some sense, this is not really “refactoring”. It is simply fixing bad code.
When you start out with good code (as in reasonably good, but not perfect), you won’t find low-hanging coding mistakes to fix. If you want to achieve improvements in code, you will have to come up with structural changes that are deeper in nature than simple code centralization. Sometimes several files may be analyzed together to identify patterns that can be used to improve the code. During these exercises, the code size may sometimes shrink, but could also expand considerably.
But this increase in code size is not the same as the normal increase in code size due to additional functionality. Increase in size upon refactoring should decrease the mental load of the complexity of the application. This is evident when you use some package, like say JQuery. Even though you are adding several kilobytes of code to your application, there is a huge decrease in complexity combined with a huge increase in reliability. Using a third party package reduces the “in-play” code by moving some code into a black box that you would rarely look at.
Do the same with your own code. It doesn’t matter if the number of lines in your code is large (barring some performance needs) as long as the code that you look at is small. If you can write some code and ignore it forever, then it is good.
There is a related point about languages and libraries. It is good to use a concise language, but it is better to use one that has a vast collection of libraries in its standard framework or through its open source community. The more you can delegate to a library that has been tested by thousands of programmers, the less code you need to handle.