Reddit reviews Domain-Driven Design: Tackling Complexity in the Heart of Software
We found 43 Reddit comments about Domain-Driven Design: Tackling Complexity in the Heart of Software. Here are the top ones, ranked by their Reddit score.
We found 43 Reddit comments about Domain-Driven Design: Tackling Complexity in the Heart of Software. Here are the top ones, ranked by their Reddit score.
Here's a list I compiled, the list books kind of hit a wide range. I don't really have any given list of talks I like. I'll just randomly google for videos by a speaker i like or subject I'm interested in.
Books:
Watch:
Podcasts:
Blogs:
News Letter:
Misc:
Edit: these are not affiliate links :)
I actually had this exact discussion today. A number of people argue that type classes must have laws. I definitely share the general sentiment that it is better for type classes to have laws. But the extreme view that ALL type classes should have laws is just that...extreme. Type classes like
Default
are useful because they make life easier. They reduce cognitive overload by providing a standardized name to use when you encounter a concept. Good uniformly applied names have a host of benefits (see Domain-Driven Design for more on this topic). They save you the time and effort of thinking up a name to use when you're creating a new instance and also avoids the need to hunt for the name when you want to use an instance. It also lets you build generic operations that can work across multiple data types with less overhead. The example of this that I was discussing today was a similar type class we ended up callingHumanizable
. The semantics here are that we frequently need to get a domain specific representation of things for human consumption. This is different fromDefault
,Show
,Pretty
,Formattable
, etc. The existence of the type class immediately solves a problem that developers on this project will encounter over and over again, so I think it's a perfectly reasonable application of a useful tool that we have at our disposal.EDIT: People love to demonize
Default
for being lawless, but I have heard one idea (not originally mine) for a law we might use forDefault
:def
will not change its meaning between releases. This is actually a useful technique for making an API more stable. Instead of exporting field accessors and a data constructor, export aDefault
instance and lenses. This way you can add a field to your data type without any backwards-incompatible changes.Smaller business logic frameworks would be mutations and ActiveInteraction.
They would replace the operations (and parts of reform) of TB.
Personally, I wouldn't use either of them over TB, they still add complexity, but don't offer too much over self-written stuff. YMMV of course.
If you want to start simple: create POROs for your "operations" with 2 public methods - initialize and run (or call, execute, apply, process etc.). Put your logic in them, create / execute them in your controllers.
Call them services, workflows, procedures, operations, scenarios, whatever.
try to put no persistent state in them - let them do their thing, return some sort of result (
true
/false
, model / nil, small result object).This fulfills a number of your criteria: it shouldn't slow you down much at all, it's simple, fairly maintainable and easily unit testable.
If you would like to research a different approach, look into DDD. The Arkency book should make for a good start, with the original DDD book giving quite a bit more background information.
> I'm not coding SPAs, so I still need awesome logic for Views / Presenters.
If you liked the Cells from TB, you can use them without using the rest of TB.
If you want something simpler, use a decorator like draper with ERB or Slim.
as a beginner you're stuck in a position where you want to learn how to do things, but also how to write them. i.e you don't only want to paint a painting, but you also want it to be pretty and admired.
for programming there's a lot of schools of thought on this subject, some guys prefer test-driven development, others domain-driven design.
some think comments outside of method parameters are good coding praxis, others think it's a code-smell because if you have to explain your code you probably wrote it in a way that makes it difficult to understand.
some think patterns are for hipsters, others are of the correct opinion (ahem) that they are standardised solutions for common problems.
all in all, if I could go back in time 15 years when I started programming, I would read the following if they were available at the time:
https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
Domain-Driven Design is the concept of breaking your code into logical real world units and bundling your code around these objects so that it makes sense to program if you understand the real world your program is mirroring. i.e if you're making a fruit shop program, you might have a fruit seller, a register, a fruit warehouse, a process to deal with ordering fruit etc.
https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882
Clean code talks not so much about the architectural patterns (outside of test-driven development) but rather what's good and bad about code at it's core. i.e
if(fruitStand.Amount < 5)
{
fruitHelper(fruitStand, 3434)
}
vs
if(fruitStand.Amount < dailySoldAverage)
{
OrderNewFruit(fruitStand, wholesaleDiscountCode)
}
outside of that, I think you'll find a lot more resources by simply researching the concepts these guys talk about. programming is constantly changing, as long as you have the fundamentals in place as these guys talk about you're golden as long as you're willing to learn.
I highly recommend the following:
Master these, and virtually any software project you undertake will become easier and better.
Books
Stuff to watch
Blogs
Other resources
Pick up these books:
Just remember that the goal of a good architecture is to provide value, but maintain high quality of code that is easy to maintain and change. Separation of concerns , loose coupling, testability, maintainability and scalability are major points to look out for .
My blog about software architecture: http://www.tutisani.com/software-architecture/ (may not be for very beginners but I hope that it's able to communicate important topics).
I'd also suggest reading the classic book about design patterns (a.k.a. Gang of Four): https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/ref=sr_1_3?crid=1XRJO0L09LHLY&keywords=design+patterns+elements+of+reusable+object+oriented+software&qid=1557502967&s=gateway&sprefix=design+patterns%2Caps%2C162&sr=8-3
There are several good thought leaders in this direction, specifically Martin Fowler (https://martinfowler.com/) and Eric Evans (he does not write much online, but his book is great - all about modeling properly): https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
&#x200B;
I'm big on modeling, objects, etc. so reply back if any questions.
Read lots of code and read books to get multiple viewpoints. This is a deep topic which will require more than superficial online reading.
Check this out.
Books I have found useful:
I've posted this before but I'll repost it here:
Now in terms of the question that you ask in the title - this is what I recommend:
Job Interview Prep
Junior Software Engineer Reading List
Read This First
Fundementals
Understanding Professional Software Environments
Mentality
History
Mid Level Software Engineer Reading List
Read This First
Fundementals
Software Design
Software Engineering Skill Sets
Databases
User Experience
Mentality
History
Specialist Skills
In spite of the fact that many of these won't apply to your specific job I still recommend reading them for the insight, they'll give you into programming language and technology design.
The following books would be good suggestions irrespective of the language you're developing in:
Patterns of Enterprise Application Architecture was certainly an eye-opener on first read-through, and remains a much-thumbed reference.
Domain-Driven Design is of a similar vein & quality.
Refactoring - another fantastic Martin Fowler book.
We evolved an app architecture similar to the one he presents. However, it is also proprietary. It is truly a joy to work with though :)
I would say the key characteristics are roughly:
There's a whole book dedicated to this topic called Domain Driven Design.
A customer purchases tickets, not train services. And a train service has customers, but the train has passengers. You should keep the concepts separate. How about introducing a third concept - a ticket?
A customer has many tickets for past journeys. The ticket doesn't need to maintain a reference to the train service, but the train service should be able to identify tickets it issued. And the ticket doesn't need to keep a reference to the customer. Nice clean separation between two indpedent concepts, or Bounded Contexts as it is called in DDD.
The few comments in here aren't explaining WHY the interviewer said "very 90s". Obviously, "very 90s" is over-exaggerated... "very 2000s" is a bit more accurate.
What you've got is a "typical" layered architecture, which is considered a bit out-dated these days. There's a couple major reasons people move away from that architecture now.
For a quick look at an alternative project structure, you can check out Onion Architecture, which moves business logic to the application core on CodeProject (this is similar to ports & adapters)
For more in-depth, look into Domain Driven Design (DDD). Many an architect, including myself, would suggest Eric Evans' book on the topic.
For a more recent DDD book, see Vaughn Vernon's Implementing Domain Driven Design.
Domain Driven Design by Eric Evans.
Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans
Well, any logic which doesn't encode business rules is, by definition, not business logic. So, for example, most or all of the logic within your infrastructure layer would not be business logic. But I suspect what you're really asking is "what sort of non-business logic belongs in a VO?" The answer to that is simply: any logic which goes hand-in-hand with the value being represented, and is side-effect free. One of the examples Eric Evans gives is that of a
Paint
VO which has a methodmixIn(Paint $otherPaint): Paint
that encapsulates the logic of mixing one paint into another, and produces a new VO.Do yourself a huge favor and just read this.
I have started reading this book and so far I am enjoying it
Domain-Driven Design: Tackling Complexity in the Heart of Software https://www.amazon.com/dp/0321125215/ref=cm_sw_r_cp_apa_i_R60tDb2Y19V4X
It came recommended to me from a few different sources including Reddit.
I presume it's Domain Driven Design -- This was a popular, well received book. DHH in particular has blogged, talked and tweeted about it on numerous occasions.
For more foundational stuff, I'd look at:
Getting familiar with these branching models will also expose you to many commonly-used Git features like branching, squash merging, rebasing, tagging, and history rewriting.
No one's really gonna ask you about this, but you should develop a habit of writing great, clear, and concise commit messages.
All the rage right now - having real/near-real time building/unit-testing/packaging/deployment of your software once you've made a code commit. Read the articles I linked, play with services like CircleCI or Travis-CI or CodeShip and integrate them with your projects in GitLab.
Probably the two most commonly used overarching test-based software development processes. I'm a strong proponent of TDD (when done right), and many teams you work on will probably employ TDD or BDD.
Beyond those links, some books that cover a lot of general material are:
I think it's Domain Driven Design
The book Domain Driven Design: Tackling Complexity in the Heart of Software sort of revolves around this topic. The author speaks at great length about projects where spending way more time in modeling / researching than coding allowed them to solve the problems in ways which allowed them to scale way better - and what they did during that time.
The book is a bit old, but if you take it for the modeling aspect it's still a great read.
It will help -to me it was the first book that came to mind. The second would be the this -the pinnacle of software design.
No worries, it's always good to make the implicit explicit. I am (and I suspect others would be as well) referring to Domain Driven Design.
"Domain", in this case, can be defined as the problem space that the software you're writing addresses. The business entities, actors, processes, activities, etc. that your software manipulates.
I'd start with a classic: Patterns of Enterprise Application Architecture by Martin Fowler. He blogs a lot on topics related to enterprise architecture.
I'd follow up with another classic: Domain Driven Design by Eric Evans. Martin Fowler has a lot to say about DDD as well
You didn't go into too many details, so I just wanted to make sure you weren't missing the things that make for a a foundation.
I think Domain Driven Design is a good path for you, mainly because it doesn't necessarily over prescribe a technology stack (those are in constant flux) and focuses on the fundamentals of designing for a domain and understanding how to deal with the complexities that come with it.
Eric Evan's book is a great place to start. Personally I have two other books that are incredibly helpful for DDD. The first is Implementing DDD by Vaughn Vernon, and the second is Patterns, Principles, and Practices of DDD. I think the second is a little more along the lines of what you're looking for, but doesn't go into as much of ideas and structures of DDD. What it does do is go into more of the patterns that you're far more likely to see in an enterprise application.
Two patterns that you should pay attention to are Command Query Response Segregation (CQRS) and Event Sourcing. CQRS can be used in a number of ways and incarnations. Event Sourcing may or may not be applicable in your application, but its useful to think of an application's state and interactions as an immutible ledger of events.
If you go down the road of microservices, then I strongly suggest you also explore message queues as well. Although they certainly are useful, microservices are seen as somewhat of a fad or buzzword. Message queues, and the patterns that go with them, are quite useful in this context and also applicable in more "traditional" service oriented architectures as well. A great book for diving into those messaging patterns is Enterprise Integration Patterns.
NoSQL and Big Data solutions will likely come up along the way, and although they are worth exploring in their own right, I think its important that they are implemented for the right reasons. I'll leave this here for now, if this is something that you want to explore further, I'd suggest reading through Fowler's Polygot Persistence as a good jumping off point
Focus on other aspects. Reading and being able to talk architecture has gotten me a lot further than the “cracking the code”, leetCode type of stuff.
(None of these are affiliate links)
https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882
https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164
https://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420
https://www.amazon.com/Refactoring-Improving-Existing-Addison-Wesley-Signature/dp/0134757599
https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670
https://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X
Have you ever heard of the open/closed principle? Or the single responsibility principle? Or Liskov substitution principle? All three are being violated. It drastically reduces the maintainability and extensibility of your code. I can't swap serializers easily, i can't tweak or extend them without touching that huge class and it's definitely not the responsibility of that class to know how to serialize A, B, C, D, E and the whole alphabet.
I highly recommend some literature on the subject if you're curious about it, it would drastically improve your approach to software architecture:
https://www.amazon.com/dp/0132350882
https://www.amazon.com/dp/0201485672
https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
http://cc2e.com/
https://www.amazon.com/dp/0321127420
Interesting!
Looks to me that you can "feel" what good code looks like but you're not able to rationalise it enough for you to write it on your own.
Couple of suggestions:
When you see elegant code, ask yourself: why is it elegant? Is it because is simple? Easy to understand? Try to recognise the desired attributes so you can try to reproduce on your code.
Try to write really short classes/methods that have only one responsibility. For more about this, search for Single Responsibility Principle.
How familiar are you with unit testing and TDD? It should help you a lot to write better designed code.
Some other resources:
Quick note about number 6: Those terms are a lot more intimidating than they sound. Some of them take a little while to really grok what they are and why they are useful but once you understand them they are extremely useful (and huge selling points for yourself as a developer).
About the interview: From what I've heard the questions they ask are different based on different backgrounds. They are less likely to ask software development methodology questions to a new graduate since that's not really in the realm of computer science.
I did get asked some questions regarding data structures and algorithms. The ones that I was asked, and I feel I did really well on, were more related to problem solving and software architecture. Think of it this way, if they hire you, in your day to day job having memorized how to traverse a graph isn't going to come up that often. Your day to day is going to consist of coming up with solutions to problems presented with you.
So when they ask a question like how to traverse a graph, they aren't looking for you to be able to spit out Dijkstra's algorithm exactly. Instead, they are looking to see how your brain works and what kind of solution you can come to by logically breaking down the steps to solve the problem.
They are looking for how you take a problem, break it down in pieces, and what your solution would look like.
Example: Implement a scale, that has two sides and lets you know based on the objects on the two sides, which side is heavier and by how much?
My answer to this question would be something like:
How do you store the set of items on each side of the scale internally in the scale class? Do you need to be able to remove items from the scale, and why would this affect how you store the items internally? Should the scale have a weight limit?
These are all great questions to ask. Think out loud, talk out loud. They want to see that when confronted with a problem you don't know the answer to, or don't know the best solution to that you don't freeze up but instead chunk it up and try to reason your way through it.
"Should the scale have a weight limit?" Asking the interviewer this question is a huge win in your favor. It shows that not only are you trying to solve the problem, but you're constantly thinking about issues that might have been overlooked in the initial assessment.
Back on number 6: I learned these by googling a fuckton. Watching a lot of videos, reading a lot of tutorials, and just asking a lot of questions.
Here's some resources I still have bookmarked from the last year/18 months. Some of them are for targeted for php, but the concepts are universal. But if any of these don't do it for you, google a bunch.
Solid: 1 2
Inversion of Control & Dependency Injection: 1 2 3 4
Domain Driven Design: This is actually a ton of concepts, and you don't necessarily need to learn them all at once. This book is the only software architecture book I've read cover to cover, its that good. If you can afford to, do buy it. Also another helpful link Intro to DDD.
Test Driven Development and UnitTesting: 1 2
Also I've found many of the top answers stackoverflow user tereško are great sources of wisdom regarding software development.
I’m fairly certain (sorry if I’m wrong) he means the book by Eric Evans:
https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
I would recommend looking into Domain Driven Design (DDD). A book a lot of people recommend is Domain Driven Design by Eric Evans but sometimes it's hard to translate the examples in the book to something you can apply in JavaScript. However you can probably find articles about DDD in JavaScript if you google for it.
Domain Driven Design
Pragmatic Programmer
> I don't know what the fuck you're actually advocating.
Try to get some more experience, kid. Especially with things like Dependency Inversion and Domain Driven Design. Then maybe you'll understand.
> Put adaptors on all the things so you don't depend on them, but
> you're not passing interfaces to everything.
You don't create such fine grained interfaces that wrap around a single library in particular. That would make the adapter nothing more than a call translator. You would end up with a bunch of interfaces around every little library you need, and that would be dumb.
The whole point is that your code represents some business functionality, and the architecture should be dependent on the rules of the business. At some point you'll need help with some aspect of the business or another. You write an interface to describe that need. The adapter simply fulfills that need.
The adapter will probably have functionality of its own, and depending on the system, perhaps not trivial. But that functionality is isolated from the rest of the system. It can be replaced at some cost that is isolated.
J2EE application servers do a lot of work, and the EJBs leveraged that capability (like clustering, distributed transactions, etc.). We had to find replacements for those capabilities. The replacement wasn't trivial. But the application itself could care less about most of that. So the risk to the application was substantially reduced.
Which allowed us to focus on specific, isolated areas and didn't risk the entire application.
> Then you talk about the one time that architecture saved you
> time and not the five hundred times it didn't.
Prove it.
> If you're putting all libraries in an adaptor then you're interfacing
> all the things and your constructors will be huge or nested.
The number of interfaces depends on how fine grained your abstractions are. You don't want your abstractions to be too fine grained, or you'll have a ton of dependencies. If you end up creating 15 interfaces in your constructor, that means you have way too many dependencies. That's a definite code smell and a definite sign you need to rethink your abstractions.
> If you're transforming your data
And what data would that be? For the most part, we are talking about parameters.
> you've got application logic in your adaptor which means
> replacing it is not low risk.
Not application logic, which is another domain. But logic related to the domain of the library. Because that logic is isolated, and independent of the business rules of the application, it is a lot easier to replace.
> If you're encapsulating your errors you've broken your stack
> trace.
Nope. The error is simply being recast into the application's domain. That is if it needs to be recast into the applications domain at all. The adapter can do much of the error handling itself, if that error handling falls into its domain.
> Separating your business logic from your presentation layer has
> nothing to do with being dependent on libraries.
It has everything to do with it. The separation of presentation layer from business logic is small potatoes compared to what I'm talking about. The Domain Driven Design book has a great section about the Anti-Corruption Layer, which describes how to protect an applications architecture from the architecture of other libraries and systems.
Libraries that represent an entire domain separate from the business domain shouldn't affect its architecture. If the library is substantial enough that it could effect the architecture of the application and more importantly is a risk to the application, it belongs to a different domain and the domains should be separated to reduce risk. We're not talking apache-commons-lang which just does string manipulation.
Grady Booch
http://www.amazon.com/gp/aw/d/020189551X/ref=pd_aw_sbs_14_2?ie=UTF8&amp;dpID=51-uo4HUPCL&amp;dpSrc=sims&amp;preST=_AC_UL100_SR100%2C100_&amp;refRID=110KGH6M22KWAJHKWZ5F
Eric Evans
http://www.amazon.com/Domain-Driven-Design-Tackling--Software/dp/0321125215
Martin Fowler
http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420
> That's exactly a multi-agent simulation.
Well yeah, that was kind of my point. At least in biology, this isn't unusual.
> For most processes this is a too low level representation to be
> useful.
I find very useful, and I've modeled pretty much all business processes that I've implemented this way. Eric Evan's excellent book Domain Driven Design describes some very useful ways to reason about business processes, in effect, as multi-agent simulations (if you call an agent an entity in DDD terms).
No problem! I've been reading this one, and it's an awesome resource: http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
Aside from that, Domain-driven design gets occasionally discussed over at http://laracasts.com, and there's a google group specifically for using DDD in php: https://groups.google.com/forum/#!forum/dddinphp
> but as far as I know the repository pattern only really achieved popularity after the blue book came out and that's the one DDD technical pattern that really seems to have been widely accepted.
Are you talking about Smalltalk-80 the Language and it's Implementation? Or this book on Domain Driven Design?
These are insightful questions and the answers are less obvious that it might seem. There are subtleties that for various reasons I can't and won't cover here, and the best advice I can give you is to read about the subject(s). The second best advice I can give you is to search Google like mad, because there's a lot of stuff out there and I don't have time to find other books.
> but setters should be protected, for extensibility
How often do you extend your classes? If it's often, it's probably too much -- favour composition ("has-a") over inheritance ("is-a"). I declare all my classes
final
to start with and I rarely have to change that. More, your private members are the only ones you have complete control over -- as soon as something isprotected
a deriving class can use it, and then the member is effectively part of the public API after all. For this reason,protected
is nearly as bad aspublic
. This is one of the things Scott Meyers talks about.> Furthermore, do I even need setters if my class is going to be the only thing setting its variables?!
Automatic code generation is one of the least helpful things IDEs have given us and, I contend, a direct source of much shitty code. Make no setter or getter until it is absolutely needed, and provide neither for
public
fields (that will cause confusion).> Should I ever be setting object variables outside the class?!
"It depends". There are valid reasons for it, and of course I can't think of any off the top of my head. What you should absolutely avoid is the ability to construct a
Foo
without aBar
whenFoo
cannot work withoutBar
. In this case, it's a constructor dependency, and aFoo::setBar()
implies thatFoo
'sBar
instance can be in an invalid state.Been reading that and this
Breaking away from the Rails (or in my case Django & SQLAlchemy) mindset of the model is both the business model and the persistence model can be hard to do.
However, why not this? -- This might not be good scala, I mostly tool around in it, you'd probably want status as a private attribute:
abstract class TaskStatus()
case class TaskCompleted() extends TaskStatus()
case class TaskPending() extends TaskStatus()
class Task(var status: TaskStatus) {
def isCompleted: Boolean = status match {
case TaskCompleted() => true
case => false
}
def markCompleted(): Unit = status = TaskCompleted()
}
Then Task is a regular object with no ties to a repository or service.
new Task(TaskCompleted()).isCompleted // true
new Task(TaskPending()).isCompleted // false
val t = new Task(TaskPending())
t.isCompleted // false
t.markCompleted()
t.isCompleted // true
This makes Task an entity it has business logic and state that persists from session to session (this other state is probably a title, who its assigned to, and an ID as a persistence allowance, but I've omitted these for brevity).
You can then stuff these tasks into a data store (pick your poison on how you do that) and reconstitute them from that data store -- essentially that's what a repository is: take in some entities, shove them into a data store; take in a query, pull some entities out of the data store.
With that in mind, your
TaskService.isTaskCompleted
can be a simple wrapper around a repository query that pulls that one task out and doesTask#isCompleted
on it (note you'll want to guard against unfound Tasks):class TaskService(val repo: TaskRepo) {
def isTaskComplete(id: Int) {
repo.findId(id).isComplete
}
}
Expanding this out to your TaskAssignments, your task now holds a reference to many TaskAssignments that probably have an
isCompleted
on them as well. In that case,Task#isCompleted
can end up just being `tasks.forAll(.isCompleted).<br /> <br /> Still no reference to a repository. The trick here is that
Taskis now an aggregate. When you ask the repository "Will you find me task 12345?" It not only pulls the literal
Task` out of the data store, but also all the parts of the Task as well. So you get the Task and the TaskAssignment objects.You might want to check out Domain Driven Design which helped cement these sorts of ideas in my head.