TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Under Deconstruction: The State of Shopify’s Monolith

312 pointsby kenroseover 4 years ago

17 comments

lmarcosover 4 years ago
Great article. Main takeaway: microservices is not the only option when managing big codebases. In a parallel universe I imagine that the coolest trend in software development right now is a tool for monoliths: all code in a single repo, independent deployable components, contracts in the boundaries and mockable dependant components where needed. As opposed to our universe in which building microservices is the non-official way to go.
评论 #24509209 未加载
评论 #24509132 未加载
评论 #24507702 未加载
评论 #24508240 未加载
评论 #24511989 未加载
评论 #24507928 未加载
评论 #24508949 未加载
评论 #24509037 未加载
strawsover 4 years ago
A number of years ago, I worked on a team (~20 engineers in total) that successfully carved off two relatively independent portions of a large Rails app using engines. I&#x27;m happy to see that Shopify is also using that strategy.<p>I&#x27;m curious to know more what sorts of challenges they have around managing dependencies across engines — I think what we were doing was fairly vanilla Rails, and we didn&#x27;t have the opportunity to run into those sorts of issues.
评论 #24506317 未加载
评论 #24509852 未加载
评论 #24506918 未加载
joelbluminatorover 4 years ago
2.8 million lines , 100 billion business. Rails can scale.
评论 #24507043 未加载
评论 #24508575 未加载
评论 #24508514 未加载
octernionover 4 years ago
we are actually doing precisely the same thing at instacart (breaking our 1+ million lines of code monolith into discrete components, which we call &quot;domains&quot;), and typing the boundaries and as much of the internals of these domains as possible with sorbet types.<p>this has the benefit of ruby dynamicism (fast development within domains, you can use all the nice railsy tooling, activerecord, and all the libraries we&#x27;ve built over the years), with type safety at the boundaries (we&#x27;ve also put in timeouts, thread separation, and error handling at the boundaries).<p>the additional benefit for using sorbet is that it makes making typed RPC calls (over twirp or graphql) much easier as you can introspect the boundaries trivially.<p>really cool to see other companies evolving similarly given the same starting conditions!
评论 #24506161 未加载
评论 #24506358 未加载
评论 #24506630 未加载
sandGorgonover 4 years ago
This is a brilliant brilliant article.<p>Does anyone know how Shopify created it&#x27;s Architecture Guild and grew it ? The author talks about &quot;should have done it earlier&quot;
评论 #24506778 未加载
treisover 4 years ago
Have y&#x27;all seen any issues around autoloading of classes&#x2F;modules in development? I&#x27;ve been working on a rails app composed of a handful of engines and I&#x27;ve noticed that every so often classes aren&#x27;t loaded. 6 seems to be a lot better about it than 5 was.
评论 #24507088 未加载
gregkerzhnerover 4 years ago
Interesting article. We use a similar approach for our mobile apps to allow multiple teams to develop their own modules independently.<p>Can anyone speak to what the advantages and disadvantages to such an approach are as opposed to going full Kubernetes &#x2F; Microservices? Is it that deploys are riskier and you can&#x27;t scale separate pieces independently?
kawsperover 4 years ago
Does anyone know if the Storefront rendering described here[0] is running Rails or something else?<p>[0] <a href="https:&#x2F;&#x2F;engineering.shopify.com&#x2F;blogs&#x2F;engineering&#x2F;how-shopify-reduced-storefront-response-times-rewrite" rel="nofollow">https:&#x2F;&#x2F;engineering.shopify.com&#x2F;blogs&#x2F;engineering&#x2F;how-shopif...</a>
评论 #24507295 未加载
banqover 4 years ago
DDD aggrgates: loose coupling with high cohesion!
ryanmarshover 4 years ago
There’s so much truth in this. It’s full of lessons I tell clients at the outset of similar endeavors yet they often do not heed until they experience the pain first hand.
banqover 4 years ago
in Shopify, they actually applied DDD bounded context and aggregate ,but they maybe don&#x27;t know DDD!
meesterdudeover 4 years ago
Interesting read. I&#x27;ve seen a component based rails architecture work wonders for cleaning up a codebase and allowing for the benefits of a SOA encapsulation while still keeping everything under a monolithic architecture (and avoiding the networking nasties). Not such a fan of sorbet though, but hopefully something better comes along.
ToJansover 4 years ago
I can imagine that this has been a huge effort, and kudos to the team, but this is a solved problem; there are ample methodologies to resolve the big ball of mud.<p>IMHO the shopify team could have saved a lot of time by getting some schooling about strategic DDD, and consulting one or more DDD experts to draw a first version of their context map.
评论 #24522577 未加载
mochiiover 4 years ago
Very interesting read! Thank you for sharing.
throwaway691999over 4 years ago
I think it&#x27;s kind of bad that we have this trend to use &quot;walls&quot; to enforce modularity. This whole thing about using &quot;walls&quot; to enforce &quot;developer behavior&quot; is, in my humble opinion, the wrong direction.<p>If you think about it, almost all lack of modularity comes from shared mutable variables. Segregate mutability away from the core logic of your system and the smallest function in your architecture will become as modular as a microservice.<p>Really, any function that is stateless can be moved anywhere at anytime and used anywhere without fear of it being creating a permanent foothold in the architectural complexity of the system. So if the code is getting to structured where you become afraid of moving things... do this rather than build classes and walls around all your subroutines.<p>Remember as long as that add function doesn&#x27;t mutate shared state you know it has zero impact on any part of the system other than it&#x27;s output... you can replace it or copy it or use it anywhere.... this is really all you need to do to improve modularity of your system.<p>&gt;Again and again we pondered: How should components call each other?<p>I think this is what&#x27;s tripping most people up. They think DI IOC and OOP patterns are how you improve modularity. It&#x27;s not. Immutable functions are what improves modularity of your program. The more immutable functions you have and the smaller they are the more modular your program will be. Segregate IO and mutations into tiny auxiliary functions away from your core logic which is composed of pure immutable functions.<p>&gt;Circular dependencies are situations where for example component A depends on component B but component B also depends on component A.<p>I&#x27;ve never seen circular dependencies happen with pure functions. It&#x27;s rare in practice. I think it occurs with objects because when you want one method of an object you have to instantiate that object which has a bunch of other methods and in turn dependencies that could be circular to the current object you&#x27;re trying to call it from. In essence this kind of thing tends to happen because when you call a method you&#x27;re actually calling a group of methods and state within a class and upon all those dependencies as well increasing the chances of a circular dependency.<p>Still I&#x27;ve seen this issue occur with namespacing when you import files. Walls aren&#x27;t going to segregate this from happening. You need to structure your dependencies as a tree.
评论 #24512677 未加载
leafboiover 4 years ago
I think it&#x27;s kind of bad that we have this trend to use hardware to enforce modularity. If it&#x27;s a performance issue, sure break it up into more hardware. If it&#x27;s just code modularity than by shifting to microservices you are adding additional complexity of maintaining multiple services on top of modularizing the system. In short it&#x27;s overkill. This whole thing about using hardware to enforce &quot;developer behavior&quot; is stupid. You can use software to enforce developer behavior. Your operating system, your programming language is already &quot;enforcing&quot; developer behavior.<p>Additionally, your microservices are hard lines of modularization. It is very hard to change a module once it&#x27;s been materialized because it&#x27;s hardware.<p>If you think about it, almost all lack of modularity comes from shared mutable variables. Segregate mutability away from the core logic of your system and the smallest function in your architecture will become as modular as a microservice.<p>Really, any function that is stateless can be moved anywhere at anytime and used anywhere without fear of it being creating a permanent foothold in the architectural complexity of the system. So if the code is getting to structured where you become afraid of moving things... do this rather than go to microservices.<p>&gt;We can more easily onboard new developers to just the parts immediately relevant to them, instead of the whole monolith.<p>Correct me if I&#x27;m wrong but don&#x27;t folders and files and repos do this? Does this make sense to you that it has to be broken down into hardware?<p>&gt;Instead of running the test suite on the whole application, we can run it on the smaller subset of components affected by a change, making the test suite faster and more stable.<p>Right because software could never do this in the first place. In order to test a quarter of my program in an isolated environment I have to move that quarter of my program onto a whole new computer. Makes sense.<p>&gt;Instead of worrying about the impact on parts of the system we know less well, we can change a component freely as long as we’re keeping its existing contracts intact, cutting down on feature implementation time.<p>Makes sense because software contracts only exist as http json&#x2F;graphql&#x2F;grpc apis. The below code isn&#x27;t a software contract it&#x27;s only how old people do things:<p><pre><code> int add(x: int, y: int) </code></pre> Remember as long as that add function doesn&#x27;t mutate shared state you know it has zero impact on any part of the system other than it&#x27;s output... you can replace it or copy it or use it anywhere.... this is really all you need to do to improve modularity of your system.<p>Editing it on the other hand could have some issues. There are other ways to deal with this and simply copying the function, renaming and editing it is still a good solution. But for some reason people think the only way to deal with these problems is to put an entire computer around it as a wall. So whenever I need some utility function that&#x27;s located on another system I have to basically copy it over (along with a million other dependencies) onto my system and rename it... wait a minute can&#x27;t I do that anyway (without copying dependencies) if it was located in the same system?<p>&gt;Again and again we pondered: How should components call each other?<p>I think this is what&#x27;s tripping most people up. They think DI IOC and OOP patterns are how you improve modularity. It&#x27;s not. Immutable functions are what improves modularity of your program. The more immutable functions you have and the smaller they are the more modular your program will be. Segregate IO and mutations into tiny auxiliary functions away from your core logic which is composed of pure immutable functions. That&#x27;s really the only pattern you need to follow and some languages can enforce this pattern without the need of &quot;hardware.&quot;<p>&gt;Circular dependencies are situations where for example component A depends on component B but component B also depends on component A.<p>I&#x27;ve never seen circular dependencies happen with pure functions. It&#x27;s rare in practice. I think it occurs with objects because when you want one method of an object you have to instantiate that object which has a bunch of other methods and in turn dependencies that could be circular to the current object you&#x27;re trying to call it from. In essence this kind of thing tends to happen with exclusively with objects. Don&#x27;t group one function with the instantiation of other functions and you&#x27;ll be fine.<p>Still I&#x27;ve seen this issue occur with namespacing when you import files. Hardware isn&#x27;t going to segregate this from happening. You need to structure your dependencies as a tree.
评论 #24507417 未加载
boriover 4 years ago
I like that they completely dodged the term &quot;microservice&quot; in the whole post.
评论 #24510136 未加载