best_practices_for_engine_contributors.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. .. _doc_best_practices_for_engine_contributors:
  2. Best practices for engine contributors
  3. ======================================
  4. Introduction
  5. ------------
  6. Godot has a large amount of users who have the ability to contribute because the
  7. project itself is aimed mainly at users who can code. That being said, not all
  8. of them have the same level of experience working in large projects or in
  9. software engineering, which can lead to common misunderstandings and bad
  10. practices during the process of contributing code to the project.
  11. Language
  12. --------
  13. The scope of this document is to be a list of best practices for contributors to
  14. follow, as well as to create a language they can use to refer to common
  15. situations that arise in the process of submitting their contributions.
  16. While a generalized list of software development best practices might be useful,
  17. we'll focus on the situations that are most common in our project.
  18. Contributions are most of the time categorized as bug fixes, enhancements or new
  19. features. To abstract this idea, we will call them *Solutions*, because they
  20. always seek to solve something that can be described as a *Problem*.
  21. Best Practices
  22. --------------
  23. #1: The problem always comes first
  24. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  25. Many contributors are extremely creative and just enjoy the process of designing
  26. abstract data structures, creating nice user interfaces, or simply love
  27. programming. Whatever the case may be, they come up with cool ideas, which may
  28. or may not solve real problems.
  29. .. image:: img/best_practices1.png
  30. These are usually called *solutions in search of a problem*. In an ideal world,
  31. they would not be harmful but, in reality, code takes time to write, takes up
  32. space and requires maintenance once it exists. Avoiding the addition of anything
  33. unnecessary is always considered a good practice in software development.
  34. #2: To solve the problem, it has to exist in the first place
  35. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  36. This is a variation of the previous practice. Adding anything unnecessary is not
  37. a good idea, but what constitutes what is necessary and what isn't?
  38. .. image:: img/best_practices2.png
  39. The answer to this question is that the problem needs to *exist* before it can
  40. be actually solved. It must not be speculation or a belief. The user must be
  41. using the software as intended to create something they *need*. In this process,
  42. the user may stumble upon a problem that requires a solution to proceed, or in
  43. order to achieve greater productivity. In this case, *a solution is needed*.
  44. Believing that problems may arise in the future and that the software needs to
  45. be ready to solve them by the time they appear is called *"Future proofing"* and
  46. its characterized by lines of thought such as:
  47. - I think it would be useful for users to...
  48. - I think users will eventually need to...
  49. This is generally considered a bad habit because trying to solve problems that
  50. *don't actually exist* in the present will often lead to code that will be
  51. written but never used, or that is considerably more complex to use and maintain
  52. than it needs to be.
  53. #3: The problem has to be complex or frequent
  54. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  55. Software is designed to solve problems, but we can't expect it to solve *every
  56. problem that exists under the sun*. As a game engine, Godot will help you make
  57. games better and faster, but it won't make an *entire game* for you. A line must
  58. be drawn somewhere.
  59. .. image:: img/best_practices3.png
  60. Whether a problem is worth solving is determined by the effort that is required
  61. to work around it. The required effort depends on:
  62. - The complexity of the problem
  63. - The frequency the problem
  64. If the problem is *too complex* for most users to solve, then the software
  65. should offer a ready-made solution for it. Likewise, if the problem is easy for
  66. the user to work around, offering such a solution is unnecessary.
  67. The exception, however, is when the user encounters a problem *frequently
  68. enough* that having to do the simple solution every time becomes an annoyance.
  69. In this case, the software should offer a solution to simplify the use case.
  70. It's usually easy to tell if a problem is complex or frequent, but it can be
  71. difficult. This is why discussing with other developers (next point) is always
  72. advised.
  73. #4: The solution must be discussed with others
  74. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  75. Often, users will be immersed in their own projects when they stumble upon
  76. problems. These users will naturally try to solve the problem from their
  77. perspective, thinking only about their own use case. As a result, user proposed
  78. solutions don't always contemplate all use cases and are often biased towards
  79. the user's own requirements.
  80. .. image:: img/best_practices4.png
  81. For developers, the perspective is different. They may find the user's problem
  82. too unique to justify a solution (instead of a workaround), or they might
  83. suggest a partial (usually simpler or lower level) solution that applies to a
  84. wider range of known problems and leave the rest of the solution up to the
  85. user.
  86. In any case, before attempting to contribute, it is important to discuss the
  87. actual problems with the other developers or contributors, so a better agreement
  88. on implementation can be reached.
  89. The only exception is when an area of code has a clear agreed upon owner, who
  90. talks to users directly and has the most knowledge to implement a solution
  91. directly.
  92. Also, Godot's philosophy is to favor ease of use and maintenance over absolute
  93. performance. Performance optimizations will be considered, but they may not
  94. be accepted if they make something too difficult to use or if they add too much
  95. complexity to the codebase.
  96. #5: To each problem, its own solution
  97. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  98. For programmers, it is always a most enjoyable challenge to find the most
  99. optimal solutions to problems. It is possible to go overboard, though.
  100. Sometimes, contributors will try to come up with solutions that solve as many
  101. problems as possible.
  102. The situation will often take a turn for the worse when, in order to make this
  103. solution appear even more fantastic and flexible, the pure speculation-based
  104. problems (as described in #2) also make their appearance on stage.
  105. .. image:: img/best_practices5.png
  106. The main problem is that, in reality, it rarely works this way. Most of the
  107. time, writing an individual solution to each problem results in code that
  108. is simpler and more maintainable.
  109. Additionally, solutions that target individual problems are better for the
  110. users. Targeted solutions allow users find something that does exactly what they
  111. need, without having to learn a more complex system they will only need for simple
  112. tasks.
  113. Big and flexible solutions also have an additional drawback which is that, over
  114. time, they are rarely flexible enough for all users. Users end up requesting
  115. more and more functionality which ends up making the API and codebase
  116. more and more complex.
  117. #6: Cater to common use cases, leave the door open for the rare ones
  118. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  119. This is a continuation of the previous point, which further explains why this
  120. way of thinking and designing software is preferred.
  121. As mentioned before (in point #2), it is very difficult for us (as human beings
  122. who design software) to actually understand all future user needs. Trying to
  123. write very flexible structures that cater to many use cases at once is often a
  124. mistake.
  125. We may come up with something we believe is brilliant, but later find out that
  126. users will never even use half of it or that they require features that don't
  127. quite fit into our original design, forcing us to either throw it away
  128. or make it even more complex.
  129. The question is then, how do we design software that both allows users to do
  130. *what we know they need to do* now and allows them to do *what we don't yet know
  131. they'll need to do* in the future?
  132. .. image:: img/best_practices6.png
  133. The answer to this question is that, to ensure users still can do what they want
  134. to do, we need to give them access to a *low-level API* that they can use to
  135. achieve what they want, even if it's more work for them because it means
  136. reimplementing some logic that already exists.
  137. In real-life scenarios, these use cases will be at most rare and uncommon
  138. anyway, so it makes sense a custom solution needs to be written. This is why
  139. it's important to still provide users the basic building blocks to do it.
  140. #7: Prefer local solutions
  141. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  142. When looking for a solution to a problem, be it implementing a new feature or
  143. fixing a bug, sometimes the easiest path is to add data or a new function in the
  144. core layers of code.
  145. The main problem here is, adding something to the core layers that will only be
  146. used from a single location far away will not only make the code more difficult
  147. to follow (split in two), but also make the core API larger, more complex, more
  148. difficult to understand in general.
  149. This is bad, because readability and cleanness of core APIs is always of extreme
  150. importance given how much code relies on it, and because it's key for new
  151. contributors as a starting point to learning the codebase.
  152. .. image:: img/best_practices7.png
  153. A common reason for wanting to do this is that it's usually less code to simply
  154. add a hack in the core layers.
  155. Doing so is not advised. Generally, the code for a solution should be closer to
  156. where the problem originates, even if it involves additional, duplicated, more
  157. complex, or less efficient code. More creativity might be needed, but this path
  158. is always the advised one.
  159. #8: Don't use complex canned solutions for simple problems
  160. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  161. Not every problem has a simple solution and, many times, the right choice is to
  162. use a third-party library to solve the problem.
  163. As Godot requires to be shipped in a large amount of platforms, we can't
  164. link libraries dynamically. Instead, we bundle them in our source tree.
  165. .. image:: img/best_practices8.png
  166. As a result, we are very picky with what goes in, and we tend to prefer smaller
  167. libraries (single header ones are our favorite). We will only bundle something
  168. larger if there is no other choice.
  169. .. _doc_best_practices_for_engine_contributors_license_compliance:
  170. Libraries must use a permissive enough license to be included into Godot.
  171. Some examples of acceptable licenses are Apache 2.0, BSD, MIT, ISC, and MPL 2.0.
  172. In particular, we cannot accept libraries licensed under the GPL or LGPL since
  173. these licenses effectively disallow static linking in proprietary software
  174. (which Godot is distributed as in most exported projects). This requirement also
  175. applies to the editor, since we may want to run it on iOS in the long term.
  176. Since iOS doesn't support dynamic linking, static linking is the only option on
  177. that platform.