Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declarative Function Naming

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.

like image 409
Mr. Llama Avatar asked Oct 23 '19 00:10

Mr. Llama


People also ask

How do you name a function in code?

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.

What is the naming convention for variables and functions?

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.

How do you name a function in Python?

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.


2 Answers

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:

  1. https://www.entityframeworktutorial.net/efcore/fluent-api-in-entity-framework-core.aspx
  2. https://momentjs.com/docs/.
  3. https://jasmine.github.io/tutorials/your_first_suite
like image 158
timur Avatar answered Oct 18 '22 19:10

timur


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,
      ),
    );
like image 3
Richard Woods Avatar answered Oct 18 '22 19:10

Richard Woods