Win a copy of Terraform in Action this week in the Cloud forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Paul Clapham
  • Ron McLeod
  • Liutauras Vilda
Sheriffs:
  • Jeanne Boyarsky
  • Rob Spoor
  • Bear Bibeault
Saloon Keepers:
  • Jesse Silverman
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Piet Souris
  • Al Hobbs
  • salvin francis

Cost of building flexibility

 
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I read about all of these theories about reusing code and building flexibility into systems.
It seems to make systems more complex and more costly.

Have any studies been done to show that the additional cost and complexity is worth the effort?
 
Marshal
Posts: 74388
334
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What makes you think that reusing code makes systems more complex? I am sure that is mistaken.
 
Saloon Keeper
Posts: 24575
168
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There's the cost of designing flexible code and then there's the cost of doing the same thing over and over again.

In theory, flexible code is cheaper in the long run and - in my experience - more robust, since it has to meet both current and future anticipated needs. And I do flexible code.

In the Real World, however, where developers are paid by the hour, a lot of people have found it more profitable to keep re-writing the same stuff over and over again, whereas I solve the problem once and forever and get laid off because they "don't need me anymore".

Note that you can be too flexible. Many complaints have been made about overly-abstract Java designs. On the other hand, what may seem overly abstract today may not seem so tomorrow.
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Adding levels of classes with the intention of decoupling classes is making things more complex. Adding these classes to your version control and updating them takes time.
It costs more to develop these classes (or do you work for free?).

So my question is - is it cheaper to this type of thing up front or to make the changes when necessary later on?


Of course, if you know that something is going to be reused, or has a high likelihood of being reused, it should be designed with that in mind.

Putting in abstract classes to separate the persistence level from the business level so that the persistence technology can be changed easily is only
worth the effort if you are likely to change the persistence technology during the lifetime of the system. Is this done frequently? How big are the changes?
Do you really save any real time? Since you are likely to retest everything anyway, it is not as effortless as people make it sound?

Is it that much easier to change an XML file rather than the dependent classes Java source (for dependency injection)?
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Look at this example and tell me it is not overly complex.

http://www.journaldev.com/2410/spring-dependency-injection-example-with-annotations-and-xml-configuration
 
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As with many things in software, there's a balance to be struck. Flexibility does in fact comes with a cost. Flexible components take more time to design and test properly. They can add one or more layers of abstraction, which does add to complexity. However the benefit of being reusable in many situations and making easier to use because of the abstraction it provides can far outweigh its costs. It is possible to go overboard and add flexibility prematurely when there's really no concrete justification for it.

My rule of thumb is to follow the 4 Rules of Simple Design and write clean, well-factored code. When a new situation arises that creates duplication where there once was none, I refactor, usually by extracting the duplication to another abstraction. That abstraction brings with it flexibility. Basically, I don't add flexibility just because I think it might be needed in the future -- I try not to do predictive design, mainly because years of experience have taught me that I'm not in the "business of seeing the future" because I suck at it. I add flexibility whenever the need and opportunity arises.

Here's my handy-dandy development toolkit, which I try to use every day at least as many times as I write any methods and classes:

1. Ruthlessly Refactor using Rename to clarify intent
2. Ruthlessly Refactor using Extract to remove duplication
3. Ruthlessly Refactor using Compose methods to get single levels of abstraction (SLAP)
4. Stick to your good design principles - SOLID, DRY, GRASP
5. Follow the 4 Rules of Simple Design
6. As much as humanly possible do Test-Driven Development
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the answer..
How do you do test driven development in an agile environment?
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Also, would you used Dependency Injection if there was no immediate need for it?
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:Look at this example and tell me it is not overly complex.

http://www.journaldev.com/2410/spring-dependency-injection-example-with-annotations-and-xml-configuration


If that's all you're trying to do, then yes, it would seem like it's waay over-engineered to do just a few simple things. However, you have to imagine the example code existing in the larger context of a full-blown application that does more than just what the example highlights. Sure, you could jam all of this stuff into just a few classes and get rid of Spring. There's a cost to doing that though and in the context of a larger application, a more simplistic and straightforward approach will probably cost way more than having a proper layering and separation of concerns. What I said earlier about simplicity still applies though.

