-
-
Notifications
You must be signed in to change notification settings - Fork 139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Namespaces and PSR-4 compliance #283
Comments
I really like the introduction and consistent use of namespaces for the PHP track. As a test, I went ahead and modified my old bob code to follow the example above. I added a setupBeforeClass that performed a "require_once" on "../src/Bob.php". I also had to update my signatures of setup and setupBeforeClass to include the void return declaration, but after that it worked. I also tried this on the Accumulator exercise (function based). In addition to adding the directories and adding namespaces, I had to also add the use statement:
Similarly to Bob, I also added a
As a side note, I also noticed that all the tests that extend from \PHPUnit\Framework\TestCase do not seem to include the leading backslash. It still works, but I think PHP has to see if it knows about \Exercism\Accumulate\PHPUnit\Framework\TestCase and then it falls back to \PHPUnitFramework\TestCase. So, with all this, here's my take: I like using namespaces, and I fully support using them in the tests and the code. Since PSR-4 is about autoloading though, I don't think we're going to realistically do much about that. Unless we can introduce an autoloader (composer or custom) at the root of the ~/Exercism/php directory, it means we'll need one inside each exercise. If we introduce an autoloader at the root level (assuming that's even possible) then we need to presumably have either a root level config for tests (not sure if this would be feasible) or a test config in each exercise that loads the autoloader which then allows for loading the code and tests automatically. Since the exercises are not capitalized and we're introducing a src and test inside each, I think it means that if we were to go the PSR-4 composer route, then we'd need a composer.json at the root that lists every exercise's namespace (code and tests) mapped to the appropriate directories. I don't know for sure this is possible, and even if it is, I'm not sure it's worth it. The next potential option (again, not sure it's feasible) would be to introduce a custom autoloader in each exercise. Of course in order to use the autoloader, it needs to be loaded and registered. This means phpunit.xml files in every exercise and updates to the instructions of each exercise about how to run the tests. I'm not sure this is worth it either. With those two out of the way, a third option is to introduce an autoloader that we load and register within each test file. This would mean we don't need the phpunit configs, but creating and loading an autoloader for each exercise just so it can in turn autoload the class we're testing seems a bit silly and probably overkill. This leads back to either requiring the file we want to test in the test file, either directly as has been done in most of the tests currently (and is complained about by many static analyzers) or we load the file in the setupBeforeClass method which would need to be introduced to every test file where it doesn't exist already. As much as I'd like to have autoloading "just work", I don't think the structure or the idea of the separate exercises in Exercism lends itself to having an over-arching autoloading solution and introducing an autoloader for each exercise means instead of T -> S we have T -> A -> S where T is our test, A is the autoloader and S is our SUT. So to wrap up the wall of text with a TL;DR - I like the use of namespaces, and think we should introduce them to the exercises. I don't think autoloading is going to work very well within the structure of ~/Exercism and how all the exercises are essentially completely isolated. |
Thank you for that thourough testing and feedback! That is very valuable, I appreciate it. Yes, some tests will need refactoring. AccumulateTest is a very good example. Declaring multiple classes within one file is a violation. They should reside in their own files. AccumulateTest can then require and import these. At least that is how I would solve it. Haven't used custom callables in test so far. If there is a better practice, I'm open to it. The issue with the missing leading backslash on <?php
namespace ExercismTest\Bob;
use PHPUnit\Framework\TestCase;
use Exercism\Bob\Bob;
class BobTest extends TestCase
{
// [..]
} I agree, there is currently no clean solution to autoloading and is not part of this change. PSR-4 is only relevant to the definition and usage of namespaces. @petemcfarlane Is there something you would like to add? Not sure, if there are other active contributors, have not received any reaction in Slack. Otherwise I would go ahead and start working on a PR. |
One point I have been missing so far is the introduction of namespaces to the student. I am unsure whether to start with the first exercise or another. We could add the namespace to the |
Sorry to not be more involved in this issue, I've been on annual leave until today. I feel that exercism should have a very low barrier to entry where possible, but at the same time should introduce concepts and best practices to students where possible. Typically, I think nearly all modern PHP applications I have worked on have used Composer for dependency management and autoloading - though that's just my experience, does anyone have contrary experience? We could bite the bullet and just introduce Composer as a requirement. Heck - we could even introduce exercises that specifically show how to use third party dependencies if we do that!? Whilst most modern (and all PSR-4 conforming) applications would use namespacing combined with autoloading, there is a judgement to be made on how much extra work or overhead is there to think about/juggle these concepts, the value of using namespaces - along with the core exercise or problem that the student is trying to solve. It's a balance between exploring and learning the language, and solving a particular algorithm or problem. To me the main benefit of namespacing is a clear separation and ordering of logic, and PSR-4 provides a fantastic, easy (consistent and predictable), interoperable way to load If you just want an exercise to explicitly show how namespacing works, how about creating a new exercise which highlights namespacing/PSR-4 rules using various files, classes (and functions)? Another idea I had, which I didn't see you explicitly mention in the earlier conversation, is to create a I like the idea of having an |
Hope you had a great vacation! 😊 Although I acknowledge the almost omnipresence of composer, I am hesitant introducing it into exercism, since it is not native to PHP. The main value from adding namespaces is teaching a good practice, that will become most beneficial in a context outside of exercism. By introducing namespaces we give the students an opportunity to practice and understand the concept. If we use a one explicit exercism, the learning effect is much less. If there is one exercise introducing namespaces and following exercises building on that knowledge, it would be much better. These are great suggestions on how to solve possible issues with makefile and others. I believe, we need to first agree on how (far) we want to introduce namespaces. Everything else is dependent on that decission. My suggestion: Leave hello-world as-is. Introduce namespace in Gigasecond exercise with a prepared stub file and the exercise after that. From the third exercise on, provide only empty stub files, having the student declare namespaces him-/herself. Thoughts? |
Yeah I like your final suggestion. Do you think we can gradually introduce namespaces one exercise at a time in individual PRs? I guess we need to figure out how to run the example in travis, and find out why it's not included by the exercism-cli, @kytrinyx do you know about this or who we should speak to? |
I would like to first get an overview of all required changes. Can we open a separate branch for that? There we could build a prototype (for makefile, travis setup etc.) and collaborate. Doing so will not affect production. |
By default any file with You can override what will be ignored by specifying an |
Yes, I believe a separate directory for the example code has the benefits of a clear separation and allows easier management for cases with multiple classes (files). The structure would then look like the following.
A discussion @dstockto and I had in #288, was about the filenames for exercises using functions only. The PHP-FIG has no rule on naming function files. To distinguish between classes and function files, I like David's idea of naming the stub file @petemcfarlane Would that be okay with you? |
I don't mind the I've also seen (and quite liked) the file take on the namespace as a file name, so that would lead to
What do you think to that approach? |
Yes, that's possible. Although it introduces two issues: It makes it impossible to
|
Ok good point. I think situation 2 is unlikely in our exercise project but your first point is reasonable. Let’s go with functions.php then? 👍 |
There have been several breaking changes in the directory structure, the intended usage of the exercises (via website code editor) in preparation for Exercism v3. Are there plans to move foward with this, adapt them to v3? This affects both #287 and #288 as they depend on this being finalized as well as each of them to be updated for the new directory structure. As a side note, matrix tests (like using a data provider) are not straightforward to use in the website from a UI perspective (though I think the Go track with @ekingery is doing some work with these), so they are slightly discouraged. |
Thanks for the follow-up. It's exciting to see all the changes coming to the repo. 👏🏻 Wherever possible I would encourage the usage of best practices for a particular language and library (data providers). Luckily/unfortunately I am very busy and it does not look like I have the time to make a PR for v3 in the upcoming weeks. So, I make room for anyone who would like to pick it up from here. |
Thanks for your reply! I'll see how things with @ekingery and the go-track develop with their testing strategy, and keep it in mind to migrate to data providers in time. |
This might already be understood, but just in case not - I would not migrate to data providers until someone can do the work to support them in the test runner. It's possible, but really complicated things with the Go test runner and it still isn't in great shape. I'm not yet convinced the test runner and associated consumption of the |
One of the points I am missing in the exercises of this track is the concept of namespaces (PSR-4 compatibility). Therefore, I would like to discuss and propose the following change.
Suggestion
Each exercise separates actual business logic from tests by having separate
src
andtest
directories. TheREADME.md
stays in the exercise's root folder. The example solution (and coming stub file) are going intosrc
and the test file intotest
.Since there is no definition for declaration of functions pertaining to the filename, two possible solutions are crossing my mind. Either name the file
functions.php
orexercise-name.php
- both residing within the exercise's namespace. Here I am interested in suggestions, since I haven't used a file collecting various functions in years.Example
Taking Bob as an example, this would result in the following structure:
/src
→ namespaceExercism\Bob
Bob.php
(stub file)example.php
(example solution)/test
→ namespaceExercismTest\Bob
BobTest.php
README.md
Looking for feedback
My intention is to provide an even greater learning experience for the student within a modern (meaning current) environment.
It would be great to get some feedback on the suggestion over all and possible side effects I might not have fully considered yet (like implications on test automation etc.). Thank you!
The text was updated successfully, but these errors were encountered: