Version 3, last updated by tgoodchild at September 10, 2011 19:14 UTC
Proposal to Refactor Cmd2
Abstract
I propose that Cmd2 be reorganized into modules.
The rationale is to promote easier growth and maintenance of the project, and to lower the barrier for interested developers to improve Cmd2 further.
Disclaimer
I’m new to Python. I finally decided to learn Python because I needed a quick-and-easy tool for building a command-line interface for another open-source project, and after 3 or 4 days spent searching, reading, and comparing languages like Python, Ruby, and Node.js-Javascript, I opted for Python mostly because of Cmd2 (as well as some other contributing factors related to the open source project I was working on).
I’ve spent plenty of time reading about the Zen of Python, philosophies aspired to in the Python community, and trying to gain a solid understanding of what is considered “Pythonic”.
The general principles are things I have always believed in (which is another significant part of the reason I chose Python over the other languages I was considering); however, there are some specifics I have yet to grasp.
As much as possible, I have tried to compensate for these rough edges in my understanding of what is Pythonic. I hope none appear in this proposal—but if they do, I welcome enlightenment. ☺
Should I manage to avoid exposing any of these rough edges, I hope you find the ideas expressed in this proposal useful. Building an actual, working shell with Cmd2 was one of the most amazing experiences I have ever had coding. I’m so grateful.
I would love nothing more than to see Cmd2 grow and prosper. And perhaps… mature into a module in Python’s Standard Library!
Proposed Structure
From “Packages” (The Python Tutorial, §6.4):
Packages are a way of structuring Python’s module namespace by using “dotted module names”. For example, the module name A.B designates a submodule named B in a package named A. Just like the use of modules saves the authors of different modules from having to worry about each other’s global variable names, the use of dotted module names saves the authors of multi-module packages like NumPy or the Python Imaging Library from having to worry about each other’s module names.
I believe that Cmd2 would benefit from being refactored into a number of modules.
Following the blockquote above, the Python Tutorial shows example package’s file structure. Using that as inspiration, I recommend the following structure for Cmd2:
Cmd2/ # Cmd2 package
__init__.py # Cmd2. Now with more module™.
cmd2.py # Minimal, high-level code only.
commands.py # All do_blah() defs.
errors.py # Errors are understood better (and
# evolve better) with a dedicated
# file.
parsers.py # All parsing code, including
# use of OptParse. (Also provides
# a dedicated file for
# transition to ArgParse.)
support.py # Contains code for hooks, and
# classes like ParsedString,
# Stubborndict, Borg,
# Statekeeper, History,
# and so on.
tests.py # Tests are understood better (and
# evolve better) with a dedicated
# file.
Unlike the example in the Python Tutorial, the structure I propose above has no subfolders. (I actually started with subfolders, but eventually felt that it was a bit much.)
I recognize that some of the files I have proposed above will contain very little code. I think that’s okay. I believe these generally fall into 1 of 2 categories:
- Things like “tests” and “errors”. Although they are important, they have a fundamentally different role to play in Cmd2 than the bulk of the code (whose role is all geared towards building a command line app).
- Things like “parsing”. Parsing is one of those tasks encountered near-universally in programs. But parsing is also a verbose (and sometimes even complex) task. I think it clearly deserves its own file, for the benefit of the parser-code itself as well as the cleanup of the parts of Cmd2 that rely upon it.
A lovely side-effect of putting all parser-code in its own file is that it will be easier for Cmd2 to begin transitioning to ArgParse.
Ideal Benefits
I envision a modularized Cmd2 with the following benefits:
- Navigation is trivial. It should be obvious where to go to find a particular piece of code (even if you’re not Catherine Devlin ☺)
- Contributing is easy. Newcomers to the project should be able to browse the code, never feel lost or intimidated, quickly and easily find a piece to work on, and submit their changes back to the project.
- Transitioning is easy. Consider the idea transitioning Cmd2 to ArgParse. Think about navigating the code in its current state, everything in a single file, and searching for all the places where parsers are defined, and all the places where parsers are used. Now, consider the same task in a modularized Cmd2; parsers are all in their own file, and the code that makes use of them is also easy to locate (since modularized code makes searching for what you want a much easier task in terms of signal-to-noise ratio).
…Seems much easier—am I right? ☺
- Cmd2 itself benefits. Cmd2’s developers are happier. Happy developers produce better code. Better code makes happier users. Which make Cmd2’s community develop and grow. Which inspire some users to become Cmd2 developers…and so on.
…Until one glorious day, Cmd2 humbly accepts the reins from its predecessor, Cmd, and is adopted into the Python Standard Library.
Not a bad dream…is it?
I think we can do it.
Do you?
—Zearin (Tony R.)