Closed (fixed)
Project:
Commerce Stock
Version:
8.x-1.x-dev
Component:
Code
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
16 May 2016 at 14:45 UTC
Updated:
15 Jun 2018 at 05:34 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
agoradesign commentedI'll assign this to me, as I'm currently reviewing and tidying up a little bit. A patch + comments will follow :)
Comment #3
agoradesign commentedWoooo, reviewing all the code took quite more time than a thought (plus a bottle of wine :D)
Attached is a patch, that mostly...
(some kind of) disclaimer:
What I did, was some very low-level work. I may have missed intentionally or unintentionally some other potential improvements. I'm also not sure, if that meets 100% Drupal coding standards, but it's at least a big leap towards to that.
I haven't installed and used commerce_stock at all. All changes and adjustments I propose in the patch are untested, but I did it cautiously and with good tool support. But reviewing and testing the changes before committing would be a good idea anyway.
Some general impressions gained during review
One impression, that I've got on several places is that the module hasn't fully arrived in D8/Symfony2 yet. This is evident in many function definitons, where several IDs and arrays are passed around, or especially in the storage submodule: until now, I haven't really seen hook_schema implementations in D8, most likely as it's easy as it can be to define custom entity types in D8 -> if you define an custom entity type e.g. for cs_inventory_transaction, you wouldn't have to write much more lines of code in D8. instead of the database-centric hook_schema implementation, you would define your own entity class, add the necessary annoations, base field definitions and additionally all the getter/setter and additional methods you want to have -> with actually not really much more work you'll get a fully typed entitiy class, that you can enrich with any custom functions you like. Additionally, all the parts, where you use the deprecated db_insert() calls, would be even easier to replace - you could use YOUR_ENTITY_CLASS::create([values])->save(); instead and would be fully D8.2 compatible.
Another point, that I've already mentioned before, is that the whole structure of all the classes, services, interfaces, etc defined here, is quite confusing. Of course, the whole topic and the targeted goals of this module cover a very complex scenario, so it's clear, that the structure can get quite complicated of course. But especially in this constellation, one should try to not add too much unnecessary complexity.
This was even hardened by the fact, that the current state of code comments is quite weak. In my patch, I tried to add at least a basic documentation - at least I had to find out the data types of the involved variables, etc. And then I really sometimes got lost somewhere in between all the different classes, that are partly quite tightly knit to each other. Some examples:
On the one hand, I saw some strange circular dependencies: e.g. the StockManager initializes a property holding a StockManagerConfig object in its constructor, which itself takes the StockManager as reference. I don't know, if Symfony2 would find a way to handle this, if both would be services and dependency injection would be used - but e.g. Spring Framework wouldn't compile due to a CircularDependencyException.
And finally one thing, that confused me really very much, is a combination of naming and structure. On the one hand, there's one big directory containing all different interface and class implmentations (see #2726581: better organisation of classes and interfaces), and some classes are implementing several of these interfaces (which is basically ok). On the other hand there some unclear namings, like "AlwaysInStock" and "AlwaysInStockService", which seemed to me to be directly connected to each other, but aren't. I believe, in this case, not the class names are bad, but the fact that they are in the same namespace, listed directly one after another, together with lots of XxxInterface and Xxx class defintions within the same directory/namespace.
And last but not least a very important hint, that I don't want to hide: after having it a very long time on my personal radar without ever trying, we recently decided to try and soon after decide to switch from Eclipse/Aptana to PhpStorm as our preferred IDE. We really fell in love with that tool!!! I believe, that so far I only used a small portion of the possibilites the software offers, but the gain of time, comfort and especially code quality is incredible! I tell you because many of the harmless code style adjustments, as well as problems you wouldn't see without a sophisticated IDE, wouldn't be possible without the usage PhpStorm at all -> I'll open up a separate issue right after this commit about a problem I've found only because of the great validation of that IDE...
Comment #4
agoradesign commentedComment #5
guy_schneerson commentedWow agoradesign that's amazing.
Great timing I just upgraded my Coder Sniffer yesterday, will review and test before committing. I will especially pay attention to any refactoring you have made.
Let me start by addressing what I consider the most important point in your comments as it relates to a core design concept I have made and wish to defend it, however please let me know if you are are not convinced.
The choice of using the schema and not the entity API was an intentional one. The transactional approach I have taken has a number of important design concepts that I think are not suitable for the entity API.
The transactional system was designed to suport high volume and high performance with theoretically no possibility of deadlocks & performance bottlenecks.
The concepts are:
User activity:
- Each transaction (sale & new stock) will use a single insert & each stock movement will use two inserts.
- Transactions are not updatable. Same as traditional accounting, you made a mistake, create a transaction to balance the mistake. Example: creating a credit note.
- Stock checking involves two select queries one is a transaction sum using the primary index (transaction ID).
Cron:
- Regularly sums up transactions into the "inventory location level" (cron job not written yet so have to use the dev module to run this) this makes sure the second select query can run on a manageable dataset instead of infinitely growing.
- Cron jobs are the only process allowed updates on the "inventory location level" so not introducing a chance of deadlocks.
A similar approach is used by other ERP and inventory systems. Looks to me like the Drupal entities as amazing as it is, is not the correct tool for the job but I am open to be convinced otherwise if you think such is the case.
The locations are the only table that I think should probably be converted to an entity but it is of low importance for me at this stage as it has a mainly a passive part.
As far as the developer tools module go, as the module description states, this is a temporary module that is only used for the early development stage and should be viewed as a sandbox. It is possible that it contains code that's no longer relevant. However I will review all your code changes including this module.
I am totally in agreement about better organisation of the code as I believe all the complexity it holds is for a good reason and that good naming and folder structure are important to make the code easier to understand and work with.
I am aware I am speeding through things and taking some compromises along the way however I am close to having a working version of the module and hopefully the architectural decisions I have taken are all sound and the rest can be cleaned up.
I will review all your other comments and code changes and get back to you but I am amazed at the amount of work and excited about improvements to the code. thanks a lot for this patch and the effort you have put into it it is really appreciated.
Comment #6
agoradesign commentedYou're welcome. I also configured Code Sniffer in my PHP Storm yesterday and was looking for a "victim" to test, if it's working. I remembered our discussion and thought checking this module would be a nice idea :)
regarding the architecture: these are very good arguments :) I must confess that I don't have very much low-level knowledge about what is going on in the Entity API behind the scenes. As there are pre and post save hooks on inserts and updates, the entity approach of course can't be better in performance theoretically. On the other hand, if you design your system so, that none of these hooks are really implemented, there shouldn't be too much difference in performance. And I also don't know, if there's more risk of deadlocks!?? But I'm definitely not the right person to estimate this. Maybe you could ask Wim Leers about that, as he is a real performance ninja, or fago, as he is the founder of Entity API, or bojanz,...
One thing I know about D8 entities - based on my own experience - that you can design them to only reside in a single table. If your entities are non translatable, not fieldable, not revisionable and do not have one to many relationships in their base field definitions, you only will have one table in the database, no extra "data" table like the ones we know from nodes, terms,...
If you don't want entities to be updateable, you can prevent this easily - you could even prevent saving in a pre-save hook :D
In the end, for me as potential developer using the module, it shouldn't make too much difference whether or not you use low-level schema definitions and SQL queries or not, as long as the module's API is powerful enough to cover all the needs and works as expected :-)
Anyhow, I'm looking forward to this module. I was concentrating yesterday much on commenting, removing unneeded blank lines, imports, etc, so that I didn't look too much into the actual semantics of all the bits and bytes I saw, but after all I saw there and read from your posts and comments, I'm pretty sure that it will be a giant evolution step in comparison to the much simpler D7 version...
Comment #7
guy_schneerson commentedHi agoradesign jsut applied the patch and tested and looks like functionality all working as expected. the only thing that failed was the StockAvailabilityChecker code you identified in the other issue, a good sign.
Will do so more testing and go over all the code to make sure I understand changes before committing.
Interesting observations about the entity API and if I can validate it can bee as safe to use as the schema code then it can be swooped at a later stage.
Comment #9
guy_schneerson commentedagoradesign fantastic patch committed.
You know what they say "The devil is in the details" and I just created a code sniffer report and it produced a report that is 666 line long, I kid you not. So I will do my best to chase him out of earth.
looks like mostly superficial changes so I am sure not as bad as it looks.
Comment #10
agoradesign commentedhaha, I believe you. The module is quite big. If code sniffer always complains about the same few superficial rule violations, the report will grow quickly
Comment #12
guy_schneerson commentedfixed all coding standards issues with the exception of the dev module (as it will go).
We should check again wen the module is closer to being ready.
Comment #13
agoradesign commentedGreat work!
Comment #15
steveoliver commentedSince the latest commits, we've accrued some coding standards issues, if we are to use Drupal coding standards officially. See https://travis-ci.org/steveoliver/commerce_stock/jobs/175921201.
Can we re-open this issue and resume work?
Comment #16
steveoliver commentedComment #17
guy_schneerson commentedComment #19
cosmicdreams commentedRan a check today using phpcs and found over 3k recommended code standards cleanup. I think I'll start here if that's ok.
Comment #20
cosmicdreams commentedFirst pass. Fixes all but the dependency injection code formatting standards. Those will require some more extensive changes to the construct and create methods of the objects.
Comment #21
guy_schneerson commentedThanks @cosmicdreams will review.
Comment #23
guy_schneerson commentedThanks @cosmicdreams
I committed all your changes except the StockTransactions1 & StockTransactions2 forms as those contained an important @todo item. Thanks again, great work :)
Comment #24
cosmicdreams commentedSecond pass. This one fixes a number of places where container injection is recommended to be used (by our coding standards)
Comment #25
cosmicdreams commentedAfter reviewing how that looked once it got up here I noticed I'm rewriting the docblock on a few functions and some curious things came along for the ride. Here's a new patch and let's discuss:
Comment #26
cosmicdreams commentedThis is the bulk of what I'm trying to do for the SimpleStockLevelFormatter and the SimpleStockLevelWidget. Inject the services that have been brought in by \Drupal
My IDE tells me about Exceptions that we should include in the docblocks all the time. Well, usually for cases where we haven't handled an Exception that could come up.
I wasn't expecting StockConfigForm to be missing methods that the ConfigFormBase requires extended objects to override.
Comment #27
olafkarsten commentedthanks @cosmicdreams. Some nitpicks from me
Should be $stock_service_manager
I don't see the declaration of the $request class property?
Comment #28
olafkarsten commentedAs far as I know coding standard has no rule for wrapping function declarations and calls. In times of DI the arguments list tends to be undreadable awful long.
I think we should always wrap them if long. But thats Guys decision, i guess.
See #1539712: [policy, no patch] Coding standards for breaking function calls and language constructs across lines for more background on this.
At least we should be consistent. Wrap or not to Wrap - @guy_schneerson - that's your turn
Comment #29
olafkarsten commentedWhich one looks better :D
Comment #30
cosmicdreams commentedI do prefer the second. I don't mind long documents. I may have an opportunity to make these changes tonight.
Comment #31
cosmicdreams commentedI've included those recommendations @olafkarsten. I eventually declined the change to vertical-ize the __construct methods but added the changed to the create methods.
Comment #32
cosmicdreams commentedComment #33
cosmicdreams commentedComment #34
olafkarsten commentedRerolled the patch and created a PR
https://github.com/BBGuy/commerce_stock/pull/45
otherwise it wouldn't apply after the changes introduced in PR 43/44 if they gets commited before the patch. Otherwise works.
Comment #35
guy_schneerson commentedThanks @cosmicdreams and @olafkarsten for an excellent job.
Looks good and i also prefer warping long lines. I was just never sure about the coding standards.
Will need to spend some time reviewing this as it does make some more significance changes beyond just wrapping line and spaces. but all look like good changes. So will start with this issue next time I get a chance.
Comment #37
guy_schneerson commentedAll changes but 1 are now committed (I think I may have committed the more straightforward changes in a separate commit).
The changes to StockTransactions2 was not committed as it was causing an error "Recoverable fatal error: Argument 3 passed to Drupal\commerce_stock_ui\Form\StockTransactions2::__construct() must be an instance of Symfony\Component\HttpFoundation\Request"
will be happy to push that one file as a patch or a new PR.
Comment #38
cosmicdreams commentedCool, I'll take a look. In the future, would you prefer a PR via github or a patch via D.O?
Comment #39
guy_schneerson commentedA PR is preferable but if its a small change a patch is ok.
Comment #40
cosmicdreams commentedhttps://github.com/BBGuy/commerce_stock/pull/54
Comment #42
guy_schneerson commentedThanks @cosmicdreams merged and pushed.
Comment #43
olafkarsten commented