54

Sounds pretty basic, I know, but I recently had a colleague tell me that a method called startHttpServer is too complicated to understand because it only starts the server if it's not already running. I find I get into trouble when I respond with, "Seriously? I've been doing this for decades - it's a common pattern in programming." More often than I care to admit he comes back with some documented evidence that shows that the entire programming community is behind his point of view and I end up feeling sheepish.

Question: Is there a documented design pattern behind the concept of a method that is a no-op if the action required is already in effect? Or, if not a pattern, does it have a name either? And if not, is there any reason to think it's too complicated to consider writing a method in this manner?

11
  • 6
    sounds like caching - and it is often considered complicated indeed (see also How do I explain ${something} to ${someone}?)
    – gnat
    Commented Aug 27, 2017 at 6:25
  • 8
    You got 3 different answers, but the best answer would be, apply them all: rename the original function, split its code into two functions (where one of the two now gets the name startHttpServer), and yes, the term "idempotent" applies here well.
    – Doc Brown
    Commented Aug 27, 2017 at 8:40
  • 8
    What sort of counter-evidence does your colleague provide? Can you provide a link to it? Commented Aug 27, 2017 at 14:10
  • 5
    I'm curious to see from where your colleague sources his quotes. At least around Stack Overflow and Software Engineering, this function would be at most badly named but wouldn't have any unusual behavior. Keep in mind that isn't because someone somewhere put something on a blog that it represents the entire view of the programming community. Even big names like Martin Fowler say some very weird things from time to time. We're all just humans.
    – T. Sar
    Commented Aug 28, 2017 at 11:48
  • 4
    I think a better way to think about "Do something if it's not already done" would be "Put the system on this state". Of course, if the system already is on that state, the method would do nothing - which would be the expected behavior.
    – T. Sar
    Commented Aug 29, 2017 at 11:17

8 Answers 8

127

As NickWilliams has already said: the concept the OP describes is called idempotent (noun Idempotency). It is indeed common practice, especially in high-level APIs.

BUT: Rename the function.

Instead of startHttpServer call it makeSureHttpServerIsRunning or ensureHttpServerIsRunning.

When a function is called startHttpServer, readers expect it to start a HTTP server; when called ten times in a row, I'll have ten servers running. Your function doesn't do that most of the time. Additionally, the name with "start" suggests that if I want only one server running I'll have to keep track of whether the function has already been called or not.

When a function is called makeSureHttpServerIsRunning, I assume it will do the necessary things to make sure that a HTTP server is running, most likely by checking if it is already running, and starting it otherwise. I also assume that the function makes sure the server is actually running (starting a server might involve some time where it is not quite running yet).

15
  • 84
    This. Personally I use "Ensure" instead. The point is that this should become a naming scheme that is understood in your team.
    – Euphoric
    Commented Aug 27, 2017 at 7:47
  • 3
    or have start throw an exception if its already started. like sqlconnection.open
    – Ewan
    Commented Aug 27, 2017 at 8:58
  • 9
    I always use the "ensure" naming for "do if not already" function.
    – Kaz
    Commented Aug 27, 2017 at 17:25
  • 3
    Another name I often see is getOrCreateSomething, which only create on first call and then just return something
    – Fabich
    Commented Aug 27, 2017 at 21:54
  • 5
    @aroth Are you sure you wouldn't expect it to attempt to find any available port and return it? Or just be badly written? ;)
    – jpmc26
    Commented Aug 28, 2017 at 5:12
33

Rename it to EnsureServerRunning.