I like this quote and often cite it:

Gall's Law - A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over with a working simple system. – John Gall (Systemantics: How Systems Really Work and How They Fail., 1975, p.71)

Using Spring allows you to add many abstractions that would take way too much time and effort to code yourself. But you're right, it does add a few levels of complexity. The trick is to push the complexity as deeply into the application code as you can so that you are dealing mostly with the abstractions rather than the implementations. Nobody ever said anything about software development being easy. Any non-trivial software is going to be complex and complicated. It's all a matter of managing that so people who have to work with the software can still understand what's going on.
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:Thanks for the answer..
How do you do test driven development in an agile environment?


Not sure I understand the question. TDD is better when done with a mindset and culture that promotes agility.

There are entire books about doing TDD, the best one, IMO, is actually about the "4 Rules of Simple Design" by Corey Haines. Other references I use are Martin Fowler's "Refactoring" book, Josh Kerievsky's "Refactoring to Patterns", Steve Freeman and Nat Pryce's "Growing Object-Oriented Software Guided by Tests" (the GOOS book), Michael Feathers' "Working Effectively with Legacy Code" (the WELC book), Robert C. Martin's "Clean Code" and "Agile Software Development: Principles, Patterns, and Practices" (the PPP book), and Eric Evans' "Domain Driven Design Development" (the DDD book). The last one by Eric Evans is really about design thinking, which permeates everything you do in TDD.

HTH
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:Also, would you used Dependency Injection if there was no immediate need for it?


In all honesty, when I'm starting on a non-trivial project for work, I always start with a Spring-enabled Maven project. This just gets you off the ground a lot faster.

For small projects that I do on the side, no, I don't always use Dependency Injection. Only when I start feeling the pain of not having Spring to take care of the plumbing will I consider adding DI but at that point, I'll probably put the prototype aside and start over with a full-blown Spring-enabled Maven project. I've been playing around with Gradle lately and I like it so far, so I may start moving towards that. It's simpler than Maven but Maven is a very mature tool and there's a lot of support and integrations with other tools which makes it still an indispensable part of most of the projects that I work on.
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

There are entire books about doing TDD, the best one, IMO, is actually about the "4 Rules of Simple Design" by Corey Haines. Other references I use are Martin Fowler's "Refactoring" book, Josh Kerievsky's "Refactoring to Patterns", Steve Freeman and Nat Pryce's "Growing Object-Oriented Software Guided by Tests" (the GOOS book), Michael Feathers' "Working Effectively with Legacy Code" (the WELC book), Robert C. Martin's "Clean Code" and "Agile Software Development: Principles, Patterns, and Practices" (the PPP book), and Eric Evans' "Domain Driven Development" (the DDD book). The last one by Eric Evans is really about design thinking, which permeates everything you do in TDD.

HTH



My point is, you are supposed to come up with all of the tests before you start coding. But in an agile environment, things are continually changing. So tests that are written at the beginning may not be valid by the end of the project and some new functionality may require different tests.
I realize that you can add new tests as you go along but I think the concept of writing all of the tests before you start development when you know everything may change seems intellectually dishonest.
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:
My point is, you are supposed to come up with all of the tests before you start coding. But in an agile environment, things are continually changing. So tests that are written at the beginning may not be valid by the end of the project and some new functionality may require different tests.
I realize that you can add new tests as you go along but I think the concept of writing all of the tests before you start development when you know everything may change seems intellectually dishonest.


That's not how TDD works and whoever told you that is seriously misguided. In TDD, code is written in small, incremental cycles:

1. Write ONE failing test - this shows you have a bug in your software (missing behavior is a bug)
2. Write SOME production code to make the test pass
3. Refactor (see the handy-dandy toolkit that I mentioned earlier)
4. Ask yourself: "What bug do I need to deal with next?"
5. If you can't think of any more bugs, you're done. Otherwise, go back to #1.

