This article was published in a recent refactoring effort

Before doing personal projects, to reconstruct the three times, the resume written later in scallops the interview, the interviewer asked three times respectively reconstructed the what, think carefully to refactor isn’t at that time, the first is the UI changes, but there is not much to change the project structure, the second is the overall moved to CocoaPods, this force can calculate refactoring, The third one is just the uniformity of style in variable names, method names, empty lines and so on.

At my current job, when I take over these projects, THE main work I do is refactoring, and the refactoring work, originally intended to be one line, turns out to be quite a lot. Let me make a list:

  • Delete unused third-party libraries
  • Delete unreasonable third party library, use system or build your own wheel
  • Delete defined variables that are not used
  • Delete import headers that are not used
  • Remove unused logic left over from older projects
  • Unreasonable hierarchical structure reconstruction of Controller layer, useless code cleaning
  • View layer unreasonable structure reconstruction
  • Service layer redundant writing refactoring
  • Unreasonable refactoring of the Model layer
  • Uncoupling unreasonable coupling
  • Coupling a module of a category
  • Fixed multiple memory leaks
  • Fixed multiple circular references
  • Optimize compilation speed
  • Eliminate warning in the project

In terms of deleted code, in one project over 90,000 lines were deleted from third-party libraries in the Pods folder (that directory was not ignored by Git), and around 40,000 lines were deleted from the project, much of which was left over from previous projects that had not been cleaned up. After deleting 40,000 lines, the program still runs intact.

What followed was a partial refactoring, removing some third-party libraries and building your own wheels, in the process removing 12,000 lines of code and adding about 1,100.

As a result of the refactoring, the compile speed was reduced from 2-3 minutes to 40 seconds, warning was reduced from 70 to 0, the number of third-party libraries was reduced from 51 to 13, installation packages were reduced from 22.1m to 3.7m, and features were even more than before.

In terms of memory leakage, since no one cares about it, there is a function that can add hundreds of KB of memory once it is used. That part of the code is written in C, so timely release the memory and optimize the way to call down the memory leak problem will be solved perfectly.

In terms of circular references, someone turned off Xcode warning. Later, when I opened it, I found four circular references + dozens of warnings. During the test, I found that the page kept opening and exiting, and the program crashed.

So much for generalities, let me share a few more specific points.

Avoid abusing singletons

Singletons are great to use, but they are not recycled until the program exits. If you make singletons out of modules that are not needed for the entire life cycle, you just waste memory.

Avoid useless hierarchies

Using network layer as an example, encapsulating AFN is a layer, API suffix string is put in a layer, construct request is put in a layer, OAuth authorization is put in a layer, send ordinary request is another layer. To add an API, at least six files must be modified. It’s hard to write. It’s hard to watch.

The network layer is designed only one layer, encapsulating AFN, and the function to send requests is also in it. The API address is written directly in the string, so there is no practical sense to make so many layers, in such a small project.

In addition, as for the project file structure, it is recommended not to create a new folder for one or two files. This is mainly a personal habit, but in fact, it does not matter.

Name of rational design method

No hidden trouble

- (void)requestAtPathForRouteNamed:(NSString *)routeName object:(id)object parameters:(NSDictionary *)parameters
Copy the code

and

- (void)requestWithMethod:(XXHTTPMethod)method path:(NSString *)path params:(id)params paramsType:(XXParamType)paramsType
Copy the code

Form data and JSON should not be allowed to exist in the same API. If we use the first method, our new colleagues may think that both can be used to fill in data. This is not in line with our expectations.

Even more extreme, one day we need to send the file over, do we have to expand the field again?

If you use the second option, param is the ID type, and if it is JSON, type is passed in as json enumeration type, and if it is binary, type is passed in as binary enumeration type, leaving only one field exposed to the developer.

Avoid coupling

In our project, there is a gradient color line that needs to be used everywhere. We put this line inside UIImage+XXUtil. H, and the previous design was like this:

+ (instancetype)xx_navigationBarShadowImage
Copy the code

In the.m implementation, UIColor+XXTheme is coupled to the method, and the Util method is no longer a utility. After refactoring, it is named like this:

+ (instancetype)xx_gradientImageWithStartColor:(UIColor *)aColor endColor:(UIColor *)bColor andWidth:(CGFloat)width
Copy the code

So that fits the category name Util.

Avoid abuse of inheritance

Inheritance works really well, with the consequence that subclasses will execute the parent’s methods one by one, which may not seem like a big deal at first, but what if that method is a performance drain.

In this project, the app often freezes, and when you use it, it gets frozen, and nothing happens when you click on it. Because all pages inherit a design from the base class, there happens to be one time-consuming operation in the base class that every page executes at least three times, resulting in page fee-dead.

So what we did after the refactoring was we made it a category, and we just added a couple of methods to UIViewController, called on demand, not on every page, so we solved this weird bug.

Choose third-party libraries appropriately

If there is a function, due to various reasons, you have to use a third-party library, at least choose a star on GitHub, then check the issue list to see if there are any serious bugs not fixed, as well as compatibility problems, develop good habits, and slowly filter out the most appropriate library.

Avoid abusing third-party libraries

Our project used YYText library before, just to add a picture to a paragraph of text, iOS9 device crashed hundreds of times on the day of the event. In fact this code with NSAttributedString attributedStringWithAttachment write what, seven lines is enough, seven lines replace an unstable third-party libraries, and it’s a good deal.

I don’t know for some reason, maybe PSCollectionView was used in the older project, so it didn’t have to be reconstructed if it could run. This kind of library is completely unnecessary, and the system’s own library is easy to use and safer.

Do their job

The processing of data, such as UTF8 encoding of strings and timestamp conversion to YYYY-MM-DD strings, is handled in the Model layer. The Model layer does the processing of data.

Combined with actual demand

The reason the back end records all kinds of ids in longs is because they need to be indexed, for indexing speed. The client doesn’t need that at all, so just use string, and you don’t have to worry about overflows, and you don’t have to type when you’re doing presentations.

In the same way, the amount should be double precision floating point, because float is not precise enough. Based on my development experience, the amount rarely needs to be added or subtracted by the client.

About Naming conventions

Apple’s UIKit is the best example. When writing a component that you don’t know how to name, think about whether Apple has similar components to find inspiration.

Avoid meaningless comments

The OC method name itself is very long and clear, just add a few Spaces in the middle of the method name, then as a comment, as if not written.

Delete unnecessary code

Git’s purpose is to always go back to the previous version of the code, the code can be found, comment out the code, write a similar line, except to increase the cost of reading, easy to cause ambiguity, should not be useful. One hundred or two hundred lines in a file, and opening it up to find 70 or 80 lines of code commented out, is pretty darn bad.

Refactoring ancestral code really makes you feel like you’ve lived for a long time. The ones mentioned above are impressive, and some minor problems have been quietly solved. I hope my code will not make the following students think so.