 Okay, so first who am I? Well, I'm Mark Bates. I'm the lead developer of the Mac framework And those of you who went to Greg's talk this morning about scaling Ruby. You also know that I'm a rock star Well, yeah And that's about it. That's about as close as I get to being a rock star. I guess Anyway, so, you know, I went to the presentation the presenters talked last night that Jim gave and You know, we talked about slides and and doing all sorts of cool stuff with your slides I'm putting really interesting pictures in there But when you're talking about building distributed applications, there's not a whole hell of a lot of cool stuff you can do So I figured I would jump the gun and beat most people to the punch by simply putting a Simply putting a picture of a good old Darth Vader up there for you has absolutely nothing to do with the presentation But I figure somebody's got to do it at the conference. So I figured I might as well Okay, so what are we going to talk about when we're going to talk about Distributed programming I've stolen a couple bullet points here from Wikipedia But basically we're going to talk about n number of applications running on n numbers of servers all communicating together over network and Easily and transparently connecting their resources and data with one another So now why distributed programming has anybody done any distributed programming in here? Okay, so some of you so some of this might be a bit of a repeat And you might find something out something cool that's new in there and those of you haven't this is a good introduction to it all So the company I was working for a company called helium calm Had some real scalability issues. We were running rails and run into some issues I'm not going to go into the whole can rail scale can't can it go to rails envy site for that And there's plenty of plenty of stuff about that. We ran into a couple issues like said scalability was our first issue We we found that we had parts of our app that were very very very heavy And took a lot of resources to run and parts of our app so that weren't very heavy like the registration page Didn't need a lot of resources to run but because we had this giant kind of monolithic rails app You know one was consuming the resources the other one desperately needed The other problem we were having was ease of development. We are development cycles are getting really long and Really difficult to maintain the reason being is again be this giant monolithic enterprise level rails application And if you wanted to make a change in one particular file It kind of rippled through the whole thing in that you had to do a lot of regression testing You had to make sure your tests were passing and you had to navigate through this rather extensive code base So that's what kind of discern to distributed programming and is a way to solve these three problems So first we took the issue of scalability. Well if we had several applications as opposed to just one application We could run that you know run the heavier applications run more instances of those in their own boxes And run the lighter applications on their own boxes So we had like again the registration page is a very good example of a light application You don't need 50 mongrels running a registration system You need two or three because unless you have a extremely high traffic site that's picking up, you know millions of millions of users a day We didn't we only had you know five or six thousand users a day registering That wasn't what the main part of our application was we didn't need a lot of resources for it However, our rating engine was extremely complicated took a lot of resources And we really needed to push that off into its own series of boxes I'm not just one and we didn't want anybody hitting it through the registration page and using up those valuable resources And then you look at ease of development So now we ended up with you know a half a dozen to a dozen many applications All of them easier to develop and all them easier to maintain because of that You know again, we could we had long pole projects with short pole projects Our long pole projects were anywhere up to 12 weeks not very agile. I know and our short pole projects were much more agile They were up to anywhere up to two weeks But because we had one big one big application the team would start working these long pole projects We have these short pole projects to fill in some gaps in there And those would have to sit there for 12 weeks before they get to QA and then before they would get out to production By having a bunch of smaller applications We were able to say okay, we're gonna have a long pole project here We're gonna create a new application or we're gonna update an existing application And then we're gonna have some short pole projects over here So we're gonna make big revisions to the rating engine about we're gonna add you know address information to the registration page We can get that out really quick while the rating engine is doing what it does So that also helps our quicker release cycles our quicker QA cycles So now the question you have to ask yourself is okay We understand why we need DR we why we need distributed programming question is what does Ruby offer to let us do that How was how was Ruby gonna help us in this and the first thing Ruby gives us is a system called DRB This is in the standard library. It's there when you install Ruby It's very very nice and the basic idea between between DRB is you have two processes Process one process two and they connect together over an IP address in a port Process to you know process one is our server. It fires up. It binds itself to that address binds itself to that port It says I'm offering a service here Come and use me process to says okay. I want that service. I'm gonna connect Using DRB to that IP address in that port and I'm gonna get that get that service Let's look at a bit of code here So here's what our server looks like. I hope those of you in the back and read that We're gonna do a very simple logging server All right, so we're gonna create a new instance of the logger of a logging class That's just gonna go to standard out Then we're gonna start the DRB service and again I said we're gonna bind to that particular IP address that particular port you can obviously use any IP address any port you want And we're gonna give it the instance of the logger that we've created So now we're saying okay Let's share that logger on that IP address on that port for anybody to come along and the very end of it We're gonna join the thread so that the server doesn't stop on us Okay, and our client code is very very simple We're going to get the DRB logger from From that particular IP address in that port and we're gonna call info off it as if it was a regular instance of the logger running locally And we're gonna pass in our first first argument and here's a here's a brief little demonstration of what that looks like If it'll if it'll advance to the next slide, right? Oops. There we go Okay, we're starting our server We run our client we say hello and voila sends it over has anybody ever used RMI and Java Anybody great. Can you do it in as little as lines as code as this? No Would you want to use RMI again? probably not And I think that that demonstrates why you don't want to use RMI again and why DRB is so nice There are problems. However with DRB One of them as we saw if we go back to our to our code here This is our client code. We have to know exactly where that service is We have to know what IP address and what port it's on and I know he's saying okay That's great. We can use a configuration system and we can configure it and voila We don't have to touch our code if the service changes However, what if that server falls a server falls down and another service pops up in its place And it's now in a different port or in a different IP address Well, you know no amount of configuration is really going to help that unless we have you know Array after array of array of you know, here's one port and if it's not there try this one try this one and That's not really going to help us very much. So That's where Rinda comes in Is anybody here familiar with with Linda as a you as a unixist? Okay, two people Think we had this conversation last night Here's basically here's the basic premise behind Rinda. We had a third server into the mix what's called a ring server and Process one and process two both connect to the ring server and say here I am here's where you can find me So if anybody else needs my logging service, you know, they can come to the ring server and find it The nice thing about Rinda is you don't even need to know where the ring server is the ring server broadcasts itself out to your network And all the processes come along register themselves with that and also look it up. So here's a Brief exam. Let's look at some code here. Let's look at our logging code again This time rewritten in in Rinda first thing we need is a ring server and a ring server is very simple very easy to use You see we start the DRB service But this time we're not giving it an IP address or a port and we create a new Rinda's new ring server And we give it a tuple space and a tuple space is basically think about like a giant white board or a big cork board You know, you kind of put it up there and people can come along They kind of pin their services to it and another guy can come along and he can kind of take that service off of it So it's just a centralized storage space. And again, we join the thread So that the ring server doesn't stop. So now this is our rewritten logging server using Rinda Again, we start service without an IP address We find the the ring the ring server that we want and we're going to write to it We're going to write to it basically a simple array and we're going to give it a name space We're going to call our name space RubyConf and we're going to call our service DRB logger And we're going to give it the instance of the logger now This is actually a very important thing to note here. You have to give it an instance. You can't just give it a class So you always have to give something an instance And I'll show you some ways to get around that a little bit because that definitely causes some problems when what you really want To share is class level types methods level type of methods and what have you then we give it a little name a little script of text they're my distributed logger and A renewer and I'm not going to go into renewers. They're a bit of an interesting subject But certainly will take us over our 45 minutes here and then then again we're going to join the thread back up So our client again our clients a little different We're going to start the service and all that's basically doing in the client side is saying we're going to be using some DRB stuff So set it up for me We can find the ring server then off that ring server we're going to try to find under the RubyConf namespace the DRB logger System and we're going to pass nil nil in for the last two arguments because they're wild cards We don't care what the description is if we really wanted to narrow it down to a very specific DRB logger We could obviously put the description in there and that would help narrow that down then once we get our DB logger We're going to call info off it and Bob's your uncle. It'll work So here we'll see we'll start the the ring server Nothing too exciting there We'll start our client our server up again this time with Rinda and we'll fire up our client to say hello There we go says hello All very exciting and very easy to use So now let's talk about a little just very quickly You know I said that it's a place you can go and you can post services and others can come along and find those Services well here's a little class that all it does is list the services for you so you can see which You know what see what services are out there. It's it's useful when you know when you're in production You just want to make sure something's running see where it is. It's good in development for the same reason, but Here I'll give you a brief example of what that would actually do Here we go. We list our services. You can see the RubyConf the DRB logger and it's on this really really nice address at port five five six five eight and its description, so we know that it we know that it is running Okay, so proxies so now we've passed a very simple class and we passed a logging class in DRB and Rinda allow you to pass proxies back and forth for complex objects In particular one of the things we want to do is we want to be able to pass in standard out and standard in from the Clients to the server and because we want to the server to be able to say okay What's your name let the client respond with its name and then give back print back a message to the output of the client So if we take a look here at what our server is going to look like I'll actually zoom in here Particularly this is the method. That's that's of most importance to us Okay This hello method is going to take an in stream and out stream and we're going to ask for the name On the output stream on the input you're going to get the name back from the input stream And we're going to send a send hello back on the output stream and our client again very simple We're going to get the hello service from from Rinda and we're going to call the hello method off it passing in the standard in and standard out And if we run that I hope people can see these examples in the back All right, so Ruby client. What is your name? Well, my name is mark Bates not very exciting, but hello mark Bates So that's a that's a way of pass like said we're passing across input and output streams Which is a which is a really wonderful thing to do But now we have a problem We've passed the proxy along of our input and output stream We've passed logging along and we could pass obviously any other Ruby class we want to pass along any Ruby object rather We want to pass along We have a problem however that so far what we've been doing is we've been passing along Objects that both VMs know about they both have the class definitions for logging They both have class definitions for inputs and output streams What they don't have is a specialized class so our server is going to have a specialized class So we want to pass to our client. How do we do that? Let's take a look with this routes class this really poured routes class and all it has is a foo method on it and Someone just called me and it's going to return back foo-remote So that's very simple if we look at our complex proxy service service here We have a get routes method down the bottom that is going to return an instance of that routes class And we bind the complex per proxy service to Rinda and we want to be able to get that from our client So with our client code here all again all the same until we get down that very bottom line We get the we get the complex proxy service We want to get the routes method off of it and off of that we want to call the foo class the foo method However, when we try to run this Remember the client doesn't have access to the routes class definition So we get this undefined method foo for DRB unknown So how do we get past that because let's be honest passing strings in arrays and hashes and logging is well and good But in a real application, we're not really going to be able to do a whole hell of a lot with that Well, I mean we could do a whole lot with it, but we want to get a little more exciting a little more interesting so if we revisit our routes class the way we solve that problem is by Including DRB undumped and when we do that it's actually going to send a proxy class definition down to the client That the client can then make calls off of and they got proxied back to the server to be run It all sounds like magic and it is a little bit But it's it's very exciting. So if we rerun That that same example again this time with our include DRB and dumped in there You'd see this time in the server we see someone just called me and in our in our client We see foo-remote So that's how we get around DRB undumped So now the question you must be asking yourself is this is great How do I do something really cool with this? How do I really make an application run with this and not have to deal with all this kind of looking up and reading and configuring well the answer to that is the Mac framework and This is something I started writing at helium back in March. It's at 0.8.1 And one of the big goals of it is to really ease the use of building distributed applications it's primarily geared towards web applications, but you could very easily run it as a background application as well and Mac allows you to do three Very simple things one. It allows you to share any object you want Any object any class you want as a matter of fact not just any object in any class It allows you to share your routing information So those I imagine who use rails and MIRB or any other web frameworks know what I'm talking about when I share when I'm talking About routing and I'll talk about why it's important to be able to share routes when you're dealing with distributed Applications in a minute and the last thing that it gives you is the ability to share your views in your layouts Now all three of these things were things that we had problems with at helium So we decided we wanted to build these mini applications as I said and the first thing we want to do is say okay We have our registration app that's gonna have our user object Well, the rest of our applications need to have access to user objects in one way shape or form Right and we need to be able to call class methods off that so we said okay so that's problem number one problem number two we had is our views and layouts with Multiple applications. I'm sure everybody here has run multiple applications. Do you want to look the same? That's a bit of a problem, especially Especially something like rails. There's no really good way to do it You can't really use a plug-in. You can't really use a gem to do that. So you're stuck with either NFS mounts Which have their own problems obviously you're also stuck with copy-paste or are syncing You know from your libraries doing some sort of get sub modules to do it and the solution We came up with was having a Mac Mac application that just did nothing but serve up views and layouts using the distributed views and layouts features of Mac which I'll show you and then the third thing we had was routing and Why why this was a problem was because we have our registration app and our rating app actually That's a bad example. Let's say we have a user Management application and an article application two applications. We had so user management They could go in and they could you know do the user updates edit profiles They could also get a list of the articles that they've written Now we want to be able to have those users click on that article and get taken to the article page Which is in the article application a completely separate application. So we could either Duplicate the entire routing stack from each of our applications in each of our applications We could hard code Those routes we could say okay. We know that it's slash article slash ID So we're gonna hard code that in there But God help us if articles ever changes its its address and the third thing is we want we also didn't know if it was even Going to be on the same host because it could be articles dot healing dot com and users dot healing dot com And so we'd have to know that as well. So now you get into this whole configuration nightmare and Mac very simply and cleanly Wraps that up for you So let's take a little bit a quick look at some of the code and see how Mac is going to help us The first thing we need to do is actually add the Mac distributed package to any Mac application Very simple in your config initializers gems file you add gem add Mac distributed And now you've got access to all the Mac distributed stuff next thing we need to do is is add these five lines of configuration This honestly and truly is the all the configuration you actually need to do to get your Mac application up and running You give it an app name and that's going to be what we were using is ruby comf earlier So in this case, we're going to build a quick news application And that's going to be our top level namespace for all of our services are for this for this application We're going to run underneath it We're going to give it a site domain and the reason we do that is for our routing because again We don't know where this application is actually we don't know we know that it might be news dot Example calm, but we don't know that it when we're in users dot example calm And so we can't rely that it's on users dot example calm So this will give us a fully qualified URL. It's it's not the most perfect solution, but it's a solution And then the last three is where we turn on the three things that we can share You want to share your views your objects in your routes? So the answer to these things is all true in this particular case You don't have to use all of them you do but once you do that your app fires up It's going to start registering all your views all your layouts with Rinda It's going to register Your your objects that you used to tell it to register and I'll show you that in a minute and finally it's going to register your routing with with the ring server So if we look at our routes our routes are very simple here. We haven't done anything special to our routing We've got a resource called news items and Mac routing is very similar to rails routing and it's very similar to Merbs previous router before they went and changed it like two weeks ago Except a little more powerful than than the rails router Simple little plug there. Anyway, then we have our news item model If we're in this case, we're using data mapper could be active record It could not be a database-backed model We whatever you want the thing I want to draw your line your attention to is include Mac distributable That's all we need to do to get this object to register itself with Rinda So now you can you know the clients have now have access to this news item model At the class level and I'll show you that because I think it's that's that's really cool Because again, you can't do that basic our client side All we need to do to get our client to be able to work is to add is to add the Mac distributed package to our clients That's it. That's all you need to do. That also means the client can now become a server I'm Mac. It's an end-to-end relationship or end-to-end relationship. How we want to do it many to many So anything to be a server anything to be a client So now let's take a quick peek here We fired up the top is our server and the bottom is our console and First thing we're going to do is we want to try and get that news item from the server So here we're going to say okay Mac distributed news item dot all there is no new news item in our client application There's no package called Mac distributed But instead but we are calling Mac distributed news item and then we're calling a class method off of that news item This is where Mac gets really cool because anything you call in the Mac distributed package if it doesn't have that class It'll actually go to Rinda and find the first instance of that service running for you So now I know you're probably saying okay What if I had two news items and two different services you can use a retrieve method that allows you to ask for very specific one But some would also argue this probably poor planning on your part if you have objects or name the exact same thing So okay, so what happens when we actually run? Dot all off of it Well there we go you could see the server it called selected basically selected all of our news items off of our server And now on our bottom here it gave us a nice big stack You know nice big inspect and the inspect actually gives you the DRB inspect as well as the inspect of the actual Model itself so there we go So we've called the class level method off of an object that we don't even have and We've done it by adding one line of code in our client and a couple configurations in our in our server So now off of that We can we can get you know the very first news item object As we will do here and slow typing we've printed it out We're gonna print off the title of it and we're ever in we're interacting with this as if it was a Local object and you can see the server is doing all of our database work for us So the client isn't doing any of this database work, which is which is really nice again if you're trying to offload that processing We can do you know we'll here. We'll update the title and Send that back to the server to save it back to the database. So I say hi there RubyConf Which is great. We save it and again. You see it does the update in the very top of the screen Again, this is really easy to use and I'll tell you a programming we've been programming this for for you know months now and It is just it's really fun to program with and to use Okay, so if we take a look at our controller on our client sites We're gonna build a little page that just lists out our news items Very simply in our in our client and then we're going to link them back to the news application itself The two things in particular you want to look at is this layout line where we're saying okay We want to use a distributed layout from the news application from the news app And we're gonna use the application layout so when the layout gets registered with Rinda It uses the name of that file as as it's a as this registration. So application on html. ERB becomes application So it's a very simple URI pattern everybody's familiar with it That's why we decided to go with it very clearly says you're looking for distributed Gives you the host and give it a service you want off of that then in our index action again We're doing that news item dot all that's it. We're signing it to an instance variable It's it's ready to go in our view here We're gonna zoom in a little bit here in our view and we're gonna show you what a distributed route looks like So here we go so we're saying the distributed URL and we want to get that off of the news application the news app and the URL we Want is news items show URL and we're in that that URL takes some parameters So we can give it an optional hash at the end And that's actually going to build our link back to the news item So here's what our our server looks like you see it's not very exciting and But it's got you know, it's got a nice layout on it. It's got print a bunch of stuff now if we go to our client All right, this is the client. We've just built you can see we've got the distributed layout around the top of it I came from the news app then you can see we have the client app in the middle and then a couple links that we built back to the main application and If we actually click those links you see it goes from port 4,000 to port 3,000 and takes us to the news item What's really nice now is if the news item URL changes under the covers We can actually just we don't have to do anything to our client application now So if the news item, you know, they decide that news item is no longer be slash news item slash one It's going to be slash article slash one The server changes that it re registers its routes back to Rinda our client application remains unchanged The big you know the big thing there is you just obviously don't change the the name of your named route If you change the name of your named route, then you're going to have to go through and change that So that's it. So it's a little I thought I would open this up for questions Because there's a lot kind of going on here and obviously I can show you some more But that's it. Are there are there questions? There must be. Yes When I talk about portal like applications, yeah, that's a great question. So portal like applications The way I I've always seen them our applications that contain other mini applications And this is I think it was the original goal of rails components to do something like that And I think it's kind of the goal of murb slices. I don't think either of them really gets sketchy where you need to be Mac has a new feature that came out in 08 one I think called portlets and Portlets allow you to build and it's another way of kind of distributing your code actually So it actually kind of works in well with the whole talk here Portlets allow you to build a Mac application a regular Mac application. It's standalone. You can fire it up. You can test it There's zero zero miss zero a specialness about this application When you're done with it and you want to distribute that application you run a rake task It builds a gem for you and you can distribute that gem and include it into your other Mac applications in that gem Though it also bundles up not only your controller code and your model code and your lib code It'll package up your plugins your the gems that you're requiring your assets or all your images your views your layouts your JavaScript files Your PDFs your media your routing your configurations They all get bundled in together for you and you don't have to do a damn thing you plug it into your next Mac application It has it if you don't like, you know, there's one that you can find on my github page Which I probably should put up here and get to it to the Mac framework calm But I'm working on one called user off-portlet Which is you know basic, you know restful authentication like like like like like gem And if you you plug it in and you don't have to do any running generators or unpack the gem if you you know if you Don't want to you start it up and boom you have registration You have user management people can edit their passwords upload a file photo themselves What have you it's all there ready to go and if you don't like the registration page Well, you just simply override that one view and so it always looks locally and then kind of goes goes through your portlets So that's what when I talk about portlet like applications I mean being able to bundle up applications into many applications and then either embed them Into your applications or be able to access them through other applications and one of the features Mac has is a render URL Method so you can re-render text render action render all those sorts of things You can also do render URL and if it's a local URL so it doesn't doesn't contain a scheme a scheme or a host It'll actually do a call internally and render that render whatever that action is Into that page or wherever you're rendering it if an external one will actually do a call out and come back in so it's very easy To write portlets to to work with other applications And bring them back in so does that answer your question? Great great other questions in the back. Yes Is Apporting the Mac distributed package to other frameworks like rails and Merb the answer is yes and no Like I said, we started on rails and I was we were hoping to stay on rails because that's what our framework That's what we were using And the rails system on the covers and rails code on the covers is extremely complicated We could definitely port some of this Certainly, you know probably two-thirds of it The routing aspects I think would cause the most problems It'd be easier to do in Merb because their API is a lot cleaner and at the time when we were looking to do something I wasn't originally looking to build a framework it just kind of happened and Merb was definitely on that short list originally, but it was a much different framework then than it is today This was back in February So it could be ported and I have thought about it. Yeah, but right now obviously I'm a big fan of Mac So I gotta give it some edge right does that it does that answer your question? Great Yes, so let's say you have a database server and an app server and for now they both know about the object So when you send a request over the database server, it gets run there. Now. Let's say they don't don't don't both know But so you get a user using a proxy object, right? That means when you perform a computation over here the data has to come across to be processed correct? Do you know of anything? where This guy doesn't know about that object, but somehow gets magically shipped to code So that the all the processing first on that side you know you start out with proxy, okay? So the question if I understand it is you have a server and a client the server has as a has a as a specific Class in it the client doesn't and you want to know is there a way that? The client can actually get that full class definition so it can run it locally versus run it on the the server The answer that off the top of my head it well off of the experience. I've had when I originally started building this was no and at the very first implementation of the the route of the distributed routes for Mac was it was definitely a hack and Because I you know I couldn't I didn't find the DRB undumped thing until like the next release Which helps solve a lot of our problems, but it was basically to package up a string send it down the pipe Evaluate into the class and then then you have the class definition local. It's not the best It's certainly not the best approach, and I hope I hope somebody comes up for the better approach Definitely definitely does that answer? Awesome great questions No one has any questions about distributed programming you yes Right Okay, so your question is Is there a way to basically run multiple ring servers so that if one fails and the answer is yes You can fire up as many ring servers as you want Yes One if one goes down the other one be able to fire up Rinda has has a broadcast list so when you fire up Your sir your client in particular in your client you can say I only want to look for my local ring server I want to look across my network for a ring server and Rinda on the server side also has ACLs so you can actually block Different different ports allowed of the loud different IP addresses and disallowed different IP addresses if you want So there's a lot of security built in there as well, but actually just to that answer your question But to go back to your point real quick because I think one of things you brought up there was scalability in some respects You have you know you're sending a lot of data back and forth, and this is a very important thing to know about distributed programming It only scales to a point And I found that when I was pulling one to ten Instances of you know the news item across right so I pull back ten records of the news item one that wrote one record Negligible you would never notice the time it takes to marshal that object Bring it back crust pipe and on marshal it ten objects same thing a little little performance hit But you never really notice it when I got to a hundred. I think I was getting the two or three times The slowdown simply because of all the marshaling and un-marshalling so you've got to be judicious in your use of the distributed programming You know great examples of this are really just you know if you have services You want to send something over just send it over let it do its thing and just get back a receipt Don't try to get back this giant enormous blob of data And if you need ginormous blobs of data to come back use memcash Use use a user use your database. Don't don't just sit there marshal the objects across across dr. B Because it's gonna slow you down so Questions yes Okay, so the question is how do you deal with a lazy loading of objects? So you have you know a post has many comments and those comments are lazy loaded Well, the answer is it's very simple. It all happens for you It's just like any other method call, you know, so when you call, you know, you know, Mike, you know Come I comment dot my posts dot comments It's gonna call it's gonna call that proxy objects that you've got and it's gonna send back to the server saying I need To call the comments method on this on this object and it's gonna do the work And it's gonna send you back the results So in the case of you have a few of a thousand comments probably not the best architectural choice to do that As I just said as far as scalability is concerned So, you know or or try to load those things all up at once You know and not use lazy loading in that particular case So, you know if using data mappers, it's really easy to do different variants of things depending on what you want. So Questions yes Okay, so the question is how does this impact coupling of the applications and the answer is it impacts it It impacts at the same way I guess as if you didn't if you weren't using the Mac framework It's all about your architecture at the end of the day Our applications were pretty tightly coupled with the exception of some of our more service-based applications You know again, it was more it wasn't a decoupling of the application so that hey I could run, you know this one thing Right run the rating engine on its own and no one never has to be any of the wiser That wasn't the point of what we were trying to do We were really trying to just a couple the development time as well as the processing power needed to do those things But yeah, you could certainly get into a situation where they're very tightly coupled Accidentally with if you're not careful about your architecture Right so the question is how do you how do you deal with testing? With with applications that are distributed like this and the answer we came up with was mocking You know, we knew that our application, you know a particular application needed You know needed to user objects you needed access to user objects What have you so we would just mock that out and not have to not do the remote calls So that's that's how we got around it and it's you know, it's pretty I thought it was a pretty decent way of testing We ended up building gems of all of our mocks You know very simple mock gem that just we can include into all of our applications and just have access to all Those mocks that we may or may not need So It's that question Yes Portlets specifically Migrations and portlets and Distributed applications somewhat right. It's kind of a little there. Well to first answer the first question Migrations get bundled up into portlets And they get run that you know, they get run in the same order as if they were local So again, it's all about naming you had make sure that if you have a zero zero one migration in your portlet And you have a zero zero one migration local that That that we relies on that you might have an issue There is an unpack feature Specifically designed so that in the case of migrations migrations with a big one that always caused me problems So you can unpack just the migrations if you really need to do that But we we use one one big database primarily for the application So everything was under the cover is all talking to the same database But again, you know with portlets, you know, they rely on whatever database you have configured locally So they don't carry their own database configuration over so they use whatever is local So but migrations are there so you can run them And if you're using one database if using active record or data mapper, they both have ways of preventing You know, you're running the same migration twice So even if you have the same portlet the user off portlet in a couple apps, you run the migrations It's not going to we add the user table again So it's already gonna know that migration was run and just skip it. So you yes Built-in notification system There is actually notifiers packaged. That's more for email and XMPP and the like There's nothing currently built in to do that now. So you'd have to if the service has changed Yeah, you'd have to ping back and say hey as the service changed on me and then then then use that service It all depends again all depends on your architecture. Are you cashing? You get service locally once you you know first time you get it You kind of take it down and use it locally the issue that issue came up with routing Right, so we wanted to be able to not have to bring down our client apps if our server app changed its routing So what we actually did was on each request We cashed the routing for that one request so we can hit it n number of times within that request and the next request Come then we actually pull the cashing down again so that was an architecture we chose in order to To make sure that we were getting some benefits of cashing because if you're calling a hundred URLs You know you pointed a hundred different distributed URLs You don't want to have to get those things a hundred times for that one request However, if they change You want to make sure it's using the right ones in the next request So there's a brief moment where someone could change something under the covers and you get built a static You know an out-of-date page, but that was kind of what we did with it. Yes So the question was can you use the distributed portions of this in a non web application the answer is yes and no the answer is It uses the Mac distributed gem uses that definitely hooks into parts of Mac So it would have to be a Mac based application. However, you don't have to use it as a web Application, but then you get all the other good stuff that comes with a Mac application as well So that answer your question great question. I saw another hand up somewhere. Yes Starts using it to parcel out So the question is if you have an existing rails application and you want to start introducing Mac applications And is there an easy way to start migrating that rails app one over it one at a time? If the if the if the answer you're looking for is there's a rake task Then the answer is no unfortunately But Mac and rails are similar enough in their structure that you would do it You could do some cut and paste and do some tweaking to get that So you still have your Answer is that that's a very similar question the question again is I want to use Objects for my rails application in my Mac application in a distributed way. Can I do that and that that's a question, right? Okay, good. I just want to make sure I have the question right and again The answer is is yes and no The Mac distributed package itself can't just easily be plugged into rails Because it relies on some Mac stuff So you won't be you won't have the quick right out of the gate boom I can use rails and Mac interchangeably You could very easily Port part portions of the Mac gem the Mac distributed gem over to your rails app and do that It's certainly something I've considered doing at least for again, you know two of the three parts and particularly just the the object part I think just being able to share do the object part be very very useful To people so it's definitely something I've thought about but you could you could do it. It's not a whole lot of code It's not a lot of code at all. So I'm sad answer your question great any other questions. I don't know how we're doing for time I think we're almost out of time anyway, so yes Is there any issues to use this with JRuby JRuby I was actually working on it the other day I'm down to 20 our spec bugs on the 19 of them seem to be the same thing So I'm pretty close and that's going to be in the next release. Hopefully in a few weeks So yeah, I'm looking to use JRuby in the next next job I'm working in so I definitely want to be able to use Mac. So it's high on my priority list. Definitely Definitely any other questions Well, great. Thank you very much for your time. I appreciate it