The above description is just a VERY ROUGH outline. There's much more to TDD than that and it's not an easy thing to learn how to do, especially when you're used to writing software in the more "traditional" way: Do a bunch of analysis, do some up front design, code everything out, maybe test a little bit as you go. When you've coded most of the program out, start testing it to verify that it behaves the way you expect it to behave.

I always tell people I train on TDD that it turns everything they know about software development on its head. It's like trying to learn how to ride a backwards bicycle after years of riding a regular one. It takes a long time to change that rigid way of thinking that has been burned into your brain with years of experience. It took me about 2 years to rewire my brain and get comfortable with TDD. Now it's difficult for me to write software and NOT do TDD. I still can but I'm no longer comfortable doing it.

You'll see how difficult it is for people to get unstuck when they get an idea in the head. Just see some of the more recent threads that I've replied to in the last 24 hours. I find that many programmers, even those who make a living of writing code, seem to WANT to stay in the low level details and find it very hard pull their thinking out to a higher level where they can actually have a better, clearer view of the problem. But that's where you need to be to handle complexity and see the benefits of flexibility and abstractions.

 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And please DON'T get the wrong impression that I don't do design either. That's another big misconception about TDD, that design is just thrown out the window and all you do is write tests. In TDD, good tests actually become detailed design specifications. If you read the listing of my passing tests, they read like a list of behaviors that I expect from my software:



These names are arrived at after much discussion about intent and design. We also tie this in with higher-level automated testing methods like ATDD (acceptance test driven development) and BDD (behavior driven development). Again, design thinking permeates everything we do throughout the process. We will do SOME up front design but that's only to give us a baseline for discussion and exploration. The design changes many, many times as we write tests and see our ideas get codified in the tests and the production code that they exercise.
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Regarding asking yourself "What bug do I want to deal with next?" then writing a test that fails to show that you indeed have a bug ... this is not even a new idea.

The eminent computer scientist and winner of the 1972 ACM Turing Award, Edsger W. Dijkstra, wrote: Program testing can be used to show the presence of bugs, but never to show their absence!

So this idea has been around for a while and it's the exact mindset you need to adopt so TDD really works. Again, this mindset turns the "normal" way of thinking about testing on its head. This another strategy for handling complexity and working in simplicity. TDD helps you focus on the important things you want your software to do and tends to keep you from unnecessary "gold plating". I have found it an excellent way to handle complexity.
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:I think the concept of writing all of the tests before you start development when you know everything may change seems intellectually dishonest.


TDD addresses the intellectual dishonesty of doing Big Design Up Front (BDUF). These are some more ways that TDD turns things backwards:

1. Give up on having certainty in planning and design and accept that there are things that you just won't know up front but will discover as you learn more about your system and how it should behave.
2. Give up on Big Design Up Front and embrace the idea of Emergent Design - small designs up front are fine as long as you accept that things can change as you go. See #1
3. Give up on getting things right the first time. We're human, we can't see into the future and we make mistakes. See #1 and #2.
4. The goal is not to get it right the first time, it's to get it right in the end, before we go to production.
5. TDD is a way to make a lot of mistakes up front, incrementally discover how you want your software to behave, and keep moving forward with well-factored and well-tested code base, one small increment at a time.

As Uncle Bob Martin says, "The only way to go fast is to go well."

 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:Regarding asking yourself "What bug do I want to deal with next?" then writing a test that fails to show that you indeed have a bug ... this is not even a new idea.

The eminent computer scientist and winner of the 1972 ACM Turing Award, Edsger W. Dijkstra, wrote: Program testing can be used to show the presence of bugs, but never to show their absence!

So this idea has been around for a while and it's the exact mindset you need to adopt so TDD really works. Again, this mindset turns the "normal" way of thinking about testing on its head. This another strategy for handling complexity and working in simplicity. TDD helps you focus on the important things you want your software to do and tends to keep you from unnecessary "gold plating". I have found it an excellent way to handle complexity.



