How can functions be named to clearly reflect that they follow a declarative paradigm?
Context: I've recently started working on creating libraries that work in a declarative manner but I'm having a hard time coming up with a naming convention that reflects it. In the past I've created imperative functions with names like createThing
, but I'm finding it difficult to succinctly convey the idea of "do what is necessary to return a Thing
that looks like ____" in a function name.
Ideally, I'd like to follow a formal standard or established naming convention. Otherwise, I'm hoping to at least find some guidance from pre-existing codebases.
The name should clearly, without ambiguity indicate what the function does. You don't have to jump around searching for the truth. Function names should apply the lower camel case form: addItem() , saveToStore() or getItemById() . Every function is an action, so the name should contain at least one verb.
Function and Class Naming conventions An important aspect of naming is to ensure your classes, functions, and variables can be distinguished from each other. For example, one could use Camelcase and Pascalcase for functions and classes respectively, while reserving Snakecase or Hungarian notation for variable names.
Function names should be lowercase, with words separated by underscores as necessary to improve readability. Variable names follow the same convention as function names. mixedCase is allowed only in contexts where that's already the prevailing style (e.g. threading.py), to retain backwards compatibility.
Given your concerns to have a succinct function name, I would look into whether your createThing
function does too much and split it into a few smaller chunks (this is heavily influenced by C# syntax):
var yourThing = new Thing()
.with(new PropertyA()).thenWith(new DependentPropertyOfA()) // digress a bit
.with(new PropertyB()) // back to main thread here
.withPieceOfLogic((parameter1, parameter2) => {define some logic here}) // so you can potentially can swap implementations as well
.create();
Here I'm aiming at something along the lines of FluentInterface. This might get you to the aesthetics you're looking for.
One thing to bear in mind with this approach, this chaining makes it heavily linear and might not work well if you need to make detours from defining your main object a lot.
Another few examples to draw inspiration from:
In my experience there is no canonical naming scheme for primary functions in declarative frameworks, but there are many prominent examples you could draw inspiration from.
Methods associated with the FluentInterface style are often prefixed 'with'. e.g.
new HTTPClient()
.withProxy(new Proxy('localhost', 8080))
.withTimeOut(Duration.of("30s"))
.withRequestHeaders(
new Headers()
.with('User-Agent', 'FluidClient')
);
See https://martinfowler.com/bliki/FluentInterface.html
Some FluentInterface designs do away with function name prefixes and just name functions directly after the declarative element they represent. An example from JOOQ:(https://www.jooq.org/doc/3.12/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/)
String sql = create.select(field("BOOK.TITLE"), field("AUTHOR.FIRST_NAME"),
field("AUTHOR.LAST_NAME"))
.from(table("BOOK"))
.join(table("AUTHOR"))
.on(field("BOOK.AUTHOR_ID").eq(field("AUTHOR.ID")))
.where(field("BOOK.PUBLISHED_IN").eq(1948))
.getSQL();
This has the benefit of making a chain of imperative invocations read like a declarative DSL. However eschewing naming conventions for methods can make the source for the builder class less readable.
The above examples are of builders being used to construct objects where encapsulated state is used to represent the concept being declared. Some OO frameworks reduce this further so that the code is composed solely in terms of constructors for 'fine-grained' objects. In most c-derived languages constructors are required to be named after the type they are associated with.
An example of a UI widget tree being declared in Flutter (from https://flutter.dev/docs/development/ui/widgets-intro#using-material-components):
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.menu),
tooltip: 'Navigation menu',
onPressed: null,
),
title: Text('Example title'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
tooltip: 'Search',
onPressed: null,
),
],
),
// body is the majority of the screen.
body: Center(
child: Text('Hello, world!'),
),
floatingActionButton: FloatingActionButton(
tooltip: 'Add', // used by assistive technologies
child: Icon(Icons.add),
onPressed: null,
),
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With