5 ms·
Nice, congratulations. It must feel so surreal launching this! One of my biggest learnings from doing a bunch of web MVC through Rails over the years is that t
by kvirani 2y ago
Nice, congratulations. It must feel so surreal launching this!
One of my biggest learnings from doing a bunch of web MVC through Rails over the years is that the framework should heavily discourage business logic in the model layer.
Some suggestions:
- Don't allow "callbacks" (what AR calls them) ie hooks like afterCreate in the data model. I know you don't have these yet in your ORM, but in case those are on the roadmap, my opinion is that they should not be.
- That only really works though if you not strongly encourage a service aka business logic layer. Most of my Rails app tend to have all of these as command aka service objects using a gem (library/package) like Interactor.*
* It's my view that MVC (and therefore Rails otb) is not ideal by itself to write a production-ready app, because of the missing service layer.
Also, curious why existing ORMs or query builders from the community weren't leveraged?
Disclaimer: I haven't written a line of Rust yet (more curious as the days go by). I'm more curious than ever now, thanks to you!
- sodapopcan 2y ago> * It's my view that MVC (and therefore Rails otb) is not ideal by itself to write a production-ready app, because of the missing service layer. This is quite the claim. I despise service objects, personally. They end up scattering things around and hurt discoverability. There are other ways to do modelling that scale very well. There are a few blog posts on it, here's one from someone at Basecamp: https://dev.37signals.com/vanilla-rails-is-plenty/ https://dev.37signals.com/vanilla-rails-is-plenty/ This is of course very OO which I'm not a huge fan of. Elixir's Phoenix framework, for example, uses "contexts" which is meant to group all related functionality. In short they could be considered a "facade." In any event, if you like services you like services, they can work, but saying MVC isn't enough for production-grade is a bit misguided. I do agree that model callbacks for doing heavy lifting business processes is not great, though for little things like massaging data into the correct shape is pretty nice.
- jt2190 2y agoIt would help a lot if you would clarify what you mean by “service object”. In my experience a single method on a service object would define a transaction. Is that what you mean by “service object”?
- sodapopcan 2y agoAlong the lines of what OP is talking about, part of the problem is that Rails has no service objects, so I have seen a handful of different ideas of what they mean (probably no more than 10). The one I've seen he most is stuff like `UserRegistrationService` or the like. These things can end up getting scattered and in general, I would rather just talk to the business object, ie, `User.register` which can delegate to a more complex private object handling it. It's basically "inverting" things. The win here is that things are more discoverable (You can look at the user object and see a list of everything it does) and more importantly draws better boundaries. This way the web layer only has to know about `User` instead of `RegisterUserService` and `DeleteUserService` etc. Again, services can work and aren't inherently bad, but plain MVC can certainly also work.
- CSSer 2y agoI feel like the same people that like UserRegistrationService will argue that database table names should be plural because it reads better, which is wrong for similar reasons.
- sodapopcan 2y agoI don’t really follow. My focus wasn’t on the naming but the location of responsibilities.
- CSSer 2y agoI understood. Perhaps my mental connection was somewhat flimsy though. I was trying to make a tongue-in-cheek joke about how whenever I work on a database that has tables with overloaded responsibilities (poor normalization) instead of proper foreign keys they often also coincidentally have poor, plural names. Whenever I encounter such a thing, I think about the story of how it became that way. Usually part of the story includes a developer looking for a place to stick some logic and deciding an arbitrary place seems good enough because it’s a bit vague.
- ecshafer 2y ago> One of my biggest learnings from doing a bunch of web MVC through Rails over the years is that the framework should heavily discourage business logic in the model layer. I am curious where this comes from, because my thinking is the absolutely opposite. As much business logic as possible should belong in the model. Services should almost all be specific more complex pieces of code that are triggered from the model. Skinny controller, Fat Model, is the logic of code organization that I find makes code the easiest to debug, organize, and discover. Heavy service use end up with a lot of spaghetti code in my experience. The other part is that from a pure OOP pov, the model is the base object of what defines the entity. Your "User" should know everything about itself, and should communicate with other entities via messages. > Don't allow "callbacks" (what AR calls them) ie hooks like afterCreate in the data model. I know you don't have these yet in your ORM, but in case those are on the roadmap, my opinion is that they should not be. This I agree with. Callbacks cause a lot of weird side effects that makes code really hard to debug.
- idle_zealot 2y agoThis sounds to me like the standard OOP versus Data Oriented programming divide. You want to think of code as a bunch of bundles of data and associated functionality, GP wants to think of code as data models and services or functions that act on them.
- yoyonamite 2y agoIt's because people ended up with models that were thousands of lines and difficult to reason about. Out of curiosity, did you end up running into this issue and how did you deal with it?
- throwaway313373 2y agoIf I had to choose between thousands lines in models and thousands lines in controllers I'd definitely take "fat" models over "fat" controllers.
- ecshafer 2y agoI work on a few projects that do have a model that is over a thousand lines long. A lot of times as the model gets more complex, you start moving associated model logic into their own models, which helps reduce the problem space. I think its fine because the logic ends up being cohesive and explicit. Whereas services end up with logic being hard to track down when they get very large and usually scattered.
- LeftHandPath 2y agoInteresting. I’ve rolled my own PHP ORM at work (forbidden from using FOSS libraries like Laravel) and found hooks to be extremely useful. Notably, my programming experience started with PHP for Wordpress which used hooks extensively, so maybe I’m biased. Mine has a table spec that can translate into a SQL definition or spit out a nicely formatted HTML form. There’s a separate controller that handles all DB connections / CRUD operations, with before- and after-hooks that can easily cross reference with other tables and constraints if needed. It all works pretty nicely, although I would still switch to Laravel in an instant if I could.
- freedomben 2y agoPlease don't feel obligated to answer if you can't, but why can't you use FOSS libraries like Laravel? Are you not even allowed to use MIT licensed stuff? What industry do you work in?
- LeftHandPath 2y agoSmall aerospace company. We had a really old school CEO at the time the project was started - didn’t even want us using GitHub since it was on the cloud. Everything runs on an on-premise IBM i Series (AS400 / IBM Mainframe). I pushed hard and was able to get us to the point where stuff runs in PASE with modern languages (like PHP). It’s not any specific licensing issue, just organizational distrust of anything that isn’t paid for.
- ensignavenger 2y agoAre there not any Laravel shops that would take your money so you can "pay" for it?
- LeftHandPath 2y agoHah, I’m currently trying that tactic to get us on Bookstack for our SOPs. Never thought about doing it with Laravel. Could work!
- globular-toast 2y agoWhat even is a "model" if it doesn't have business logic? It sounds like you just want your model to be built from structs (that you call models) and procedures (that you call services). You can do that, but it can be quite hard to reason about what ways an entity can be updated, because any number of procedures could do it and all have their own ideas about what the business rules are. At this point your procedures might as well write back to the db themselves and just get rid of the "models".
- pdhborges 2y agoSome people use the ORM models as pure persistence models. They just define how data is persisted. Business models are defined elsewhere. I think makes sense when you application grows larger. Domains become more complex and eventually how data is persisted can become quite different from how it is represented in the business domain.
- DeathArrow 2y agoI do agree that models should not contain bussiness logic. Not having bussiness logic in models is what Martin Fowler and Robert C. Martin call "anemic domain models" and is contrary to how legacy OOP-heavy and pattern-heavy enterprise development used to be. However, after +20 years of development, I've came to the conclusion that encapsulation is a burden, not a feature and data should be separated from actions that are being performed on that data. It's called data oriented design or data oriented programming, and I am far from the only one that came to the same conclusion.
- cies 2y agoI so much agree with this, I want to hug you. All this encapsulation for sake of encapsulation, and interfaces everywhere even for implementations that the application is married to. I once heard a wise man say: most of these design pattern only add code! And we should be weary of adding code that does not add features. Sure in some cases it makes the code easier to understand/read/refactor. But in many cases it becomes a holy goal with very little actual benefits. Clean architecture being the epitome of this. > data should be separated from actions that are being performed on that data This view is shared by nearly all dev that prefer functional programming. I also consider this true. FP-langs help you to "keep 'm separated", and OOP-langs historically make this very hard. If you build an app on top of a db, you biz logic will get intertwined in the queries and the some of the code that's close to those queries (i.e. model code). That code represents you business logic. Trying to write the biz logic separate from the db is --to me-- just a way to make your project go over budget and hurt your performance.
- DeathArrow 2y ago>OOP-langs historically make this very hard I don't think is just the langs, but mostly the old culture around those. I do .NET development using a data oriented approach and nobody calls me an incompetent developer. I also teach junior colleagues to be vary of OOP-ness for the sake of OOP-ness and overusing patterns. I am not aware of any OOP language that demands inheritance, encapsulation or method overriding. It's the people who do. >If you build an app on top of a db, you biz logic will get intertwined in the queries and the some of the code that's close to those queries (i.e. model code). That code represents you business logic. Trying to write the biz logic separate from the db is --to me-- just a way to make your project go over budget and hurt your performance. I tend to separate, when possible, business logic from DB logic and from other kind of input like calling into external APIs. But I do that trough layers. I put a repository over the DB and its job is to just fetch data from DB and deliver it as data structures. I use that repository in a business layer.
- DeathArrow 2y ago>* It's my view that MVC (and therefore Rails otb) is not ideal by itself to write a production-ready app, because of the missing service layer. How is that so? Can't you add a service layer and call a service from a controller? I don't know about Ruby but for .NET and most Java frameworks this is possible. To take an example from .NET frameworks, which I am mostly familiar with, you use WebAPI for web applications and MVC for websites. An API just returns data in JSON or whatever form and MVC returns HTML + javascript + whatever media and files. A controller receives the HTTP request, does some logic, make DB requests, receives models and uses that logic to update a view and serves that view as an HTML file. Controller - does actions and uses logic View - describes how the page looks Model - contains data Nothing stops the controller to call a service layer which will call a data layer instead of just calling directly the DB.
- kitd 2y agoNot OP, but I think that what s/he's saying. By itself, MVC is not complete for production apps, ie don't put business logic in the model &| controllers. Rather it must be in a service layer which is entirely dependent on the developer to provide.
- levkk 2y agoThanks! Re: callbacks. They are very nice, when you have CRUD endpoints that modify models directly from JavaScript [1]. It ends up being pretty DRY, especially since you'll find yourself modifying the same model from different places in the code, and without callbacks, you'll have bad data. Re: service layer. It's a matter of taste, and you can probably avoid it until you're way in the thousands of LOCs. Rails and Django are all about building quickly - that's an advantage you shouldn't give away to your competitors. Service layer is a drag that you may need as an "enterprise". Re: MVC not production-ready, we know that's not true, but appreciate the hot take, always a good starting point for a great discussion. Re: existing ORMs, they were not flexible enough. I used ActiveRecord and Django as my inspiration; those are both excellent ORMs, while existing Rust ORMs lean too heavily on type safety in Rust in my opinion. The database should be the source of truth for data types, and the framework should allow for intentional drift. Hope you get to try Rust soon. I've been using it for years, and I don't want to go back to Python or Ruby, hence this project. Cheers! [1] https://levkk.github.io/rwf/controllers/REST/model-controller/ https://levkk.github.io/rwf/controllers/REST/model-controlle...