Thanks for the info. I'm sure they have changed the Wiki explanation of what TTD is. I never saw anything about just writing the tests for a small part of the project, like a class or new feature. I thought they were supposed to be written for the entire project, which seems cumbersome.
I still think you can learn a lot about what the system is supposed to do during the development process. For instance, sometimes the data shows you that additional tests are needed that you didn't know about until you saw the data. Perhaps some account type you were not aware of or something.
What this does seem to indicate is that there is some conflict between programming only what needs to be programmed and building flexibility for the future. I'm sure you are going to tell me that is done in the refactoring stage.
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:What this does seem to indicate is that there is some conflict between programming only what needs to be programmed and building flexibility for the future. I'm sure you are going to tell me that is done in the refactoring stage.


Am I that easy to read now? As a programmer who strives for readability, I'll take that as a compliment

Sandi Metz said it best in this tweet: https://twitter.com/sandimetz/status/441241600077725697

Sandi Metz on Twitter wrote:Don't write code that guesses the future, arrange code so you can adapt to the future when it arrives

 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:I never saw anything about just writing the tests for a small part of the project, like a class or new feature. I thought they were supposed to be written for the entire project, which seems cumbersome.


Think even smaller. A test that you write while doing TDD can be for as little code as a simple if-statement that's missing from a method. Higher level tests like what you'd have with ATDD and BDD are more at the level of classes, features, components, modules, and interfaces between application layers.

And yes, writing all your unit tests for the project before you write any production code would be intellectually dishonest and downright insane.
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I've spent all morning reading about ApplicationContext and Spring annotations and I think I actually understand what is going on in this example.
The DIConfiguration class has Spring load an occurrence of all beans from com.journaldev.spring.di.consumer into the ApplicationContext by using @ComponentScan
and also an occurrence of the EmailService class.

Then the ClientApplication uses the getBean method of the ApplicationContext to instantiate the MyApplication object app. Then it executes a method of app.

Am I close?


http://www.journaldev.com/2410/spring-dependency-injection-example-with-annotations-and-xml-configuration
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:Then the ClientApplication uses the getBean method of the ApplicationContext to instantiate the MyApplication object app.


Close. You shouldn't assume that instantiation is happening with the call to getBean() -- the instance could already be there and you're just getting back a reference to it. All the call is really saying is, "Hey, ApplicationContext, give me a reference to a bean of class MyApplication" - the client doesn't care how that reference is materialized, whether through instantiation or through a lookup in a table of existing instances or through some other kind of magic.
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Tim Bee wrote:Then the ClientApplication uses the getBean method of the ApplicationContext to instantiate the MyApplication object app.


Close. You shouldn't assume that instantiation is happening with the call to getBean() -- the instance could already be there and you're just getting back a reference to it. All the call is really saying is, "Hey, ApplicationContext, give me a reference to a bean of class MyApplication" - the client doesn't care how that reference is materialized, whether through instantiation or through a lookup in a table of existing instances or through some other kind of magic.




It should be in the ApplicationContext because of the @ComponentScan(value={"com.journaldev.spring.di.consumer"}) statement.
So it is just referencing the bean in the ApplicationContexy.
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
One more question about the sample app that I linked to. When does the setService method of MyApplication get executed and why? I don't think it is called anywhere. I could understand if the service was set in the constructor but it isn't.

Thanks.
 
Rancher
Posts: 4801
50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It's injected by Spring based on the DIConfiguration class (in this case).
So it would be an EmailService, if I've scanned that code correctly.
 
Java Cowboy
Posts: 16084
88
Android Scala IntelliJ IDE Spring Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:As with many things in software, there's a balance to be struck. Flexibility does in fact comes with a cost.


I agree with Junilu.

You need to find a balance to design software. On one hand, you don't want to have tunnel vision and build a rigid system that does only exactly what the customer wants and that is hard to add new features too, and on the other hand you don't want to build a system that is so flexible that it can do anything. Designing and building an infinitely extensible and flexible system is going to cost much more time and lead to a much more complex system than necessary. See Inner-platform effect for an interesting description of this.

