Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example with Data Source et Wireframe #1

Open
JeanLebrument opened this issue May 27, 2014 · 26 comments
Open

Example with Data Source et Wireframe #1

JeanLebrument opened this issue May 27, 2014 · 26 comments
Assignees

Comments

@JeanLebrument
Copy link

Hi,

First of all, I would say big thanks to those which wrote this article and carried out VIPER architecture, this is really great.

I try to implement VIPER architecture for my app but I would have an example on how implement Wireframe and Data Source.

In your article on your blog, you said that you will add a new example with Wireframe and Data Store soon ? When will it be available ?

Best regards,
Jean Lebrument

@cnstoll
Copy link

cnstoll commented May 27, 2014

Hey Jean,

Glad to hear that you've been finding this helpful! I know some work is being done on an updated example. I believe we'll have more information on that to share soon!

Thanks,

  • Conrad

@cnstoll cnstoll self-assigned this May 27, 2014
@JeanLebrument
Copy link
Author

Thank you very much !

@ghost
Copy link

ghost commented Jun 19, 2014

Hey,

I wanted to ask, if I want to send some data from one viewcontroller to another, how do I send it using the VIPER architecture?

Thanks

@cnstoll
Copy link

cnstoll commented Jun 19, 2014

FYI - The new article on VIPER that I mentioned for @JeanLebrument is published here:
http://www.objc.io/issue-13/viper.html

@cnstoll
Copy link

cnstoll commented Jun 19, 2014

@shwetsolanki with VIPER you sort of lose the concept of transferring data between view controllers and replace it with the concept of transferring data between screens. There are certainly cases where data needs to make it from one screen to another, such as to populate an edit screen to modify a selected item. In this case, the two presenters for the respective screens have to work together to identify the piece of data from one screen, possibly modify it to make sense to the other screen, and pass that along when the second screen gets displayed.

@ghost
Copy link

ghost commented Jun 20, 2014

@cnstoll Thanks a lot. It would be great if you guys could add this to the To Do example. Passing the selected ToDo from one screen to another and showing a detail todo screen. I know it doesn't make much sense functionality wise, but will clear the doubts of many others.

Cheers!!!

@hugobast
Copy link

Allow me to put a 👍 to the previous commenter, I figured my own way of passing stuff view to view but I am dying for an authoritative example on this.

@hugobast
Copy link

I'll put my way of doing it could lead to a discussion (it's ok if it doesn't or if the example gets shot down). Let's imagine a table view for which tapping a row segues to a detailed view of that item:

From the List Wireframe

class SomethingListWireframe: NSObject {
  weak var controller: SomethingListController?

  func presentSomethingListInterface(parent: UIViewController) {
    // ... wire up the VC -> Presenter -> Interactor, etc
  }

  func presentSomthingDetailInterface(selection: Thing) {
    let wireframe = SomethingDetailWireframe()

    wireframe.presentSomethingDetailInterface(controller!, thing: selection)
  }
}

Then in the Detail Wireframe

class SomethingDetailWireframe: NSObject {
  func presentSomethingDetailInterface(parent: UIViewController, thing: Thing) {
    let controller = SomethingDetailController()
    let presenter = SomethingDetailPresenter(thing: Thing)

    // ... wire up the VC -> Presenter -> Interactor, etc

    parent.navigationController?.pushViewController(controller, animated: true)
  }
}

Of course this entails that something on the list side holds a reference to the list wireframe, I think I went with the presenter, so messaging goes: Cell -> ViewController -> Handler (presenter really) -> InteractorInput -> InteractorOutput (presenter again most likely) -> Wireframe with the Interactor being completely optional depending on the use case.

Good/Bad/Ugly? Let's have it!

@JeanLebrument
Copy link
Author

I worked on a complicated project as lead iOS developer and we developed the whole project using VIPER architecture.

To pass data from one module to an other, we decided to add a class to each module called "module i/o" which aims three goals.

First one, instantiate the whole module and connect classes together.
The second one, is to manage the "parameters" needed in input so that the module works normally.
The last one, manage the output of the module and permits to instantiate an other module (by instantiating the "module i/o" class of the next module) and give him needed parameters.

Another interesting thing with the "module i/o" class is you can easy extend it by creating a subclass to change the output module instantiated and the rest of the module (wireframe, presenter, view, interactor, data store and entities) are totally non-dependent of the "module i/o" class.

Moreover to navigate between modules, we used JLRoutes.

If you are interested I give you more explanations about it.

I would be very glad if I can have some feedbacks about my solution.

@hugobast
Copy link

Hi @JeanLebrument thanks for responding! The module approach you describe was the next logical step for me. I am waiting to feel some kind of pressure to move me toward it, it feels like a good thing. I would be very interested to know more about your approach for sure.

@fatuhoku
Copy link

👍 @JeanLebrument would be good to learn more. Nothing would be better than a little toy project.

@JeanLebrument
Copy link
Author

@hugobast and @fatuhoku, I will show a little project, but I'm super busy right now with my midterms.

Cheers

@hugobast
Copy link

@JeanLebrument Sounds good, I'll keep an eye out. Let us know.

@delebedev
Copy link

Hey @JeanLebrument any updates here?

@JeanLebrument
Copy link
Author

Sorry dude, I was really focus on my exams and I totally forgot answer to
this issue after! I will do it right now.

On Thu, Apr 23, 2015 at 8:14 AM Denis Lebedev notifications@github.com
wrote:

Hey @JeanLebrument https://github.com/JeanLebrument any updates here?


Reply to this email directly or view it on GitHub
#1 (comment).

