TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

The controller pattern is awful, and other OO heresy (2013)

148 点作者 thatxliner将近 2 年前

33 条评论

bedobi将近 2 年前
As a professional dev who has made a career out of working in oop languages and codebases, it took me far too long to realize that when it comes to oop, the emperor has no clothes.<p>To this day, oop advocates can&#x27;t even agree on what oop even is or means.<p>Apparently oop as envisioned by Alan Kay was supposed to work like cells in the body that pass messages between each other and take actions independently.<p>Why? Who knows! It was never really explained why literally one of the most complex systems imaginable, one that we still really have very little idea how it even works, should be the model for what could and should probably be a lot simpler.<p>Today&#x27;s modern oop languages are probably very far from what Kay envisioned (whatever that was), but it&#x27;s remains unclear why classes and objects are &quot;better&quot; than the alternatives.<p>And before anyone goes and comments aksully code organization blabla like yes but code organization can be great or shit in oop or fp or procedural codebases, it has nothing to do with the &quot;paradigm&quot;.<p>Let alone that the entrenched, canonical, idiomatic coding styles of most modern oop languages encourage state, mutability, nulls, exceptions and god knows how many trivially preventable entire classes of errors. Granted, most have now started to come around and are adopting more fp features and ideas every year, but still.<p>Don&#x27;t get me wrong, writing programs like cells in the body that pass messages between each other and take actions independently is an interesting idea which deserves pursuing, if nothing else but to satisfy our curiosity and seeing to what if anything it&#x27;s applicable and suited. (and even if the answer turns out to be &quot;nothing&quot;, we&#x27;ve still learned something!)<p>But going from there to making strong claims about it being a more or less universally superior paradigm for computing and writing code, with little to zero evidence, that&#x27;s a huge, huge stretch.<p>To the degree Erlang and Actors work, I think that&#x27;s kind of a happy coincidence, and not due to any rigorous work on Alan Kay&#x27;s part.
评论 #36668539 未加载
评论 #36668521 未加载
评论 #36669752 未加载
评论 #36670193 未加载
评论 #36671616 未加载
评论 #36672484 未加载
评论 #36671154 未加载
评论 #36673964 未加载
评论 #36669503 未加载
评论 #36668625 未加载
评论 #36669467 未加载
评论 #36669316 未加载
评论 #36676900 未加载
评论 #36668944 未加载
gumby将近 2 年前
This ten year old essay is still strong. It makes some points that are worth repeating<p>&gt; I have a hypothesis: this pattern is so common for the simple reason that Java doesn’t have first-class functions.<p>She’s picking on Java deservedly because Gosling made what in retrospect was a mistake to go so all-in on classes, and because it became such an important pedagogical and deployment language (and nobody will shoot at you if you’re unsuccessful).<p>Say what you will about C++ but it took a different path, not only changing its name from “C with Classes” but making classes a tool for manipulating the type system (and not the only one) and supporting the true benefit of a class system, generics.<p>Edit: I changed an incorrect &quot;He&quot; pronoun to &quot;She&quot;. Thanks to quickthrower2 for pointing out this embarassing blunder.
评论 #36666051 未加载
narag将近 2 年前
The many &quot;you&#x27;re wrong if you believe that&quot; made me remember the anecdote of Alan Kay attending some conference about OOP and saying that it was wrong, that he invented OOP and it was not like that.<p>IIRC, Kay&#x27;s vision is that OOP is about messages.<p>I have my own pet theory, of course it must be wrong too, but if I may, only as food for thought: The core usefulness of OOP is usability. A language is a matter of connecting thoughts through a mental model. Subject, verb, predicate. Object, method, parameters. That&#x27;s mostly it. The rest are implementation details and lots of bikeshedding.
评论 #36666092 未加载
评论 #36666494 未加载
评论 #36667570 未加载
评论 #36665789 未加载
评论 #36666046 未加载
评论 #36668702 未加载
评论 #36665808 未加载
cheschire将近 2 年前
&gt; The app is the object, and the various URL handlers are its state.<p>There were a lot of assertions in this article that rubbed me wrong, but this one was particularly egregious. Handlers are behavior. They handle something.<p>This feels like the kind of article I would&#x27;ve written early in my career when I was getting really clever with stuff and starting to be able to question the way I understood the world of programming.
评论 #36667113 未加载
评论 #36667321 未加载
评论 #36683829 未加载
评论 #36666880 未加载
kgeist将近 2 年前
I actually like &quot;dumb&quot; service classes with 1 method. Usually that method may require tens of dependencies to function (db connection, authorization logic, etc.), which in turn have their own dependencies recursively, and your choices are: 1) use global variables&#x2F;functions for dependencies, 2) pass all dependencies as arguments to your function, 3) inject dependencies in the constructor of a service class&#x2F;functor. Global state is a no-no in multithreaded code and is poorly manageable (side effects and all), while forcing a client of your function to pass all required dependencies manually as arguments is cumbersome and basically leaks implementation details (hard to refactor). So for me, service classes are the best option. It&#x27;s kind of equivalent to a closure (object fields are basically captured variables), just written using the familiar OOP syntax (OOP syntax != OOP semantics). In the context of web, I tend to prefer stateless architectures (because they are easily scalable and less error-prone), and coupling behavior with state often goes in the way, in my experience. So my favorite architecture is a network of service classes whose dependencies are injected in their constructors and which are basically &quot;smart&quot; functions (not &quot;objects&quot;), they have no state, and they operate on domain objects which have no logic other than basic self-validation during mutation (to uphold invariants). I know it&#x27;s a heated topic (rich model vs. anemic) but I&#x27;ve seen projects naturally, through evolution, end up being more anemic than rich. Pure OOP, where state and behavior are entangled, feels very cumbersome to me, it&#x27;s harder to refactor when requirements change every day, and having too much state is pretty error-prone. YMMV.
评论 #36666418 未加载
评论 #36665990 未加载
评论 #36668185 未加载
评论 #36675974 未加载
AugustoCAS将近 2 年前
I recently escaped an organization that had a couple of apps built using this approach <i>everywhere</i> but for the opossite reason stated in the article. The team wanted to write code in a functional way in Java because _FP is better than OO_.<p>Most (if not all) classes had a single method and implemented BiFunction. The app was wired with Spring... if you had the bad luck of using Spring you can get the idea of how ugly this was. All method invocations were `apply`s and navigating the code was as easy as finding a needle in a haystack in the middle of the night. A good amount of the wonderful features of a tool like IntelliJ couldn&#x27;t be used.<p>My rule of thumb is to follow the grain of the language &#x2F; framework &#x2F; library as to produce as little surprise to other devs.
评论 #36671348 未加载
评论 #36675915 未加载
bob1029将近 2 年前
&gt; Stop writing <i>stupid</i> classes.<p>This is really it. It&#x27;s not a game of all-OO, zero-OO or strictly following a pattern you saw on YouTube that one time. It&#x27;s all about nuance and minimizing the # of moving parts until each is really serving you some value.<p>I am in the process of ripping out a bunch of class bloat in a product iteration. Our typical pile of model class POCO spam for &quot;one thing&quot;:<p><pre><code> Entity.cs --The &quot;official&quot; view EntityController.cs EntityView.cs --Another common view that became popular over time (???) EntityTableRow.cs --gotta have that 1:1 sql model, amirite? EntityViewForTypeA.cs --what was wrong with the common one :( EntityViewForTypeB.cs --And again... ... </code></pre> Ultimately, every time we wanted a &quot;view&quot; of the data, we wound up creating another type to enshrine this and then tried to figure out how many holes we could more-or-less hammer it through. Every one of these has some cranky mapping layer too (NxM if you want to get crazy).<p>The alternative pattern I am working with is to directly query my database in the exact place the data is required and to use anonymous &#x2F; scalar return types like so:<p><pre><code> &#x2F;&#x2F;Some function that produces a HTML partial view for a webapp &#x2F;&#x2F;View w&#x2F; join that would otherwise require a new POCO type to communicate. var myEntityView = await sql.QueryFirstAsync(@$&quot; SELECT e.Id AS Id, ep.Name as Name FROM Entities e, EntityProperties ep WHERE e.Id = ep.EntityId AND e.Id = @Id&quot;, ...); &#x2F;&#x2F;Direct usage of anonymous result type. return $@&quot; &lt;h3&gt;Entity:&amp;nbsp; &lt;a href=&#x27;Entities&#x2F;{myEntityView.Id}&#x27;&gt;{myEntityView.Name}&lt;&#x2F;a&gt; &lt;&#x2F;h3&gt;&quot;; </code></pre> In the above, there are <i>zero</i> POCOs or &quot;messenger&quot; types. Just a raw query right where it needs to be taken, without any extra ceremony or implications for other code sites. I actually don&#x27;t have a single type in the new codebase that is a POCO, other than schema tracking models (which are still useful for interpolating into queries to enforce magic strings). Effectively, the only domain data types are 1:1 with the SQL schema now.
评论 #36670273 未加载
评论 #36694778 未加载
prewett将近 2 年前
Maybe I&#x27;ve been ruined by early exposure to C++, back when C++ was the new hotness, but I find encapsulation and even the namespacing aspect to be helpful. Encapsulation is obviously helpful, but it also comes in handy for some algorithms that are complex enough to require several functions, but which share a lot of state. If I recall correctly, Voronoi tesselation is one of these. Even though an &quot;tesselate&quot; is an action, putting it in a class just makes it easier to think about things. Otherwise as a user of the function I have to first create the shared data object, then know to call the three helper functions. Better would be a high-level tesselate() call, but then that call needs to do that. Now you&#x27;ve just pushed the complexity down to the next maintainer, who needs to figure out how all this soup of functions from all the various algorithms and whatnot that have collected over the years relate to each other. With an object, the newbie maintainer at least knows what the topic of the functions is.
xg15将近 2 年前
I wonder if at some point, we could train an LLM to churn out hot takes about why this one design pattern is awesome but that other design pattern is horrible and why you need to die in a fire if you use MVC but everyone should be using MVVCP instead but do stay away from MVPVC or your life will be wasted. Then we could train a second LLM to read the first LLM&#x27;s articles and write flaming rebuttals and have the first LLM write rebuttals to the rebuttals. And if everything works, we could finally automate the entire debate away and go on writing code.
评论 #36665506 未加载
评论 #36665628 未加载
评论 #36665902 未加载
评论 #36665449 未加载
iambateman将近 2 年前
Meanwhile, in busytown…millions of developers will wake up on Monday morning, sit down to their work and make something using the best tools they know.<p>If it works for you and your team, it works.
评论 #36666662 未加载
评论 #36671157 未加载
boredumb将近 2 年前
Here&#x27;s my hot take. Most patterns are incredibly awful and abused because people prefer to solve architectural related problems in code and produce &quot;elegant&quot; solutions over delivering features.<p>Here&#x27;s my pattern that I use instead of a MVC&#x2F;MVVM&#x2F;MVP&#x2F;etc&#x2F;etc: I have a handler function to choose what url and routine I need and it calls some functions and methods and then renders some json &#x2F; templates out some html.<p>I think a good rule of OOP is to try to write everything out as functionally pure as possible and refactor into classes when you see data AND functionality blocked together that you can bottle up into an object. To start ranting, I think a lot of the OOP insanity you see in .net&#x2F;java&#x2F;etc is from dogmatic approaches to unit testing over there and the common examples of how to do it involving the mocking and interfacing that end up obfuscating the actual production code.
评论 #36665948 未加载
TrianguloY将近 2 年前
I don&#x27;t see this mentioned, but on python a file can be considered a singleton class. If you come from java, this may help you write better python code. No need to encapsulate things on a class! The file is the singleton itself!
评论 #36668747 未加载
评论 #36674282 未加载
DeathArrow将近 2 年前
&gt;Object-oriented programming is about objects: bundles of state and behavior.<p>That means hiding state, and having it spread throughout the app, in places that are hard to find, which is error prone and leads to complexity. And monstrosities like FactoryFactoryFactory [0] and Kingdom of nouns.<p>[0] <a href="https:&#x2F;&#x2F;factoryfactoryfactory.net&#x2F;" rel="nofollow noreferrer">https:&#x2F;&#x2F;factoryfactoryfactory.net&#x2F;</a><p>[1] <a href="http:&#x2F;&#x2F;steve-yegge.blogspot.com&#x2F;2006&#x2F;03&#x2F;execution-in-kingdom-of-nouns.html" rel="nofollow noreferrer">http:&#x2F;&#x2F;steve-yegge.blogspot.com&#x2F;2006&#x2F;03&#x2F;execution-in-kingdom...</a>
评论 #36674087 未加载
评论 #36665483 未加载
indigo945将近 2 年前
<p><pre><code> Last pop quiz: what makes Python an object-oriented language? Ah, hm. It can’t be classes, or I’d tell you you’re wrong. So what is it? [...] self? No, that’s not a keyword or anything; it’s just the de facto standard name for the first argument. So what makes self work? That’s close enough, really. The answer is descriptors, which are basically “the things that make self work”. </code></pre> From another blog post on the same site [1]:<p><pre><code> A descriptor is just an object; there’s nothing inherently special about it. Like many powerful Python features, they’re surprisingly simple. To get the descriptor behavior, only three conditions need to be met: 1. You have a new-style class. [...] </code></pre> It therefore follows logically that Python code using old-style classes is not object-oriented, and that Python was not an object-oriented language prior to the introduction of descriptors.<p>[1]: <a href="https:&#x2F;&#x2F;eev.ee&#x2F;blog&#x2F;2012&#x2F;05&#x2F;23&#x2F;python-faq-descriptors&#x2F;" rel="nofollow noreferrer">https:&#x2F;&#x2F;eev.ee&#x2F;blog&#x2F;2012&#x2F;05&#x2F;23&#x2F;python-faq-descriptors&#x2F;</a>
评论 #36668514 未加载
lamontcg将近 2 年前
Well, yes, but no, but yes.<p>A counter example of a good bag of function is every languages Math static class.<p>Also it is quite viable to have a bag of data and multiple different classes which have algorithm which operate on that data. Those algorithms should not be trivial (but there is no good definition of what trivial is or isn&#x27;t). If you toss all those algorithms into the bag-o-data class you will wind up with a massive class which changes under too many circumstances and clearly violates separation of concerns.<p>If you have a three line function that should clearly not go into its own class. If you have a dozen methods that implement an algorithm on a class, and the private methods don&#x27;t need to be shared amongst other algorithms, and perhaps you have some private state dedicated to just that algorithm that doesn&#x27;t make sense to have in the data-holding class, then you should probably extract that into a stand alone class. Where is the actual dividing line? I don&#x27;t know. Wrestling with it all right now with some code that I&#x27;ve been writing for the past several weeks. It doesn&#x27;t help that I don&#x27;t yet have a second algorithm that hits this data, so there&#x27;s no good dividing line for me between what should be private to the algorithm and what should be public hanging off the data.<p>It is not anywhere near as clear as the author of this blog makes it out to be though.<p>And the algorithm I&#x27;m implementing is a Job, which inherits from BackgroundJob as well. The horrors.<p>(I do at least have three different BackgroundJobs now which all need common task handling and cancellation&#x2F;timeout kinds of logic wrapped around them so that&#x27;s a bit more clear what that abstract base class should look like).
jmull将近 2 年前
&gt; It’s nothing. There’s no way to describe it without sounding like a blowhard. It’s not “a controller for some URL space”, because that’s what the class is. An instance of it is utterly meaningless!<p>IMO, this is being almost willfully obtuse and pointlessly pedantic.<p>For one thing, the instance, not the class, is the thing most clearly described as the controller in this case. It&#x27;s true that there&#x27;s no need to have instances for this static logic, but it&#x27;s also true that some routing behaviors have their own dynamic data (like caches or database connections, etc.) So a point of just always using instances is that you don&#x27;t need to know or care externally or ahead of time whether or not such data exists (and to provide something better than singletons or worse things to manage it when it does.)<p>I&#x27;m not a big fan of this form, BTW, though it&#x27;s not on OO grounds. It&#x27;s a code and logic organization thing. When I&#x27;ve seen this in real life it turns into spaghetti code of little objects connected in a tangle. I think it goes down like this: people start by encapsulating little steps of processing, I guess because they image they are independent. At this point it&#x27;s OK -- a sequence of objects connected in a chain of references matching the processing steps. Then they realize they aren&#x27;t independent, but instead of unwinding the chain, they add more objects -- to hold bits of common context -- and connect them here and there. The spaghetti is starting to tangle. (Mistakes are always made at this point -- e.g. there&#x27;s ends up no coherent way to update this common data as things change.) The thing grows 10x and these kinds of things are repeated ten times and you have a big ball of spaghetti. Oh, and someone introduced a DI framework to solve these, which helps a little, but also introduces its own complications.
agurk将近 2 年前
Could we get a (2013) in the title please.
评论 #36665495 未加载
yurishimo将近 2 年前
One nitpick from the article, PHP does have first class support for functions in the language. Functions are available in a few different ways:<p>- Normal function declaration in global and &quot;module&quot;&#x2F;namespace scope.<p>- Anonymous functions that can also be assigned to variables (except in a few cases, like object properties)<p>- Anything extending the Closure class<p>The last one is obviously a nod at what is going on under the hood, but as far as the developer writing the code is concerned, it doesn&#x27;t matter.<p>A library even exists to explicitly provide some functional programming functions under a namespace for easy inclusion with other projects. There is no requirement that all functions must be defined in a namespace, as evidenced by the first 10 years of crappy PHP code littered with functions in the global namespace!<p><a href="https:&#x2F;&#x2F;github.com&#x2F;lstrojny&#x2F;functional-php">https:&#x2F;&#x2F;github.com&#x2F;lstrojny&#x2F;functional-php</a><p>Edit: formatting
评论 #36667931 未加载
dxuh将近 2 年前
I find it funny that people that know almost nothing about C++ talk about it so much. Function pointers are not the only way to treat functions as values, as is implied in the article. Lambdas exist and have existed in 2013 as well (and are nowadays the canonical way to have something like first-class functions).<p>And what does this mean?<p><pre><code> Quick: off the top of your head, what makes JavaScript an object-oriented language? If you thought “what? it’s not!” then there is no hope for you and you should go back to C++. </code></pre> Ironically it&#x27;s the C++ programmers that have pretty much collectively understood that classes are for maintaining invariants, which this person is almost about to understand in this article (I hope they did by now).
williamcotton将近 2 年前
<i>You can write object-oriented code in C, but no matter what tricks you do with storing function pointers in structs, you still have to pass the struct itself as an explicit argument.</i><p>A sprinkle of clang blocks and Block_copy on top of your structs and you’re on your way!
评论 #36665176 未加载
thurn将近 2 年前
OOP is a tool like any other, and it has real costs and benefits. The original idea of being able to easily add new common APIs via inheritance is very powerful and widely applicable. In fact both Haskell and Rust wound up with a similar mechanism to inheritance (the &#x27;deriving&#x27; annotation) to reduce the pain of problems like &quot;I don&#x27;t want to have to write code to define equality for every struct&quot; which are hard for the purely-functional approach to solve.
评论 #36665989 未加载
评论 #36670276 未加载
dawnofdusk将近 2 年前
Is the problem here not simply that Python does not have a convenient way to namespace functions except a class declaration? The `module` keyword in e.g., Julia or Rust seems like what&#x27;s desired to avoid this phenomenon of &quot;a class which is just a bundle of static methods&quot;.
评论 #36666315 未加载
weare138将近 2 年前
<i>I have a hypothesis: this pattern is so common for the simple reason that Java doesn’t have first-class functions. -----<p>I would put C++ and PHP in second and third place, and they have the same flaw.</i><p>PHP supports first-class functions.
Mikhail_Edoshin将近 2 年前
The author of the article also writes about “good classes.” She criticizes two specific mistakes one can make in Python classes (and she is right), but not the OOP itself.
jononomo将近 2 年前
In my opinion you&#x27;re not really doing object-oriented programming unless each object is also a separate process. This is why the best object-oriented programming uses functional programming languages and the actor model (i.e., Erlang). Just having state and methods, but without having an associated isolated process means you end up in situations in which multiple processes may fiddling with the same objects and all your encapsulation of data just gets you in a twist. It&#x27;s only when you commit fully to functional programming and have immutable state that you truly unlock the power of object-oriented programming.
评论 #36667801 未加载
slotrans将近 2 年前
&gt; I have a hypothesis: this pattern is so common for the simple reason that Java doesn’t have first-class functions.<p>Exactly correct.<p>See also &quot;Execution in The Kingdom of Nouns&quot;
jononomo将近 2 年前
In my experience, people who really like object-oriented programming just haven&#x27;t yet gotten the hang of functional programming.
ddtaylor将近 2 年前
I am surprised that an article this length never mentions &quot;message passing&quot; once.
whimsicalism将近 2 年前
2013 in the title please, also the tone of this post is a bit condescending
评论 #36665798 未加载
acscott将近 2 年前
A little bird told me that it was easier to break up big projects into classes and farm them out than in other languages at the time. The `protected` keyword for example prevented the other developer(s) from modifying that part of the object, creating safety.
quickthrower2将近 2 年前
She seems quite deeply knowledgeable about a lot of different languages which is impressive. Or much research was done. I just don’t have that much stuff stick especially for languages I don’t use every day.
nathias将近 2 年前
OOP was a mistake rooted in platonism
评论 #36672545 未加载
评论 #36674425 未加载
评论 #36666329 未加载
ivan_gammel将近 2 年前
It is interesting that Java is mentioned there as a language without first-class functions. Maybe, but from programmer‘s perspective it kinda does and they are encapsulated in «namespaces»: they are static methods of classes and with ˋimport staticˋ they do look like first-class functions.
评论 #36665230 未加载