The immediate mode abstracted quite a lot from the actual operations OpenGL performed and while it was easy to learn, it was hard to grasp how OpenGL actually operates. However, it's also more difficult to learn. The advantage of learning the modern approach is that it is very flexible and efficient. Whenever we try to use one of OpenGL's deprecated functions, OpenGL raises an error and stops drawing. When using OpenGL's core-profile, OpenGL forces us to use modern practices. For that reason the specification started to deprecate immediate mode functionality from version 3.2 onwards and started motivating developers to develop in OpenGL's core-profile mode, which is a division of OpenGL's specification that removed all old deprecated functionality.
The immediate mode is really easy to use and understand, but it is also extremely inefficient. Developers eventually got hungry for more flexibility and over time the specifications became more flexible as a result developers gained more control over their graphics. Most of the functionality of OpenGL was hidden inside the library and developers did not have much control over how OpenGL does its calculations. In the old days, using OpenGL meant developing in immediate mode (often referred to as the fixed function pipeline) which was an easy-to-use method for drawing graphics. The specifications also provide a great reference for finding the exact workings of its functions. The interested reader can find the OpenGL specification of version 3.3 (which is what we'll be using) here which is a good read if you want to delve into the details of OpenGL (note how they mostly just describe results and not implementations). Khronos publicly hosts all specification documents for all the OpenGL versions.
This is one of the reasons why it's always advised to occasionally update your graphic drivers.
Since most implementations are built by graphics card manufacturers, whenever there is a bug in the implementation this is usually solved by updating your video card drivers those drivers include the newest versions of OpenGL that your card supports. This also means that whenever OpenGL is showing weird behavior that it shouldn't, this is most likely the fault of the graphics cards manufacturers (or whoever developed/maintained the library). When using an Apple system the OpenGL library is maintained by Apple themselves and under Linux there exists a combination of graphic suppliers' versions and hobbyists' adaptations of these libraries. Each graphics card that you buy supports specific versions of OpenGL which are the versions of OpenGL developed specifically for that card (series). The people developing the actual OpenGL libraries are usually the graphics card manufacturers. Since the OpenGL specification does not give us implementation details, the actual developed versions of OpenGL are allowed to have different implementations, as long as their results comply with the specification (and are thus the same to the user). It is then up to the developers implementing this specification to come up with a solution of how this function should operate. The OpenGL specification specifies exactly what the result/output of each function should be and how it should perform. However, OpenGL by itself is not an API, but merely a specification, developed and maintained by the Khronos Group. OpenGL is mainly considered an API (an Application Programming Interface) that provides us with a large set of functions that we can use to manipulate graphics and images. Before starting our journey we should first define what OpenGL actually is.