Another thing that comes to mind here is the YAGNI principle (You Aren't Gonna Need It - only build stuff that is actually necessary, don't build stuff because you think you might need it in the future).

One problem with designing software is that in the beginning a customer will give you a specification of what they want, but you don't know (and often, the customer themselves don't know) what new features they might want for the system in the future. You can try to design it so that it is extensible in one particular way, but it's really hard to predict if that particular way you chose will really be important in the future, or that it should be flexible in a different way.
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here's another quote along the same lines that I dug up from my EverNotes:

"Your task is not to foresee the future, but to enable it." —Antoine de Saint Exupéry, Citadelle or The Wisdom of the Sands (1948)

This is exactly what truly incremental and iterative development gives you an opportunity to do. It might surprise many that the idea of Technical Debt as Ward Cunningham, who coined the term, originally used it was to describe how they would go ahead and do something they knew wasn't quite right just so they could show their user some running software. After getting feedback, they would "pay back" the time that they borrowed to be able to experiment with the not-quite-right implementation by applying what they learned about how the system really needed to work.

The trouble nowadays is that "Technical Debt" has morphed from being a tactical approach to learning and getting better (very positive, yes?) to something that's to be avoided (Technical Debt? Bad! Can't have it!). The point missed there is the learning that you get from earlier contact with running software and paying the debt back by applying what you learned would make it better and do what it should. If you've never seen his explanations of Technical Debt, Ward emphatically states that you need well-factored code to do this. The term "Technical Debt" was supposed to represent gaps in your understanding how the software should work, not gaps in the quality of the software.

One of the conclusions we came to on an expert panel about Technical Debt at a SPLASH (formerly OOPSLA) conference a few years ago was that the currency of Technical Debt is NOT Quality, as many people believe. It's actually TIME - the time you borrow by not bothering too much to implement the correct thing. That time is used to experiment with running, albeit somewhat imperfect, software instead. You pay back the time that you borrowed by making the software right from your gain (knowledge of how it SHOULD work).
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
...
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Dave Tolls wrote:It's injected by Spring based on the DIConfiguration class (in this case).
So it would be an EmailService, if I've scanned that code correctly.



Yes, but what calls the MyApplication.setService method? Why would that be called from Spring during injection and MyApplication.processMessage is not?
Are all setters called or something?
 
Dave Tolls
Rancher
Posts: 4801
50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The annotation @Autowired.
It acts as a marker, so Spring knows what has to be injected.
Spring uses either other annotations (@Service etc) to find things that match, or the Configuration class (as in this case).
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:

Dave Tolls wrote:It's injected by Spring based on the DIConfiguration class (in this case).
So it would be an EmailService, if I've scanned that code correctly.



But when it is injected, doesn't just the constructor class get executed? I'm not sure why some setter class has been run.


First, let's be clear with our terms. Classes don't get executed. Classes get instantiated. An instantiation of a class results in an instance / an object.

Methods and constructors get called or invoked, which then causes the statements inside them to be executed.

The constructors in the example have been commented out. That means that the example uses setter injection. When Spring injects a MessageService object into MyApplication, it does so by calling the @Autowired public void setService(MessageService svc) method. Only the statements in that method are executed. Nothing more.

I think Dave is right: in the example, the instance of MessageService that gets auto-injected into an instance of MyApplication is the EmailService, which is provided by an instance of the DIConfiguration class.

In ClientApplication, the main method first loads up the annotation-based ApplicationContext, which then causes Spring to go and do its automagic component scan and dependency injections. The call to getBean() on line 12 gives back a fully ready to rock and roll instance of MyApplication.
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Tim Bee wrote:

Dave Tolls wrote:It's injected by Spring based on the DIConfiguration class (in this case).
So it would be an EmailService, if I've scanned that code correctly.



But when it is injected, doesn't just the constructor class get executed? I'm not sure why some setter class has been run.


First, let's be clear with our terms. Classes don't get executed. Classes get instantiated. An instantiation of a class results in an instance / an object.

