2014-04-21

Oh, I love fast and simple text editors. Being a Linux user, I lived years in the company of Kate and KWrite. With some tweaks and plugins I could make them really smart. I wrote whole projects in Perl, Bash, and even some PHP and Java in those editors. I can appreciate all the enthusiasm going around Sublime Text or TextMate, but I could not live without a full blown IDE today.

The Culture

I observed that there are two kind of programmers. The first kind has a tendency to use applications that can offer greater and greater code manipulation productivity but at the cost of the abrupt learning curve and difficulty in use. These programmers are the ones who prefer Vi(m) or Emacs.

The second category of programmers tend to migrate from simple editors to IDEs. This is as natural of an evolution as the first category. However, it leads to a different mindset and different view of the project and the code. I am a programmer from this category so in this article we will talk about the IDE I use at the moment: PHPStorm.

Tools and user preferences for applications are so volatile that I rarely write about a specific framework or application. However, if you use an application 10-14 hours each day, it becomes part of you, part of how you see your code, your projects. It becomes the highway for your day to day workflow. So it deserves to be mentioned and presented.

So, What's the Difference?

I used to bring up a fast text editor when I needed to code only a short script or program. But I don't anymore. Today's computers and IDEs are so fast that there is little difference between starting PHPStorm and writing the code or starting KWrite and writing the code. The application itself is almost as fast as an editor, and creating a project, even for one or two actual files is nothing slower that doing the same file creations in your editor.

OK, OK... These are all similarities. But what is this IDE thing all about? IDE comes from Integrated Development Environment. This expression has two key parts: integrated and development environment. The development environment part can be seen as the editor and the specific features for source code manipulation: code writing features, highlighting, auto-complete, complex editing features like multi-select and multi-edit, refactoring tools, and so on. The integration part can be seen as integration between the development environment described above and various external tools, testing frameworks, document versioning system, debuggers, and UI builder tools.

The key feature of an IDE is its understanding of the code you write. An IDE doesn't just have a list of command you can use in your favorite language, like PHP. It has complex algorithms to understand your code. PHPStorm will not suggest you a command or expression that would be syntactically incorrect. It knows, for example, that you can't write "print('Hello World');" directly inside a class, without putting it into a function. So it won't suggest the "print()" command when it can not be used. But this is just the tip of the iceberg. Let's see some more concrete examples.

Using PHPStorm for the Refactoring Legacy Code Tutorial Series

Yes. If you've read the first two parts of the Refactoring Legacy Code series, The Golden Master and Magic Strings & Constants, you may have observed that there are screenshots shown in the tutorial with an IDE. That is how my PHPStorm looks like. And the following is how PHPStorm helps me, when teaching you to program.

Code Highlighting

This is essential. Most simple editors can also do basic code highlighting, but an IDE is a different story. Here you can have different highlighting setups for different languages like PHP, HTML, CSS, and so on. Each with it's own rules. For example, I like to have strings green in CSS and orange in PHP and HTML.

On the left, you can see all the supported file types and languages (some may be added by plugins), in the center you can see the various PHP language elements that can be configured separately, in the top-right are the options each element can have, and at the bottom there is a preview.

When we were hunting for magic strings in our refactoring session, we were able to easily spot these strings by just finding orange stuff on the screen. The same is true for magic constants and numbers. When those were sought for, the blue color was our friend.

Structure and layout is essential when we need to understand source code, and proper coloring and highlighting is essential in this matter.

Refactoring Tools Overview

I've used many IDEs and editors throughout my career. The one that I really liked and appreciated was NetBeans. But after about five years of exclusive NetBeans usage, I had to give up on it. There is something PHPStorm can offer, that no other editor or IDE for PHP can do. This is a set of refactoring tools that are so needed in our day-to-day work.

Highlighting, indenting, project management, templates, macros are all features found in most editors. Integrations with testing environments and debuggers are by definition part of any IDE. However, smart and complex refactoring tools are a totally different story.