@JeanLebrument
Copy link
Author

I just finished to code an example with a class diagram: https://github.com/JeanLebrument/iOSModuleArchitecture

The architecture looks overkill for the type of project, but in a large scalable project with a lot of interaction between modules which need to be abstracted, this architecture permits to maintain a high level of scalability.

Feedbacks are welcomed!

@delebedev
Copy link

@JeanLebrument 👍

@hugobast
Copy link

Thanks for doing this @JeanLebrument

@JeanLebrument
Copy link
Author

You're welcome! Sorry for the delay!

@tar500
Copy link

tar500 commented Jun 2, 2015

Hi @JeanLebrument, @garnett and @hugobast

Almost a year ago I have also made my own version of Counter app with some architectural an file structure changes, that allowed to create/use modules with ease: https://github.com/tar500/viper-counter-app

Also I made my own Objective-C template for vipergen that I used for creating a Counter app modules: https://github.com/tar500/viper-module-generator

This template already includes a lot of boilerplate code, so you can start to add your own code right away. Also there's plenty of helpful comments that help you to think less about what to do.

I would like to know if I didn't mess up the original idea of VIPER, so any feedback is really appreciated!

@membersheep
Copy link

I would like to thank everybody for the helpful discussion.
I'm building a small app to learn to use VIPER architecture and I encountered the same problems that @JeanLebrument solved with the Builder and the IO elements. Giving the responsibility to fulfill those goals to the wireframe seemed wrong and I was theorizing the same solution myself.
@tar500 your generator seems cool, I hope I have the chance to try it soon!

@JeanLebrument
Copy link
Author

I'm glad to hear that my contribution helped you guys!

@hugobast
Copy link

Just a quick update from me here, random thoughts really:

I am moving away from presenters being required objects always. What I do now at the start of a new module is have that be an interface that the Wireframe will implement. Otherwise I end up with a presenter that's managing the view and a wireframe that's only ever used for segues. I usually name a protocol after the module's name. It's all fuzzy still for me. Really I am just scaling it down a little because starting a module is so much overhead that I started hating it.

All that being said I would totally introduce a presenter object and have that object implement the module interface if the wireframe gets messy.

Other random thought, I'm fine with the wireframe knowing about everything by name, but nothing should know about the wireframe only the protocol it implements (exception being either the AppDelegate or other the RootWireframe if you have one of those). Other than that it's on a case by case basis. At first I overused protocols and there was really no reason for it.

@membersheep
Copy link

I think that as long as you have a user interface for a module, the module should have a presenter to present and to control it (so it is usually required), and if the module is connected to other modules it should have a wireframe to handle this routing (but it handles the routing, nothing else). I understand that in smaller projects the overhead of decoupling like this may seem wasted time, but I think that when one is used implement the architecture everything becomes fast and easily testable

@scottrhoyt
Copy link

Just to add my quick 2 cents (feel free to respond with questions).

I have mostly abandoned the VIPER architecture. Here's how I felt about my experience.

Pros:

  • Presenter - This is the biggest advantage of the architecture. Getting that code out of the VC makes everything more manageable, testable, and maintainable.
  • Interactor/Entities - The distinction between entities and interactor data structures helps keep things like core data and other data services from creeping into view code and making things messy.

Cons:

  • Too many objects. So many times the interactor and presenter are doing too little work to justify. Writing unit tests for these objects becomes tedious and not useful as well.
  • Viper modules tend to make my think about my code as silos. This has advantages, but I found it worked against me writing reusable code. Sometimes I code get an interactor to be reusable, but this required a good deal of subclassing and adapters to also have the specific interactors conform to module-specific interactor protocols. Simple things became a lot of boilerplate quickly.
  • Wireframes are poorly defined currently. They seem to have the responsibilities of both routing and module assembly. Routing is a good concept when you outgrow storyboards, but module assembly is handled better by DI frameworks in my opinion.
  • Inelegant model if you are working with some services. In particular, I love Parse. When using Parse with VIPER, I have to either give up a lot of the niceties of Parse, or come up with other additional mapping schemes to recover functionality at the interactor/presenter barrier. This is mostly because of the two different methodologies at play in VIPER and Parse. A Parse object encapsulates most of the business logic of the data object into the data object itself.
  • Asynchronous code is more difficult. If you need to have an asynchronous data operation, it should manifest in the land of entities/interactor. But that asynchronous operation now often becomes an asynchronous interactor method and an asynchronous presenter method. If you use another data manager object in the entity layer, this is a third asynchronous operation. Testing asynchronous operations is not trivial and with VIPER I find myself writing 2x the tests and usually for passthrough methods.
  • Inter-module communication is not well defined at all.

In short, I find the architecture to be too rigid. I wind up with too much boilerplate code, not enough reusable classes, and hacked together intermodule communication. The effort does not seem worth it for small apps, and for large apps, the abundance of trivial objects, lack of reusable code, poor intermodule communication standards, and non-trivial coexistence with DI frameworks and back end frameworks makes it's usefulness suspect.

I vote to keep the one concept that I really find useful (presenters) and throw the rest out. This makes the architecture look a lot more like MVVM.

Cheers

Edit:

This is from my experience writing an app with 12,000 lines of code with VIPER. Without VIPER, I believe the app would have been < 10,000 LOC.

@membersheep
Copy link

Thank you Scott, your answer is very interesting, it confirms my doubts. Maybe the lack of strict boundaries (in wireframe and intercomunication) in some modules of the architecture is done on purpose to make those parts more flexible, but I found it a little confusing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants