TL; DRWe wrote a
cool code generator for iOS development, with the following advantages:
- Swift and Objective-C support,
- Using liquid markup language to create templates
- Flexible template management system
- Integration with Cocoapods dependency manager .
More details - under the cut.
Serious decisions regarding the architecture of the project bear the need to make a certain compromise. We stick to the
n-tier structure - we get some amount of empty forwarding of information between the layers. We parallelize tasks on several threads - spend a huge amount of time on solving non-obvious bugs. In a similar situation requiring a compromise, we also encountered at
Rambler & Co , deciding to use
VIPER as the standard of architecture for all our mobile applications. Having received excellent modularity and a clear separation of component responsibilities, we acquired a headache in the form of the complexity and monotony of the process of creating new modules.
The average iOS developer at the beginning of work on the new screen simply creates one class. The one who made a willful decision to switch to VIPER, at this moment begins to suffer. In most cases, he needs to create
five classes, six protocols and write five test cases . Suppose that to create new modules, our poor fellow will hire a professional secretary with a huge print speed - but even in this case, he is unlikely to go beyond 30 seconds to create and fill out one file. Apply the small knowledge of mathematics, which has given the nature of mobile developers, multiply these numbers and get an answer
in the region of 10 minutes . During the same time, the average developer will have time to distribute a couple of hundred lines of the UITableViewDataSource, send several network requests and paint all the view's in a beautiful azure color. Somehow unfair to the work of our VIPER-guru.

But heavy and tedious manual labor is not the only problem. Repetitive with every module misprints, which every day more and more drags the project to the muddy bottom of broken deadlines, are no less a headache.

One of the ways to solve these problems, which we have used for a long time, is to create our own templates for Xcode. Apart from the fact that such an approach is simply not sporty, for ourselves we identified a number of relatively serious flaws.
- Xcode is not the most stable IDE , and periodically when it is updated, templates, plug-ins and other body kits can successfully fly.
- There is no convenient mechanism for adding new templates, let alone getting updates.
- Basically, there is no possibility of adding generated files to different project targets .
- The syntax is infinitely inconvenient and complicated , especially for someone who needs just ten to draw a template for a project in ten minutes.
But, of course, everyone understands that he was most upset by another, fatal, flaw - the solution was not written by us. There is too little control over it, and extensibility for more specific tasks tends to zero. That's why we decided to write our code generator -
Genembu . I will immediately clarify a very important thesis - even though we started the project in order to simplify the process of creating VIPER modules, but as a result we received a much more flexible utility that can help automate a wide range of code generation and standardization tasks.
')
From the moment of installing Genremba (
gem install generamba ) before creating your first module, you need to go through three steps:
- generamba setup starts the process of setting up a genremba for working with a specific project. At this point, set the standard paths for files, test settings, dependency managers and other infrastructure. As a result of the command, we get the configuration file of the project - Rambafile .
- generamba template install launches the installation process of the templates specified in the Rambafile .
- generamba gen HabrahabrModule rviper_controller already directly creates a new HabrahabrModule module using the rviper_controller template.
For the work of Generamb uses several resources:
- Rambafile is a configuration file containing everything that the user specified during the execution of the setup command, as well as links to the templates and their directories,
- One or more templates that can be specified when creating a new module,
- User settings (for example, the name of the author).
The first two points boldly fall under Git, and the settings tied to the user are in a project-independent directory.
Rambafile Example### Headers settings company: Rambler&Co ### Xcode project settings project_name: GenerambaSandbox prefix: RDS xcodeproj_path: GenerambaSandbox.xcodeproj ### Code generation settings section # The main project target name project_target: GenerambaSandbox # The file path for new modules project_file_path: GenerambaSandbox/Classes/Modules # The Xcode group path to new modules project_group_path: GenerambaSandbox/Classes/Modules ### Tests generation settings section # The tests target name test_target: GenerambaSandboxTests # The file path for new tests test_file_path: GenerambaSandboxTests/Classes/Modules # The Xcode group path to new tests test_group_path: GenerambaSandboxTests/Classes/Modules ### Dependencies settings section podfile_path: Podfile cartfile_path: Cartfile ### Templates catalogs: - 'https://github.com/rambler-ios/generamba-catalog' - 'https://github.com/igrekde/my-own-catalog' templates: - {name: rviper_controller} - {name: local_template_name, local: 'absolute/file/path'} - {name: remote_template_name, git: 'https://github.com/igrekde/remote_template'}
Special mention is worthy of working with templates. Unlike many other generators, we do not sew templates into the utility itself - instead, we have built in a more flexible system, spied on by dependency managers (read, Cocoapods). New templates can be installed using one of the following ways:
- Local template (copied from the specified folder)
- Deleted template (cloned from specified repository)
- Template from the catalog (in the repositories with the used directories, a suitable template is searched for by name).
After several months of using Genermba on our projects, the most frequently used pattern emerged - a project catalog is created for the project, within which all, even the least frequently used templates are stored. Over time, some of these solutions, sharpened for a specific project, after certain improvements, fall
into our public spec .
As I already mentioned, we were confused by the complexity of the markup of standard Xcode templates, and the
template engine liquid was chosen as a tool to combat this problem - not only with a simple, convenient and understandable syntax, but also with a bunch of additional bonuses that can be found application not only in the frontend, but also during code generation.
For comparison, the Xcode template:
InteractorTemplate.h // // ___VARIABLE_viperModuleName______FILENAME___ // ___PROJECTNAME___ // // Created by ___FULLUSERNAME___ on ___DATE___ // Copyright ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved. // #import "___VARIABLE_viperModuleName:identifier___Interactor.h" #import "___VARIABLE_viperModuleName:identifier___InteractorOutput.h" @implementation ___VARIABLE_viperModuleName:identifier___Interactor #pragma mark - ___VARIABLE_viperModuleName:identifier___InteractorInput @end
Liquid template for the same file:
InteractorTemplate.liquid // // {{ module_info.name }}{{ module_info.file_name }} // {{ module_info.project_name }} // // Created by {{ developer.name }} on {{ date }}. // Copyright {{ year }} {{ developer.company }}. All rights reserved. // #import "{{module_info.name}}Interactor.h" #import "{{module_info.name}}InteractorOutput.h" @implementation {{module_info.name}}Interactor #pragma mark - {{module_info.name}}InteractorInput @end
We continue to actively develop the Genermbu. In addition to everyday tasks, we also look at other areas:
- add GUI , including in the form of plugins for IDE,
- support for Android projects
- fiction requiring work with an AST-tree - for example, autogeneration of test cases according to the described protocols or mocks for swift-classes.
As a conclusion, I would like to add that Generamba served as an excellent illustrative example of the benefits of automation of quite trivial tasks - we will transfer the experience gained to other areas of the department’s activities, which would not hurt to get rid of manual labor.
Have you decided to start using Generamba? Ask your questions and write about the issues found in the
issues - our community, although small, is quite active.
Useful links: