 Hello everyone and my name is Pramod Sadalge and today I'll be talking about evolutionary database design and architecture and I'm based out of Chicago so it's late night for me here but hopefully you are in a good place and ready to listen to this and I work for ThoughtWorks and have written some books as they are shown here but the idea being I want to talk about the concept of evolutionary design. So the first question that generally comes up is why evolutionary? Why do you even care about being evolutionary? So we know the reality is businesses are in a constant change especially true now like maybe 30-40 years ago the business model and the types of business processes changed like maybe once in a decade much more slower change but now businesses are changing much more faster like 2-3 years stuff has to change innovations much has to be much higher rate and that innovation in turn forces your architecture and which in turn forces your database to change. So that's one of the reasons priorities are also constantly changing again businesses are reacting to forces in the market and those forces are also forcing the business to change which in turn changes the priorities and also changes the underlying databases and things like that. The other is also learning and responding to customer needs is critical nowadays like you can't just say I'll come back with a feature in a year or so you have to put a feature out gauge some response from the customer and see how it goes and then respond to that feedback that is coming in and you are learning from that feedback and that becomes critical and at the same time you cannot have the luxury of like having a design phase where we are like just sitting in a box somewhere and doing design but nowadays design has become like a continuous phase like which where it evolves based on feedback evolves based on changing priority and all those things and sometimes making decisions before they are necessary is a waste like you may think I want I want this design I want this features I want all of that stuff and the market goes somewhere else and then all that work you did is basically a waste and then you don't want to get into that situation that's why this evolutionary thing has caught on and people are trying to do that evolutionary design on everything right so as product requirements evolve so does the code as well as the database that supports that code supports the business requirements needs to evolve right and the underlying thing of all of this is dealing with emerging design as design emerges how do you deal with that particular change in the need itself right so the question comes in how do you evolve databases as all of these business things are happening right and there's a classic definition I want to go back to that was done by Martin Fowler way back like maybe early 1999 where he said refactoring is a small change to your source code that improves its design without changing its semantics like without changing its behavior it's improving the design of this thing and to do database refactoring I basically want to add one other factor to this right like my database refactoring again is a small change to your database schema DDL data db code whatever it is which improves its design without changing its semantics but when it comes to database refactoring there's a interesting thing that is different than code refactoring in code refactoring you're only created only responsible for keeping the behavioral semantics at the same but in database refactoring you also have to deal with the informational semantics an example of that would be like in code refactoring you can change the name of the method you can change the things that happens inside the method as long as the method does what it's supposed to do but in databases you can rename the table and all that stuff but you cannot lose the information like if it's a customer table you cannot lose the customer's names and addresses and things like that so that's the informational semantics so both of them have to be maintained for the information and the refactoring to work so a little bit of difference as compared to code refactoring that you have to keep in mind when you are doing a database refactoring so let's talk why it is hard right so database refactoring is really hard because over the period of time we have kind of like stitched our architecture around that database right so sometimes you are working with the database your application maybe your framework maybe your e-commerce platform is working with the database but over a period of time lot of like other applications that you know about there are sometimes applications you don't even know about like someone in the op side has just given somebody a username password and they started like reading from your database there are other places or jobs that are putting data in your databases and there are other databases that are replicating from your database lots of dependencies happening this kind of pattern is also known as database-based integration right like kind of talked about in Gregor Hopper's book enterprise application integration patterns and he talks about how like integrating at this level couples your architecture to the database right so generally what that does is once this coupling is tight it's really hard to break it apart and not just breaking it's even hard to change what's inside your database you don't even want to break you just want to make it better you want to like add more features you want to probably do some changes into the database but it's becomes really difficult because all the other constituents in your enterprise are going to stop you from making the change because they are dependent on the database as it is so then your architecture becomes really brittle right so over like the next five or ten slides I want to explain how you can do your changes without trying to break or without breaking any of these applications of course over a period of time you want to evolve those other applications also to use the new design that you have put in place and that gives you like this evolutionary way of doing changes in a database right so let's talk about those types of changes so generally speaking there are like four types of changes or refactoring and they are structural they could be data quality related they could be architectural or they could be method kind of refactoring transformations are changes that you do to the database that are not necessarily a refactoring but you are adding new things to the database right so that's like that's why we call it a transformation and the way to do this is basically applying the strangler pattern to the database a strangler pattern as defined by Martin Fowler and I think even some other people who are involved in that pattern is basically over a period of time you want to take away some of the functionality from the old legacy code to the new code it could be anything right so you may want to go from a class or a web app that was defined and go somewhere else you may want to break apart a monolith into microservices or you may want to break apart a database all of those are a kind of a strangler pattern right applied different areas of in your architecture so we are applying a strangler pattern to the database also and in the beginning which is during the start you are implementing the refactoring and I call it the expand phase when you're expanding this your database or expanding the refactoring then you have this thing known as a transition period when the old design as well as the new design both are working at the same time right so imagine you had like a deprecated class your deprecated class is also working and your normal class is also working so you have like these two types of things going in parallel at the same time and at some point of time you deprecate like literally delete the old side and what's left is the new side or the new thing right so if you had like two objects definitions of objects or definitions of views for example let's say and you deleted the old view and now what's left is the new view so you are now totally deprecated the old one and people have to use a new version of whatever you have come up with right so that's the way to do this so let's kind of like talk about an example here right so I have this table called customer has three different columns and you think like oh putting like nowadays people are all over the place nobody is like within their own region mobile phones go move from state to state and that kind of stuff so I just want to merge all the phone three phone number related columns all into one because theoretically I just want all of them in one place right so that's what you do you say okay I'm going to introduce a new column here move all the data and that kind of stuff and then basically like at the end what's left is a phone number and a country code right so you could also talk like one of one other example here is I have a first name and a last name and I basically want to convert like make one of those columns not even that's a refactoring you're trying to improve quality of the data by saying at least the first name should be not now you don't want a customer that doesn't have a first name or a last name in your database so like you're saying I want to improve the quality of this by adding certain things right similarly quality wise there's also this oh I want to add a foreign key constraint like the account status has to be there on account you cannot have account without account status so I'm going to add a foreign key to that that's also a quality based constraint that you can do and here's an example of like a architectural constraint refactoring that you can do like there's a customer there's account and there's insurance and you're constantly looking up like joining all three of those tables to get this customer portfolio right like a customer their name and all their like totals of insurance and totals of payments and that kind of stuff you basically create like a read only copy like maybe your view or maybe you do a materialized view like a table that gets populated in at some particular frequency and it's only basically read only but what you're doing is creating an interface for your data so that other people can just read your data without having to know the dependent tables where all this came from and that allows you to improve read performance but the trade-off now is the some data may be stable and that's the architectural concerns that you should be dealing with like is this okay for the business to deal with like if data is tailed by like say five minutes two minutes what is that interval do they really need it real time those are the types of concerns you're dealing with here but here if you introduce this kind of stuff this kind of refactoring what you are doing is giving people an ability to abstract away from the physical tables and that kind of stuff which you can change at your own rate as long as you keep the customer portfolio view or even materialized view consistent with what they're expecting right so that gives you abstraction layer that you can work the other migrate method from database is basically removing code that was in the database like say a stored procedure for example and you want to take it away from there and put it in one of your components or maybe a service or something and the reason to do that would maybe is you want to have some horizontal scalability maybe that get valid policies procedure you want it now to call some rating service you want it to call some policy validity service or something else that is that cannot be called from the database so that stored procedure is cannot do what it's what you wanted to do so you're saying okay let me extract it out of the database so in the before version you have the stored procedure inside the database but in the transition you have it on both sides right like same to it's the exact functionality but it's replicated on both sides allowing the coding and e-service to also use that short procedure but over the period of time you basically extract it out and now coding and e-service can also call the policy administration to get a list of valid policies instead of calling the get valid policies stored procedure in the database right so this way architecturally over a period of time you can move some dependencies or coupling that's happening to the database to a different place allowing you to move components around do some kind of vertical scaling or horizontal scaling or any other type of needs you may have and then at this point I want you to like walk through a expanded contract example like in a very detailed way so that we can see what options are available how you can actually use it and things like that so we are going back to this customer as an example here so we have a customer and a name and you are thinking okay maybe I should like change this first name last name right and you are not like thinking this just because you want to do this refactoring but sometimes there are business needs that come in and they say oh I want to split the customers into first name and last name so that I can do some sorting some other stuff and keep track of like for better master data management and things like that and that's why this split usually happens so in the beginning let's assume we have in the name column we have the name of promote Sadalge like my name and then you say okay I'm going to split this up and then at this in the expand stage I still have a name column which has the data of promote Sadalge and the first name now becomes promote last name becomes Sadalge and when it contracts right like when you are done and all the other dependencies on this particular table have caught up not just your application but all the other dependencies have caught up and probably they are ready to now release you can just say now in the contract phase I want to say first name is promote last name is Sadalge and there is no more the name column right at this point you are done with the refactoring totally and you are there with the new two columns that are available first name and last name and there is no longer a column name name now I'll walk this a little bit more further detail with you to talk about how this can be done right like so you have in the start here have the name equal to promote Sadalge and then you have two options to actually do this right like one is without data migration so you just introduce two columns to this first name last name and there's another option is with data migration and both of these options have like there's a place where you can both use both of them let's say you are not in production yet maybe you are even in only in QA and stuff like that you say okay I'll introduce these two new names and delete the old name and we are all good from now on whatever new data I create it will all use the first name and last name but what about application that are already in production right you can put two columns there and have all of them be nulls right so you have to have some kind of like mechanism to move the data that is the with data migration step that comes in right so in the simple scenario all we are saying is you're basically modifying the customer table adding a first name and last name and you're done right like nothing else to do but a little bit more complicated scenario would be I are adding those two columns and you are also adding a trigger which will basically synchronize like if the if some other application comes in and puts data into the old column the old name column you want to make sure you can split it and basically put the name part of that column into the first name and the last name part of that column into the last name column and if some new application is actually coming in and writing the first name and last name then you want to make sure you merge them together and put them in the name column and the reason to do this is any old application looking for data that was written by the new application right that understands the first and you will still get the data right and at the same time if some new data was put in by the old application the new application that you have modified can still get there so there is no data lag as such or there's no mismatches like saying oh your name was changed to that other application you have to do it again here so that kind of stuff just goes away and you have like all of that data is synchronized right so that's why I call this synchronized data scenario then we can get a little bit more fancy here where you are migrating the data and synchronizing like so we add the columns we update the existing data and then we put a synchronized thing in place so that we have taken care of existing data we take care of future data that is that is being written by the old as well as the new columns and all of that data is all in one place right so this is the expand stage and the transition stage when both old and new are in play and your old and new applications are using their own version of the schema right so at some point in the future especially in a very complicated enterprise architecture this may take maybe a year or two year for everything to roll up and make things better in a not so complicated architecture you can say oh we are like in a month or two months we are all caught up we can just drop this column name and we are all happy right in like e-commerce or maybe 24 7 type of setups the drop itself may take longer than necessary right so you may end up into like log table situations and things like that lots of databases support this like I'll set the unused like set this unused as a name column so it doesn't show up anywhere but it's still there like you have not actually taken it out but it's still there but not visible to anyone right so that that's one other method to like not take any downtime but at the same time have some kind of a method to contract right there's sometimes still somebody may else make a man say hey I was using the name column to extract my data out of this database and send it to like some external party and now you have taken out my name column and I'm left with this first name and last name can you just put the name column back right there's usually like some of these laggard applications that cannot be actually modified maybe you don't even have the source code to modify and things like that so those kinds of requests do come about so what do you do about those right like so you could also add like virtual columns like this like in Oracle in my still it's called generated column and other databases also support this concept of a of generating a virtual column and I call this creating a facade in the database right and it like it's not necessarily true only in a column name like let's say you modify the table name you can add a view that match the old table name to create like a facade on the old table you can do the same thing like using different methods of like giving a facade to the data so that whichever application is coming for data into your database looking for this stuff you can create a facade or interface for them so that they can still get access to the data that they are looking for without having without restraining you from doing the modification that you want to do right so that's that's the important bit to understand here you are providing an interface for consumers that can't really modify themselves but at the same time you are modifying your design you are improving your design and delivering value back to the business without having to stop yourself it gets a little bit more complicated because you have to manage this dual interface or dual facades but at the same time it does let you move forward with the refactoring that you are looking for right so here's the example I was talking about like creating a view like there's a table called cussed order and you think oh this table name doesn't really reflect what it is like using the domain driven design concepts so I'm going to make it like a proper table name but there may be some people who are still coming and looking at cussed order and you say okay we just create a view for that and people can be happy using the view and I'm going to use this customer order table so that I can start putting data in it and that stuff over a period of time you can ask those consumers to use the customer order table instead of the cussed order view and then you can just delete the view after some time when you are contract when in the contract phase right so one other thing you want to also keep track of is the more interfaces and the more facades you create over a period of time you want to make sure you clean them up or else you'll end up in like a situation where there are so many facets you'll kind of get confused in what is a facade what is the interface and what is the actual real stuff behind it so keep track of what you need to clean up as you go so that you end up in a place where it's much more cleaner design wise so that you can you can be more productive in using that this right so let's talk about some things that actually enable you to do refactoring properly right so one is this keeping the old and the new working it basically improves up time and the ability to evolve and it also gives you the facility to take on things that otherwise would not have been allowed in an enterprise like hey that thing is not allowed don't touch that table if 10 of those things happen you can't do much in the database and then we start creating like when people don't allow you to modify database then what we start doing is we start creating side tables that basically have a one-on-one relationship with these things and that over a period of time that design gets so complicated it doesn't perform it doesn't scale and all that stuff kinds of things happen so the ability to modify an existing database is important right so improve the up time as well as the ability to evolve itself you should be in a position to create interfaces in the database right and many a times these interfaces are good to like support some applications that don't necessarily deploy new changes at all like there are many in many companies there are lots of these tools and interfaces or maybe even like libraries that cannot be modified because nobody has the source code and this thing is running for a long time and then we can't do anything about it so for that kind of stuff you should be able to create interfaces in the databases and your databases should be able to handle multiple versions of the application right and there especially this is true when you're doing like red-green deployments or canary deployments as they're called you may also want to do like hot cold kind of like environments where like you're deploying the new code in one place and the old code is available if something goes wrong you want to switch over and that kind of stuff failovers so you're so in those kinds of situations especially like handling old and new power by the database should be like very easy for the application to switch from version to version without having to worry about if the database needs to roll back and that kind of stuff and again like wrapping tables into views to provide a facade is a very good way of allowing older applications to perform similar to like calculated columns to perform to give you a facade using triggers to synchronize data between like tables that were split or columns that were split or merged and things like that and you can think about this this we are thinking about just like when you're deprecating an API or a method right like the old as well as the new both are available at the same time and over a period of time you are deprecating the old permanently like you can't even access that anymore and you are providing a new interface that is going to be there forever right so you can think have the same kind of philosophy even for even inside the database right like it doesn't necessarily have to just at the code level it can be inside the database also and then what is this what kind of guide is there to do a successful refactoring right so generally large refactorings are risky like don't take on too much and it's the same advice as code like if you're core refactoring code generally the advice is don't refactor too much like it should probably be done in a day two days don't be in a place where like you're refactoring for months and then when you try to go back and merge into the main line it's really hard because by that time the main line has changed into many different things sequencing small refactoring so that it can create that large desired change that you want is a good way to go about these refactoring every refactoring should be like inversion control should be like the same script that runs in like dev or ci or qa uat prod performance whatever environment with the same migration script that the developer wrote or the dba wrote in the beginning and generally i advocate that developers and dbs pair together to create this change right when that happens that same change can then move on to different environments right and even if you have changes for data like your reference data changes for example or if someone introduced a bug and then the fix to that bug is basically fix the data then that also can be just a migration that gets introduced into your pipeline right and they should be treated just like any other code so you can like basically check them in when the ci engine runs it uses the same migration script it packages those migration scripts it ships the migration scripts along with the artifact so all of that should be just like you treat code and even those these migrations should be in the same place where your ci scripts are right like you're all of your code base is basically that's where they need to be so let's look at like a journey of like evolutionary design like here are like my 10 of my stories or requirements or gira tickets or whatever you want to call it like so look up a car by a vehicle identification number you want to see the accidents reported against the car you want to look up a truck also now you want to see the cars truck make model whatever you want to look up owners for a car then when the car was first sold so you want to get a little bit of history and you want to look up what type of vehicle it was you want to see the mileage reading or kilometer reading on it and you want to see how the vehicle was used and you want to get a history of owners of this vehicle so those are the sequence in which you are getting stories or tasks and let's see a journey of how the tables we evolve over time like the first time when you get this story you're just say creating a table for a car and basically your owner and that kind of stuff and then you create a foreign key then you add an accident table because you want to see a list of accidents against a car then you are basically adding a unique index on a win because the vehicle identification numbers are unique right and then you go okay let me make it easy on searching at an index on the last name and then you start putting some other stuff because that's what is being looked at and then at some time you were basically changing the cable car to be called a vehicle now you don't want a car table and a truck table so you basically call it a vehicle table and then you add a vehicle type like is it a car or a truck or a tractor or anything else so you basically add that kind of stuff and you also add like a bunch of data to that vehicle type in the drop down if it's showing up in the drop down kind of thing and then you basically remove the owner column from the car table and basically add a joint table that joins the owner and vehicle because it now you are going into the feature where you have multiple owner over a period of time and that kind of features are being added then where is this car right now that you created you are basically creating a view for that table right and then you are saying okay let me basically add more columns to the owner table that's what's happening here and then you basically create a owner type is it a company is it a private owner and things like that now get added and then what happens is you are basically trying to like in the bottom you see here if there are accidents you want to basically create a you renamed it to event and what was the event type was it accident was it like flooded was it any other type of like incident that you want to record against the car so you're calling it to event now and you introduce the concept of an event type so all of this is happening and then when this is happening all of these changes are like a series of requirement changes that happen to the database schema right and you are being these changes were not like you just decided you want to do they are being dictated by the changing requirements as requirements come to you that's how you're designing right because at any point of time the business may say okay we are ready to release to production right so your core has to be and your database at the same time has to be ready to go to production at any point of time and that series of changes are basically nothing but migrations those series of changes are nothing but migration and as we saw before every change is a migration and we saw how to write a migration before so that we can basically take a list of these migrations and we have those all ready to go right but without good development practices and patterns using and implementing evolutionary design is difficult right so what are those practices that make like any like even in code side if you want to do TDD and all of these there are all practices that support evolutionary design and similarly even in the database evolutionary design is supported by some good practices right like test the behavior of the database for example like objects in code databases also have behavior so you can develop some tests around that behavior so I'll just show you an example here's an example of that says like okay you should not do save duplicate win cards yeah I don't want to save any model years that are 20, 10 or under so if I try to save a 2004 model it should fail like should not basically say it should not save when the model name is null for example and a bunch of that kind of stuff like I don't want cars in here that are less than 12,000 miles and that kind of stuff or more than 12,000 miles 10,000 miles so this table definition basically will make all those tests pass right so now the behavior in the database is encoded in a test and what this gives you the power to do is now you can say okay my definition or the function of my vehicle table I am expecting certain features from this table right so it should not accept duplicate wins that's a requirement you're saying the vehicle table should support similarly you're saying a bunch of things like name cannot be null again that's a requirement you're putting on the vehicle table all of those can be exercised using a test a test that runs automatically in your CI cycle so that if someone changes this by mistake or someone changes this because there is a new requirement one of these tests will fail and that will create a conversation point between the developer and the probably the analyst saying okay what why did we change this requirement previous requirements save this we are changing this is there a reason what is the reason that kind of stuff so it introduces that conversation point which is very good to have because you don't want to change these requirements and not know what else is breaking right so imagine if you have this kind of test some other application may actually write a test on your side saying here's my test for your table because I'm using your table and if you change anything in the table their test will break and then that will be a conversation point between your team and their team saying okay I broke your test why are you how are you using this table and maybe tell them to like change their code so these conversation points are really important right and then you can once you have those kinds of tests those kinds of migrations now you can put that migration stuff in a CI cycle right so when you're developing that's where you're writing the migration script that migration script using your build scripts like rake or riddle or ms build or maven or whatever you have is running against your own local copy of the database right and then you can use basically like any kind of source control to basically check that in right that's what you're doing and when the source control receives a new migration script probably along with a bunch of other code that you changed that's talking to the new structure of the database then the CI server basically takes all of that as a package and runs it against the integration database and when that happens your migration scripts your code all your tests all of that run in a pristine environment and gets tested again and then when those tests pass you can just publish your migration scripts as well as code based as one package and whenever that package gets deployed to your qa environment your uit or production or performance whatever environment it gets run again there so the same script is running multiple times so there's no question of will this script run will this application run against this version of the database and things like that so you don't have to you don't have to worry about those kinds of things right so that is like a way to run a ci version of this database ci version against your database migration scripts as well as your code all at the same time right and now what this does is gives you a power to like maintain different versions of the database in different environments you may want more than one qa environment you may want more than one uit or maybe there's a demo environment maybe there's a client test environment or maybe different pairs are working in different versions because somebody is probably fixing bugs into a production code base and somebody else is working on new features everybody gets different versions so that you can work independently of others right so that gives you the power to do that and once you get into this kind of way of working you can now easily deploy frequently right because now you have a script that goes with the code base that can be just deployed at a click of a button and that allows you to deploy frequently and deploying frequently basically reduces the risk right so I show this boat metaphor for a reason is imagine you have this boat going from one shore to the other shore and this boat goes only once in six months then everybody who wants to get from this shore to that shore is going to pile onto that boat right and that introduces all kinds of risks one is over like burdening the boat the weight and all that stuff but at the same time if you don't get onto that boat and the next boat is in six months the fear of waiting for six more months will make business users pile on a bunch of features on you all to be done even if they are not a priority and that kind of stuff so it creates interesting human dynamics that forces you to like even if they don't want it right now they'll ask I want it right now because I don't know when I'll get in the next boat ride right so that's why it creates interesting dynamics on the business side so if you say I'm going to release I'm going to deploy every Thursday for example then the business may be even more relaxed like if I miss this Thursday I'll get the next Thursday's boat and you can make it more interesting by saying I can deploy every day to production that again makes it more interesting to the business saying oh we are deploying every day so they are much more relaxed about not pushing things on the dev team to like release to into the release every six months and then so so especially deploying frequently it's counterintuitive a little bit but deploying frequently actually reduces risk. I have a question here from Rakesh Pai and he is asking like how would you add a unique constraint on a win at a later point in time if constraint didn't exist before and there is possibility of duplicate data in the column right so when this happens what you want to do first is find all the duplicate wins in the data first as an analysis point and then ask the business what do you want to do about this right so the business may say oh these are all duplicate wins and they have the same car that have different owners and then you can say oh I can just move the wins that are duplicate as different owners on the same car and then merge those rows then it becomes just a pure data migration you do that data migration and then add the unique constraint sometimes the business may say oh the duplicate wins but they are different owners I want to represent there's different cars totally then you have to come up with a scheme where you introduce like probably the owner ID also into the uniqueness concept and make the owner plus the win as unique at that particular point of time so the answer here probably has to come from what it needs to be done from the business and then you can you have then various paths to implement that particular refactoring because if the business says oh all the duplicate wins are really duplicates they're just different owners at different point of time then you basically collapse them and add three eight more rows on the owner side and then you have this one too many going between owners and like cars and owners and then you can just add the constraint afterwards if the business says no they are really like different cars I just want to represent them as that then you have to bring in probably the owner into the uniqueness I have another question here from Pradeep Chandran is there a way the DB can recognize which are the applications and interfaces the that access DB similar to any application that can track and know where they are other applications interfaces that are interacting so on the database side you can add some system triggers that can tell you what tables or who is logging in and who is accessing tables and things that information is there but it's not really I would say that granular for you to go back to the because many a times lot of applications are probably sharing the same username password which is a bad practice but sometimes happens similarly like a lot of places also share like they have shared access they have this common username that everyone uses though that kind of stuff you can't really figure out but there are system level triggers that you can put in that can tell you who logged in what time it was logged in what table was created like DDL created and that kind of stuff the thing that you cannot put a trigger against is select statements and that's one of the biggest drawbacks of trying to track this at the database level is that the select statements cannot really be tracked there are techniques to do that also only if you had followed this from before like for example you can create two schemas one schema actually has the tables and the other schema is basically a wrapper including like just views around these tables and within those views then you can have like probably a sequence or something and that only the only thing it can do is basically increment the sequence and tell you okay this table was read and that's about it it cannot really tell you who read it and the reason for that is that level granular level information cannot be extracted out of the database level stuff so generally to solve this kind of problem what I tend to do is basically work at the ORM layer of these things and talk about like okay how can I add this kind of functionality at the ORM layer of course this does not solve the problem of other applications coming to your database and trying to get stuff out of there the way to fix that also is sometimes especially in QA and UAT environments don't try to do this in production environments is to see what all connections are coming in and probably sometimes you can change the IP address of the server or you can change the password of the server and see what fits that's a good way to figure out who else is calling your database in a in a fast minute but not recommended for production environments all right on to the next slide that's all I had to say hopefully you got something and I think I'm right on Q here yes yeah so probably be saying challenge is the third party applications so again the code base on which you have no control if they're calling your database directly then you are anyway in a pickle because you can't change your database without the third party application third party people changing their application and that kind of stuff so that's why like database based integration is really tough and it's considered a bad practice in the new microservices landscape because database based integration kind of couples your database to the architecture and over a period of time it's hard to like break it apart it makes your architecture very brittle so generally avoid it and if any third party applications need data from your database best recommendation is to ask them to come via service and you can evolve the service over a period of time and so they don't have access to direct access to your database that's all I had thank you folks