As programmers, we spend half of our time reading code, about 40% modifying and refactoring existing code, and, if we are lucky, really lucky, 10% writing totally new code. So having good, fast and reliable refactoring features will help us concentrate our efforts more on what to refactor and less on how to do it. We will save time also, but I consider the gain in less-effort to be much more important. When you can discard the thought about the process into your IDE, and only think about the logic, algorithm, dependencies, SOLID principles, it is a gain in productivity that must be considered.

This is why I left the free and open source NetBeans for the payed PHPStorm. There is, in PHPStorm, a set of refactoring tools that makes it special, makes it worth paying for.

Introduce Local Variable

One of the simplest refactorings we've already worked with in Magic Strings & Constants was Introduce Local Variable, also known as "Extract Variable". Here is a reminder with the steps we need to take to use this refactoring:

Add a variable with the desired value.

Find all usages of the value.

Replace all usages with the variable.

These steps are easy to follow if we have a single value to be transformed into a variable, but what about step two? How do you reliably find all occurrences of that value? You need to analyze your code and take conscious decisions of what to replace and what, not. Here is an example.

In printAPairOfPlayers() we can observe that the string "Player name: " repeats twice. If we want to extract that string into a local variable, a variable inside the function, we will need to replace both occurrences in printAPairOfPlayers() but not the one in printOnePlayer(). If printOnePlayer() would be 100 lines below, we may not even realize that there is another duplication of the string in another method.

So we want a local variable. We first create the variable, run the tests, then look for the string and find it in the second echo statements. We replace it, run the tests, we look again, we find it in the last echo statement, we replace it, we run the tests. We look again, we reach the end of the method. We decide we are done with our extract local variable refactoring. This is quite a demanding cognitive process, especially with ugly and not well understood code.

Wouldn't it be useful to press a single shortcut, or select an option in a context menu and have all this done by the IDE? It would be awesome, and PHPStorm is quite capable of doing it for you.

In the code above, just position your cursor inside the "Player name: " string anywhere and Right click.

After selecting "Extract Variable...", PHPStorm will analyze your code and search for various pieces of code you may want to extract. It will propose two possiblities for our case.

Now that the piece of code we want to extract was identified, the next step is to name it. "playerHeadersString" seems a sensible variable name. You do not have to put "$" in front of the name in the input field. PHPStorm will put it in the code for you automatically. Another important aspect is that there is a checkbox. PHPStorm found all the occurrences for our variable. We selected to extract a local variable, so PHPStorm knew to search only in the current method and it found only two occurrences. The same string in the method printOnePlayer(), was not counted, nor proposed, and it will not be replaced. That would lead to incorrect code, and PHPStorm is smart enough to not write invalid code for you.

Less Tests

Another advantage of PHPStorm is that you don't have to run your tests often. When we did a manual refactoring we run our tests after each step. If we did a typo or replaced something that we thought was the same but in reality was not, we needed a safety net to quickly tell us so. However, PHPStorm will not replace something that is not logically correct in the context. You may be surprised that a piece of code you also expected to be extracted will not be, but at least you can be sure the resulting code will be correct. Plus, we have less steps. Manually, we do only a single step. After that single step we need to run our tests a single time.

It doesn't matter how you look at it, it is easier, faster, and much less error prone than any other way to do the refactoring.

Extracting Class Variable

To extract our string into a class variable - also known as class field - we can use the "Extract Field" refactoring option from the same menu as above. We will be asked to identify the piece of code we need to extract, and we will be presented with a slightly different form.

Besides its name, we now have three found occurrences. PHPStorm knew we wanted a class variable and it was capable of identifying the same string where needed. We also have options to initialize the variable in various places and set its visibility. By selecting the options as in the image, the resulting code will be as below.

Of course, if you want it to be public, or initialized in the constructor, all you need to do is just select the appropriate options and let PHPStorm do the work for you.

Context Dependent Variable Initialization

