When we want to set a texture as one uniform, we cannot bind a texture id to a program, we have to establish the relationship like below:
textureId <-> texture unit <-> set Uniform
Is the concept of "texture unit" little redundant?
Is there something special here so that it is useful as an intermediate?
There are limits to the number of textures that a shader can access (in theory). These limits are distinct from the limits on the number of uniforms and other parameters that shaders can access.
Furthermore, by making texture objects not be part of program state, it allows you to change programs without changing what textures are being used. Two different programs can reference the same texture unit (for example, a shadow map). With your way, we would have to attach the shadow map to every program that uses it. With the current way, we bind it once, and let the programs decide what they use.