I'm in the camp of use qualified keys wherever you can and convert as appropriate if needed at the edges.
Given that you can go in and out of the database with qualified keys (if you're using Datomic, or a JDBC setup with next.jdbc
), you can stay in qualified keyword land for pretty much everything except JSON interactions -- and even then some systems will happily accept /
in key strings...
I work daily in a system where Clojure is the minority, interfacing with both Ruby and JS. The pain of keyword conversion is real, but I sympathize with both sides of the argument. Clojure best practice can be argued as a general best practice, but it definitely creates friction elsewhere. I liked option 2 in the last link I shared, which were deemed “all terrain keys”, especially a conversion that somehow preserves the namespace portion, allowing for systematic conversion back into clj without loss of data.
I actually tried having some keywords as kebab, and the “remote” keys remain snake, and it was extremely confusing. Ended up reverting back to converting at the edges.
Given that both Cheshire and c.d.j offer controls on preserving or dropping qualifiers when generating JSON and on adding a qualifier or not when parsing JSON means that it's trivial to transform at the edges tho'...
The snake_case / kebab-case thing is something you have to think about with next.jdbc
too, if your DB has tables or columns in snake_case. Hence the built-in support for the camel-snake-kebab library if you have it on your classpath 🙂
Unfortunately, we have some legacy DB stuff written in headlessCamelCase (both tables -- which are case sensitive -- and columns -- which are not, in MySQL at least).
(and somewhere along the way we passed through nodelimitercase in our transition from headlessCamelCase to snake_case in MySQL... argh!)
Ha sounds familiar. The issue with preserving namespaces is less that it’s difficult and more that your coworkers give you funny looks, ie social friction. It can result in some pretty long keys which some people find unappealing (which admittedly is not a great technical reason, but alas). We have good support for them in Clojure at least, other langs aren’t so lucky...
document.designMode = "on"
TIL
reading some old papers, from 1983: The System Modeller is a complete software development system used in the Cedar project of Xerox PARC's Computer Science Laboratory. The Modeller provides automatic support for the program development cycle followed by programmers using Cedar. It uses information stored in a system model, which describes a software system by specifying: 1. The versions of various modules that make up a particular software system. 2. The interconnections between modules, such as which procedures are used and where they are defined. 3. Additional information needed to compile and load the system. 4. Hints for locating the modules in a distributed file system. Under the direction of the Cedar programmer, the Modeller performs a variety of operations on the systems described by the system models: 1. It implements the representation of the system by source text in a collection of files. 2. It tracks changes made by the programmer. To do this, it is connected to the Cedar editor and is notified when files are edited and new versions are created. 3. It automatically builds an executable version of the system, by recompiling and loading the modules. To provide fast response, the Modeller behaves like an incremental compiler: only those modules that change are analyzed and recompiled. 4. It provides complete support for the integration of packages as part of a release. Thus the Modeller can manage the files of a system as they are changing, providing a user interface through which the programmer edits, compiles, loads and debugs her changes interactively while she is developing her software. The models are automatically updated to refer to the changed components. Manual updates of models by the programmer are not normally necessary.
The model refers to a component module of the program by its unique name, independently of the location in the file system where its bits are stored. The development of a program can be described by a collection of models, one for each stage in the development; certain models define releases. ... In 1983 a system is specified by text which is stored in files. This provides modularity in the physical representation: a file can name other files instead of literally including their text. in Cedar, these files hold the text of Cedar modules or system models. This representation is convenient for users to manipulate; it allows sharing of identical objects, and facilitates separate compilation. Unless care is taken, however, the integrity of the system will be lost, since the contents of the named files may change. To prevent this, we abstract files into named objects, which are simply pieces of text. We require that names be unique and objects be immutable. By this we mean that: • Each object has a unique name, never used for any other object. The name is stored as part of the object, so there is no doubt about whether a particular collection of bits is the object with a given name. A name is made unique by appending a unique identifier to a human-sensible string. • The contents of an object never change once the object is created. The object may be erased, in which case the contents are no longer accessible. If the file system does not guarantee immutability, it can be ensured by using a suitable checksum as the unique identifier of the object. These rules ensure that a name can be used instead of the text of an object without any loss of integrity, in the sense that either the entire text of a system will be correctly assembled, or the lack of some object will be detected. What happens when a new version V2 of an object is created? In this view, such a version is a new object. Any model M1 which refers to the old object V1 continues to do so. However, it is possible to create a new model M2 which is identical to M1 except that every reference to V1 is replaced by a reference to V2; this operation is called Notice and is discussed further in § 3. In this way, the notion that objects are immutable is reconciled with the fact of evolution.
I read some of these and I feel like all of those people at PARC must just be perpetually disappointed in what the rest of us have come up with since.
sounds pretty rad
The Modeller provides an interactive interface for ordinary incremental program development. When used interactively, the role of the Modeller is similar to that of an incremental compiler: it tries to do as little work as it can as quickly as possible in order to produce a runnable system. To do this, it keeps track incrementally of as much information as possible about the objects in the active models. For example, consider the following scenario. Assume a model already exists, say BTree.model, and the user wants to change one module to fix a bug. Earlier, she has started with BTree.model as the current model. She uses the editor to make a change to BTreeImpl.cedar!(Jan 14, 1983, 14:44:09). When the user finishes editing the module and creates a new version BTreeImpl.cedar!(April 1, 1983, 9:22:12),, the editor notifies the Modeller by calling its Notice procedure, indicating that BTreelmpl.cedar!(April 1, 1983, 9:22:12) has been produced from BTreelmpl.cedar!(Jan 14, 1983, 14:44:09). If the latter is referenced by the current model, the Modeller notices the new version and updates BTree.model!(Jan 14, 1983, 14:44:11) to produce BTree.model!(April 1, 1983, 9:22:20), which refers to the new version. The user may edit and change more files. When she wants to make a runnable version of her system, she issues another command to the Modeller, which then compiles everything in correct order and (if there are no errors) produces a binary file. A more complex scenario involves the parallel development of the same system by two programmers. Suppose both start with a system described by the model M0, and end up with different models M1 and M2. They may wish to make a new version M3 which merges their changes. The Modeller can provide help for this common case as follows: If one programmer has added, deleted or changed some object not changed by the other, the Modeller will add, delete, or change that object in a merged model. If both programmers have changed the same object in different ways, the Modeller cannot know which version to prefer and will either explore the changed objects recursively, or ask the user for help.
paper is here: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/11/32-OrganizingSoftware.pdf
also found a video demonstrating everything that's pretty cool: https://www.youtube.com/watch?v=z_dt7NG38V4
apparently the system described was Eric Schmidt's PhD work
Found myself typing (for ...
in Java 😆
👋 Anyone know of any good tools for declarative/data-driven testing of Web APIs and/or old-school Web Apps (non-SPAs)? I’m looking to create an integration test suite for an existing system, so I need something that can send HTTP requests and check that the responses meet expectations. I found https://github.com/aviaviavi/curl-runnings which looks decent; I’m just wondering if something else exists along these lines that’s more mature, robust, etc.
Found another one to evaluate: https://www.getapid.com