Common Lisp style: multiple packages in same repo

Pascal Bourguignon pjb at informatimago.com
Wed Aug 22 21:10:06 UTC 2018



> On 22 Aug 2018, at 00:36, Daniel Pezely <daniel at pezely.com> wrote:
> 
> I posted this to Stack Overflow but was hoping for more input.
> https://stackoverflow.com/questions/51638864/common-lisp-style-multiple-packages-in-same-repo <https://stackoverflow.com/questions/51638864/common-lisp-style-multiple-packages-in-same-repo>
> 
> May I get recommendations or links to representative code repositories with good style for multiple related Common Lisp packages, please?
> 
> For instance, consider a high-level workflow library with accompanying lower-level API, each in its own CL package but same git repo due to synchronized releases.
> 
> Each system (*.asd file) isolates tests and may be invoked using:
> 
> (asdf:test-system foo :force t)
> 
> Separate systems may be built via make, which definitely helps isolate SBCL code-coverage reports.
> 
> Some users of the library may only want to load the lower-level API. For simplifying dependencies for those using higher-level API, it seems best to keep everything bundled in one repo. Any revision to one library would likely require updating all for the same release.
> 
> I currently have a single directory tree with a subdirectory for each CL package. There's a top-level Makefile plus one in each subdirectory that the library maintain would use. The top-level also contains symbolic links for .asd files pointing into relevant subdirectories. (It's a library deeply dependent upon POSIX calls via uiop-posix, so it's only applicable on an OS with sym-links.)
> 
> This seems to be an issue at large considering issue #1 for Quicklisp-docs [0].
> 
> Found nothing relevant in Google's CL style guide [1], State of the Common Lisp Ecosystem, 2015 [2], Edi's CL Recipes [3] or Lisp-lang [4]. Browsing repos seem to have quite a mix of styles.
> 
> [0] https://github.com/rudolfochrist/quicklisp-docs/issues/1 <https://github.com/rudolfochrist/quicklisp-docs/issues/1>
> [1] https://google.github.io/styleguide/lispguide.xml <https://google.github.io/styleguide/lispguide.xml>
> [2] https://web.archive.org/web/20160305061250/http://eudoxia.me/article/common-lisp-sotu-2015/ <https://web.archive.org/web/20160305061250/http://eudoxia.me/article/common-lisp-sotu-2015/>
> [3] http://weitz.de/cl-recipes/ <http://weitz.de/cl-recipes/>
> [4] http://lisp-lang.org/learn/writing-libraries <http://lisp-lang.org/learn/writing-libraries> but see also their section on Continuous Integration
> Repo to be fixed: https://gitlab.com/dpezely/cl-mmap <https://gitlab.com/dpezely/cl-mmap>
> (commit a23bd88d of 2018-07-14; release will be tagged when fixed)
> 
> Thanks,
>   -Daniel
> 


You’re asking about different things.

- git repositories. It’s more a question of ownership and administration than anything else.  Technically, as you noted, it is better to keep in the same repository things that will evolve in sync. eg. client & server module implementing the same protocol.  But if for some reason those two modules had to be developed by different teams, it would still be preferable to have two separate repositories, and synchronize thru the protocol specification, and not thru the code.  Otherwise, as a small team of 1 I tend to prefer big git repositories holding everything eg. http://github.com/informatimago/lisp

- asdf systems are entirely orthogonal and agnostic to packages.  It will let you do as you wish. Whether what you do is good or not will depend on the use case.
It may be the less surprising option to map 1 package to 1 system, and to avoid defining (or overriding/redefining) things in other packages.  But it may be needed, useful or easier to ignore this rule.

For example, you can define a package X loaded with a system X. Then a package X.TEST loaded with a system X.TEST.  But in order to test some internal feature of X, you may have to define or redefine things in the package X, from the code loaded by the system X.TEST; or you may want to avoid the package X.TEST altogether, and just load tests in the package X, from the system named X.TEST!  All the other use cases are possible, and might be justified by a given situation.

- files. Mapping lisp definitions (and other top-level forms) to files is rather arbitrary.   The only technical constraint is that the definitions that are used by macros (at macroexpansion-time ∈ compilation-time), must be compiled before, and loaded into the compilation environment before those macros can be used (and even, better before they’re defined). This can be done by wrapping those definitions in an eval-when form, but it’s often easier to put them in a separate file, to be compiled and loaded before the file defining the macro and the files using it.  For the rest, do as you wish.  I try to follow the logic of the program, or the “explanatory order” (think about the human reader).  But it doesn’t matter at all.  Instead of worrying about that, you’d better spend your time writing an emacs mode that would store lisp forms into files automatically.  You’d just have a browser (like a smalltalk browser), and add definitions, or browse and select definitions to be edited. emacs would fetch them from the file IT had decided where to store them, and would present them in an ephemeral buffer for your edit.  Of course, instead of text-based commands such as search and replace, you’d have symbolic editing commands such as rename-symbol-in-definition or rename-symbol-everywhere or substitute-sexp-everywhere etc.  This includes directories.
That said, nothing prevents you to define some conventions for your current project. See again the above github repo for an example. I’m not saying you should follow it, it’s just a random example that suits me for this case, an aggregation of libraries. For application programs, I’d use a totally different way to structure code in packages, and spread code in files and directories, and how to load it with what systems.

Basically, what I’m saying is that it’s a software engineering question and it must be answered based on software engineering design and decisions.  In UML you have the concepts of module and components, and with stereotypes, different kinds of components, you can represent packages, asdf system and components, and even if you want to modelize it, asdf files, since asdf uses files as unit of compilation and loading.  How you structure your software cannot be PRE-designed! You have to do the work yourself, as a software engineer!

In short: it depends!

-- 
__Pascal J. Bourguignon__




-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/pro/attachments/20180822/bc7174a5/attachment.html>


More information about the pro mailing list