Methods and constructors get called or invoked, which then causes the statements inside them to be executed.

The constructors in the example have been commented out. That means that the example uses setter injection. When Spring injects a MessageService object into MyApplication, it does so by calling the @Autowired public void setService(MessageService svc) method. Only the statements in that method are executed. Nothing more.

I think Dave is right: in the example, the instance of MessageService that gets auto-injected into an instance of MyApplication is the EmailService, which is provided by an instance of the DIConfiguration class.

In ClientApplication, the main method first loads up the annotation-based ApplicationContext, which then causes Spring to go and do its automagic component scan and dependency injections. The call to getBean() on line 12 gives back a fully ready to rock and roll instance of MyApplication.



When I comment out the @Autowired annotation, it does not get called and I get an error when processMessage is called. I assume it (@Autowired) not only determines which version of MessageService to use but also executes it.
 
Tim Bee
Ranch Hand
Posts: 101
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Tim Bee wrote:

Dave Tolls wrote:It's injected by Spring based on the DIConfiguration class (in this case).
So it would be an EmailService, if I've scanned that code correctly.



But when it is injected, doesn't just the constructor class get executed? I'm not sure why some setter class has been run.


First, let's be clear with our terms. Classes don't get executed. Classes get instantiated. An instantiation of a class results in an instance / an object.

Methods and constructors get called or invoked, which then causes the statements inside them to be executed.

The constructors in the example have been commented out. That means that the example uses setter injection. When Spring injects a MessageService object into MyApplication, it does so by calling the @Autowired public void setService(MessageService svc) method. Only the statements in that method are executed. Nothing more.

I think Dave is right: in the example, the instance of MessageService that gets auto-injected into an instance of MyApplication is the EmailService, which is provided by an instance of the DIConfiguration class.

In ClientApplication, the main method first loads up the annotation-based ApplicationContext, which then causes Spring to go and do its automagic component scan and dependency injections. The call to getBean() on line 12 gives back a fully ready to rock and roll instance of MyApplication.



Actually, I should have said constructor method and setter method.
 
Junilu Lacar
Sheriff
Posts: 16693
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Bee wrote:
When I comment out the @Autowired annotation, it does not get called and I get an error when processMessage is called. I assume it (@Autowired) not only determines which version of MessageService to use but also executes it.


By taking out @Autowired, you took out the hint to Spring to inject a bean that matches the type of the parameter for the setter. I'm not sure that @Autowired actually executes anything. Spring can still do DI without @Autowire but it goes through a separate mechanism. See the XML based configuration section of that example.

With the Autowired example, the EmailService bean is instantiated on line 16 of the DIConfiguration class. When Spring sees @Configuration, it will use the annotated class as a source of instances to inject into components that it finds when it does a @ComponentScan. Any classes that are annotated as components and have @Autowired markers are eligible for autowiring. It will look at the type of the thing that should be autowired, look back at the @Configuration class and see if there are any @Bean things that match that. There are a few ways that a match can be made but it's usually off of the type. If it can find a proper match, it will take that bean from the @Configuration and inject it into the target component's @Autowired member.

In summary,
- Spring's @ComponentScan discovers that MyApplication has been annotated as @Component
- an instance of MyApplication is created. This is what Spring works with from hereon and it gets put into the ApplicationContext.
- Spring sees that MyApplication.setService is annotated as @Autowired
- Spring goes back to DIConfiguration and sees that getMessageService() method is annotated as @Bean
- Spring sees that the parameter for MyApplication.setService has a parameter that is compatible with
the value that the @Bean DIConfiguration.getMessageService() method returns.
- Spring calls DIConfiguration.getMessageService() and passes the returned value to MyApplication.setService()
- The instance of MyApplication that Spring is keeping in the ApplicationContext is now fully wired up and ready to go
- ClientApplication calls the application context getBean() method and gets a reference to the MyApplication instance that Spring wired up.
 
You showed up just in time for the waffles! And this tiny ad:
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
reply
    Bookmark Topic Watch Topic
  • New Topic