The static render is not primarily for seo. Proper seo is just so prominent given SPAs basically made it a problem in the first place.
Much more importantly: A browser cannot connect to a websocket connection immediately. It needs to do a plain http request first, which returns html linking some js, which then can attempt to connect to a websocket endpoint. So by definition there need to be two connection attempts to your server. On the http connection you don’t know yet if the client is even able to connect to the websocket endpoint for the second connection.
Given Phoenix cannot know exactly how you want to deal with that failure of the websocket connection failing it can just give an API to users, which allows them to implement it however they need. This is
connected?/1. You can decide what you render in the static render vs. any connected renders – which is not just the second one, but any fresh websocket connection made (think about reconnects).
That’s the part about failure modes.
Now the other fact people often don’t think about is the case of everything going according to plan. I initially talked about the browser not being able to connect to websockets before having the necessary js. This only affects the very first request a user makes in a given session. After that the js is on the browser and navigation can happen completely over websockets (live redirects and patching), thereby completely skipping the static render. The new stuff is directly mounted in connected mode over websockets. This means you might not even need to be so concerned about db requests being made twice. Unless the page is commonly hit at the start of a user session it might not even be rendered statically all to often in the first place.
As for the code concern: If you over and over use the same code for doing one thing for the static render and some other custom thing only when connected nobody prevents you from abstracting that into some helpers, maybe even an additional behaviour with different callbacks + some macro for the boilerplate. There are means of DRYing this up, if you truely deal with each case the same.