When you extract a variable, you want to initialize it to as close to its first usage as possible. In most cases, this is simple, especially if there is a single use of the variable. But what about more complex cases? Let's revisit one of our variable extractions from Magic Strings & Constants.

In the roll() method, on line 73 - the one selected - there is a number "11". It is a magic number we just identified and we want to extract it.

If we do our extract method by hand, we need to follow these steps:

Define a variable just above that line with the value 11.

Run the tests.

Exchange the value with the variable.

Run the tests.

Search for another occurrence of the number 11.

Identify it at line 90.

Replace the value with our variable.

Rung the tests. They will fail.

Ask yourself where to put the initialization of the variable so that it is working and still as close as possible to its usage.

Move the variable initialization one level up.

Run the tests. They are still failing.

Move the variable initialization one more level up, outside of all the if statements.

Run the tests. They are finally passing.

You search for other occurrences.

Find no more. You are done.

Now, that is complicated for a human to do. And it is error prone. We presumed you have tests that can help you out, but what if you are working on some obscure untestable code? PHPStorm will understand the context of your code. It will correctly extract the variable for all occurrences and put it exactly where it should be.

The Iceberg Under the Tip

What we presented above about refactoring tools, is just the tip of the iceberg. Extracting variables is probably the simplest and easiest refactoring you can do. We did not yet use extract method or extract subclass or even some more complex renamings in our refactoring lessons, but we will. We'll learn how to do them by hand, but I will encourage you to use a smart IDE to do the job for you.

Renaming

PHPStorm is very good at renaming variables or methods even across hundreds of classes. Imagine how difficult it would be to change the name of a public method used in 100 different classes in your project. PHPStorm can make that a five minute job instead of a two hour job. It can find and change the name of all the methods and you will only need to check for miss-matches before you tell it to act. 

Yes, yes... You will need to verify some found occurrences because PHP is a dynamically typed language and in some cases, there is just no way PHPStorm, or any other IDE's algorithm, or program for that matter, can know what type of object is used for that specific method call. Imagine, you have two totally different classes. On each of them, you have a public method called "findAll()". This is very common and correct. 

Why Do We Need to Evaluate the Changes?

Now, there are 50 classes using your first class and another 50 using the second one. If you used proper interfaces and type hinting where possible, PHPStorm will propose the correct classes to change. But if you did not specify the type you use, or you did not use any interface implemented by your class with the findAll() method, there is no way to tell automatically, which of your two classes, both having a findAll() method, will be used. That is the essence of PHP's dynamic typing. But while this is an advantage in some cases, it is a disadvantage when we need to do refactoring like this. When this happens, the only thing that can be done is for a human to evaluate the need of the change.

With all these, even though there are other refactorings present in PHPStorm, it is already the best IDE just with refactorings. Renaming, extracting and inlining variables, extracting and inlining methods are the most frequently used refactorings we do each day. If these are working great, we have a winning IDE.

But PHPStorm doesn't stop here. It has a lot of other refactoring tools which make you feel good in difficult situations. It truly has that "cherry on the top" feeling.

Testing and Code Coverage

You do TDD, right? If you don't, you should. Testing is as essential for programming as writing the production code itself. I could not imagine my life without TDD. I've got so used to it in the past few years, that even thinking about code without thinking about the tests feels unnatural and difficult.

Testing & IDEs

With testing, your process and tools need to be just as good as the production code itself. PHPStorm has great integration with PHPUnit. It is the only PHP IDE I know of that actually links directly to the PHPUnit framework, extends it and uses it to gather all the information that needs to be presented. This gives it a much more intimate connection with PHPUnit, a better output for the user and much higher test running speeds.

Other IDEs tend to just use the PHPUnit executable, write the output into an XML file and interpret the results to show it to you. This is how NetBeans works. This approach offers higher flexibility for you, the user, if you want to hack the system and convince it to run your tests in unusual ways (for example over telnet or SSH). But this also has a huge disadvantage. Things become slow. First of all, a shell process needs to be forked. "exec()" is always an important time consumer. Then the result needs to be written to a file, possibly on a remote machine. 

