Tbh, I think the main lesson is simply to not try to work around the specific 3D API conventions too much, e.g. don't try to shoehorn mechanisms into the D3D11 layer that would be straightforward in Vulkan or D3D12 but would disable the special fast-paths in D3D11.
E.g. for a traditional "one uniform update per draw call" loop with one small constant buffer per shader updated via plain old UpdateSubresource(), D3D11 is incredibly fast (you can easily do hundreds-of-thousands update+drawcall pairs like this per 60Hz frame on a somewhat recent - e.g. post-2016 or so - mid-level gaming PC.
Of course trying to emulate D3D11 on Vulkan or D3D12 might have all sorts of issues that don't exist on a good "native" D3D11 driver.
Also somewhat related: in a GL shim it's typically still faster to update uniform data via the old glUniform*v calls instead of using uniform buffers, apparently most GL drivers lack the special fast-path optimizations of small D3D11 constant buffers, and the more abstract glUniform calls seems to give the driver more 'wiggle room' to implement an optimal upload path.