Completely unambiguous and is clear that it makes sure it is running (if it isn't) without implying a restart if it is.

(Alternative: StartServerIfNotRunning?)

1
  • 1
    Most callers just care that the server is running after the call. How that is achieved, they don't care.
    – gnasher729
    Commented Aug 28, 2017 at 22:32
29

Not really a design pattern but I would call your method idempotent. There term is usually used to refer to remote calls but the description seems the match what you are doing.

Idempotent Methods. Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. (From W3.org)

The server side effect here being that the http server is started once the method is called. I see nothing wrong with a method doing this.

If you need a design pattern I guess you could expose your httpServer as a singleton which is started when initialized.

11
  • 5
    The function is not idempotent if calling it once starts the http server, and calling it a second time doesn't. Thats literally the opposite of idempotence. It would be idempotent if every call started a new http server.
    – Polygnome
    Commented Aug 27, 2017 at 10:28
  • 37
    @Polygnome Wikipedia defines idempotence as f(f(x)) = f(x) which generally matches Nick's description. Here the function input and output would be the implicit server state, so the “server is running” state would be a fixed point for this function. Maybe I'm misunderstanding the Wikipedia article here, could you link to other references?
    – amon
    Commented Aug 27, 2017 at 11:01
  • 17
    @Polygnome: this answer is correct, idempotency refers to functions for which it does not matter if they are called once or more than once, the result keeps always the same. Here, the result is one running http service, independently from the number of times the function is called.
    – Doc Brown
    Commented Aug 27, 2017 at 11:02
  • 14
    The confusion comes from the fact that idempotence at its core is a mathematical concept applied to functions. The definition is nice and simple for those and also works well for pure functional languages. As soon as you introduce side effects it gets complicated - you have to consider the environment you execute the function in as an (implicit) argument and output of the function. If that state is not modified by further calls to the function it is idempotent, otherwise it isn't. In this case the relevant state is "is http server running" - so the function is idempotent.
    – Voo
    Commented Aug 27, 2017 at 12:09
  • 11
    @Polygnome Sorry, you are wrong. Idempotent means that the request has the same effect whether it is executed once, or more than once. Starting N http servers if N duplicates of the request are received is definitely not idempotent.
    – Kaz
    Commented Aug 27, 2017 at 17:29
7

As the one who implement this tool, startHttpServer, you should be trying to make it the most simple, smooth and seamless to use...

The function's logic

Technically, by splitting startHttpServer's logic into 2 functions and calling them separately, all what you do is moving startHttpServer's idempotency into the code calling both functions instead... Furthermore, unless you wrap both logic in a third function (which is what does startHttpServer in first place), this forces you to write unDRYed code, duplicating it exponentially everywhere you'd have to call startHttpServer. In short, startHttpServer has to call itself the isHttpServerRunning function.

So my point is:

  • Implement isHttpServerRunning function because this may be needed independently anyway...
  • Implement startHttpServer making it use isHttpServerRunning to define its next action accordingly...

Still, you can make startHttpServer return any value the user of this function may need, eg:

  • 0 => server starting failure
  • 1 => server starting success
  • 2 => server was started already

The function's naming

First of all, what is the primary goal of the user? To start HTTP server, right?

Fundamentally, there is no problem by intending to start something that have been started already, AKA 1*1=1. So, at least to me, calling it "ensureHttpServerIsRunning" seems not critically needed, I'd care more about how long, natural and memorable the function's name is.

Now if you want to know how work in detail the function under the hood, there is the documentation or code source for that, I mean like for any other function from library/framework/API/etc...

You learn the function once while you write it multiple times...

So anyway, I'd stick with startHttpServer which is shorter, simpler and more explicit than ensureHttpServerIsRunning.

3
  • 1
    Especially since the method must take some configuration arguments, like root directory, security settings, possibly a port number, I'm 100% comfortable with "start" here.
    – user949300
    Commented Aug 28, 2017 at 19:36
  • @user949300: The caller of "ensureHttpServerIsRunning" doesn't care about configuration, root directory etc. That's the business of the person who implements it.
    – gnasher729
    Commented Aug 30, 2017 at 4:15
  • 2
    @gnasher729 That assumes the http server is a Singleton. Singletons are evil. And possibly inappropriate here. One could easily have multiple servers on multiple ports. If there is truly just one http server, this entire method is, IMO, bad design Better to just start the server once at program initialization.
    – user949300
    Commented Aug 30, 2017 at 4:20
2

I suppose that your colleague meant that startHttpServer is doing too much:

  • Checking whether the server is already running,
  • Starting the server if needed.

Those are two unrelated parts of code. For instance, a similar situation exists when a desktop application should ensure that it's not already running when launched; there will be a part of code which handles app instances (for instance using a mutex), and the code which will start the application message loop.

This means that you have to have not one, but at least¹ two methods:

  • isHttpServerRunning: boolean
  • startHttpServer

The application entry point will call the first method, and then the second one if the return value is false. Now, every method is doing one and one thing, and is easy to understand.


¹ If the logic needed to know if the server is already running is too complex, it may require further separation into multiple methods.

6
  • 21
    Now something else calling the two functions is doing two things, plus, exposing the functions separately may introduce race conditions. No free lunch. Commented Aug 27, 2017 at 7:05
  • 1
    If that's too much for the colleague, good luck.
    – gnasher729
    Commented Aug 27, 2017 at 7:40
  • @gnasher729: this answer does not contradict yours - quite the opposite, it might indeed be a good ideat to combine the renaming of the method with splitting it up into two. And as long as we don't see the real code, we don't know how complex the code is.
    – Doc Brown
    Commented Aug 27, 2017 at 10:57
  • 10
    This answer seem to oppose abstraction and DRY. What if startHttpServer is called more than one place in the code? Should multiple similar lines be copy-pasted everywhere? Should this be done with all functions? Pretty soon you program will be infinite size.
    – JacquesB
    Commented Aug 27, 2017 at 11:12
  • 3
    I think the first side-effect of this approach is that the start of the startHttpServer method will look roughly like if (isHttpServerRunning()){ return; }. You're asserting a business rule that "it's not valid to start the http server if it's already running", but then making it someone else's responsibility to enforce that rule. Ad-hoc and repeatedly in every location where they might call startHttpServer.
    – aroth
    Commented Aug 28, 2017 at 8:13
2

Since you don't specify a language, in JavaScript many libraries have a "once" function e.g. Underscore. So, if that would be familiar to you, call it a "once" pattern and possibly rename your method.

Myself, coming more from Java, the terms "caching" or "lazy evaluation" come to mind. "Idempotent" is technically correct and a good choice, esp. if you have a more functional background.

4
  • It might not be "once", if the server can be stopped.
    – gnasher729
    Commented Aug 30, 2017 at 4:17
  • @gnasher729. I could imagine a rarely used restartHttpServer() method. But just stopping - what's the use case there? You like sporadic connection failures? :-)
    – user949300
    Commented Aug 30, 2017 at 4:37
  • There doesn't need to be a use case for just stopping the HTTP server because it may have been stopped by something external to the program itself - the HTTP server may have segfaulted and died, an admin may have manually stopped it for some reason, etc. Commented Aug 30, 2017 at 13:21
  • Dave, a crash is "exceptional" and should be handled as such. Besides, since a crash can happen anytime, wouldn't every line of your code have to be ensureRunning()? :-) As for the admin stopping it, having this other code constantly restarting while the admin is trying to modify or fix something would be incredibly annoying and wrong. Let the admin restart it, not the code.
    – user949300
    Commented Aug 30, 2017 at 18:09
-2

I'd prefer startHttpServerIfNotIsRunning.

This way, the condition is clearly mentioned already in the method name. Ensure or makeSure seems a bit vague to me, as it is not a technical expression. It sound like we don't know exactly what's going to happen.

6
  • I'm assuming you're not a native speaker? Because ensure has the exact definition of what we're going for. But still it's a fair point that documentation and APIs should not require native English speaker levels to be understandable.
    – Voo
    Commented Aug 28, 2017 at 13:09
  • 1
    Thanks I exactly not what Ensure means. I still don't like this word for a technical expression. Ensure is something human. A system cannot ensure anything, it only will do what it's supposed to do.
    – Herr Derb
    Commented Aug 28, 2017 at 13:11
  • 2
    @Voo - I'm a native speaker and I'm not sure what ensure means. Commented Aug 28, 2017 at 13:53
  • Since everyone posting here has access to the internet, why wouldn't they look up the definition of 'Ensure' if they weren't sure what it meant? A bit of trivia...many people interchange the usage of 'Ensure' and 'Assure' without realizing that using one of those words could inadvertently make them 'legally' responsible while the other would not.
    – Dunk
    Commented Aug 28, 2017 at 20:46
  • @jcast: Seriously?
    – gnasher729
    Commented Aug 30, 2017 at 4:18
-3

What your colleague should have told you is that you have no business writing that method. It's already been written plenty of times, and written better than you're likely to write it. For example: http://docs.ansible.com/ansible/latest/systemd_module.html https://docs.saltstack.com/en/latest/ref/states/all/salt.states.service.html

From an architectural perspective, having some arbitrary bit of code managing a web server is the stuff of nightmares. Unless managing services is exclusively what your code does. But I'm guessing you didn't write monit (or kubernetes or ...).

2
  • 2
    The language is Java and the method was designed to start a grizzly embedded server in a stand-alone Jersey application. I can't fault the accuracy of your comment, given I didn't give you much context, but you assumed a lot in making your statement. It's perfectly fine to have a method that calls into jetty or grizzly to start the server. Commented Aug 28, 2017 at 18:54
  • 1
    There are millions of business applications that include self-hosted HTTP server to provide an API. And all of those will need some very simple code that actually sets up the library they're using and provides information such as which interface to bind on, which port to use, security settings, etc. Having a startServer function or similar is anything but uncommon. That doesn't mean you'll write the nitty-gritty low level details.
    – Voo
    Commented Aug 28, 2017 at 19:46

Not the answer you're looking for? Browse other questions tagged or ask your own question.