We all know that the file system is slow, very slow. SSDs are making it a little better, but they are still light-years away from the speed of RAM. Then, if we run our tests remotely, we need to copy that file over to our machine. So not only do we need to hit the file system once, we also need to add to that time, the cost of network communication plus writing it to a local file. Then the file needs to be read back, so that it can be finally shown to the user.

While that is a super customizable and flexible solution, it just takes time. Too much time when we think about unit tests and millisecond tests. And unit tests that take longer than five milliseconds to run are not unit tests any more.

PHPStorm Uses PHPUnit Internally

PHPStorm solves, or at least reduces, the overhead by using PHPUnit internally and telling it to output the result in the way preferred by PHPStorm. This reduces flexibility. You can't hack it to test outside its limits. But, it increases speed a lot. No more exec, no more files written to slow file systems. Remote execution may add the price of network communication, but we can't eliminate that anyway. Another nice advantage is that directly using PHPUnit allows more detailed information about failed tests to be presented in a more organized way. So we gain on speed, details, and clearness at the cost of flexibility.

Being used to NetBeans, I found it hard at first, to accept this inflexibility, but at the end of the day, even if sometimes I have to run an external script to test my code on remote machines, the gains from the better PHPUnit integration are prevailing.

Organizing & Searching for Files

Like most IDEs, PHPstorm is also project oriented. Usually in a project you can have source files and tests. As PHPStorm works, it requires you to specify one single folder as the folder for tests. I find it quite useful to have the same directory structure between source code and test code. This also helps PHPStorm to find your tests more easily and allows you to switch between production code and tests with a single shortcut.

But that's not everything. When it comes to finding and opening files there is a unique feature in PHPStorm: Go to Everything (or Search Everything) - I absolutely love this one. First of all, its default keyboard shortcut of Shift+Shift (double shift) is so natural to use, secondly, it is the most useful navigation feature. It was only recently introduced, and before it, we had separate navigation boxes and shortcuts for open file by name, open file by class name, open file containing the symbol (variable or method name) and so on. Now I can just double shift and start typing. It's amazing and fast.

Final Thoughts

There are so many cool features in today's IDEs that we could continue with this story for another three tutorials and still not tell all of it. But we need to stop at some point. So as a great finisher for our mini-marathon of PHPUnit features within PHPStorm, here are a few last ones that my colleagues and I at Syneto appreciate:

Live Templates - they are great for writing boilerplate for you. For example, when I write these tutorials in HTML I need to respect a specific set of tags and formatting. I have nice little templates that can write that for me, so the time spent adding an image to the tutorial, for example, is reduced to about the time it takes to hit the keys, instead of writing the whole image syntax and styling.

Project Management - this is quite common in IDEs. All your files are organized in projects. But the programmers at JetBrains did something very amazing. Their indexing engine is fast as hell. No other IDE could load our huge project at Syneto so fast and then search in it so fast. In fact, IDEs like NetBeans or Eclipse and its derivatives mostly failed to index the whole project. That made searching very slow. PHPStorm does this right and things are fast compared to any other IDE.

Document Versioning Integration - is another gem in the bag. Mercurial, Git, CVS, Subversion, you name it. PHPStorm feels at home with all of them. From selective commit and push through advanced merging, with a great diff and merge tool, to branch graphing, you have all you need. Since I use PHPStorm, I used the CLI to issue an "hg" command probably twice or so. It just works.

Macros - are useful for those tiny annoying repetitive tasks that you have to do. In PHP, each line must end with a semicolon. How often is your cursor at the end of the line when you finish writing all the code in it? Very rarely. Most of the time, you are inside some parentheses filling in parameters or similar. You have to go to the end of line and hit ";". Well, that is easily automatable by macros.

OK, enough talk. I will now let you go, download and try PHPStorm yourself. Have fun.

Show more