Best Practices for CAP Node.js Apps

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
good morning good afternoon good evening sounds like a start two hands on a cp it does dev doesn't it so welcome to devtoberfest week two uh bright and early on a monday morning here in uh in western europe uh thank you all so much for joining i can see we got uh lots of oh we just hit 100 viewers uh lots and lots of viewers uh already and you know no no no question why we have an amazing uh guest to talk to you today uh right next to me in fact you can see him as well it's uh david say hi david hi everybody so this is david klintz and david works in the cap team uh at sap and uh is one of my heroes and i'm i'm gonna say that out loud even though while he's next to me oh i don't know which is which way this way or this way i don't know but seriously david is one of my all-time heroes um the things he does in the team but also uh you know outside as well uh is pretty pretty incredible in fact i've got if you've not uh aware of david's youtube channel he does all sorts of awesome stuff um i've got here uh the url you should go right now before we start and subscribe to david because it's absolutely awesome content i'm learning so much from david and we're all gonna learn a lot from david as well because uh yeah we're going to talk about uh cap node.js best practices this is the best practices week of devtoberfest and uh yeah david's kicking us off so over to you david maybe say you can say a little bit about yourself as well and then i'll let you just share your screen and you know go for it thank you very much for this uh very nice introduction dj so let me share my screen i'm david i'm one of the developers of the cab nodejs runtime stack and yeah i've been at cab for i think is it a few years now and yeah i really enjoy working at carpets it's great and it's a lot of fun and i'm not only developing cap node.js but i'm also processing a lot of issues uh internal as well as external stakeholders have so maybe you've already been in contact with me in one way or the other and based on these issues there are also always some common mistakes people people usually do and in this talk i want to address them and show you how to fix them in the first place so they don't arise and so i will concentrate on the cap nodejs runtime stack that is the sap cloud application programming model in the nodejs flavor so i'm not going to talk about domain modeling or cds modeling which is also an important aspect in creating an app but mainly about the node.js runtime stack so the content which i'm going to present you today is sometimes a generic with respect to node.js sometimes it's specific to cup so for example dependency management and error handling is very generic it doesn't have to do anything with cup but the rest is all tough we go from transaction handling to database pool configuration to logging to generic handlers to environment configuration testing and also my favorite part the wrapper so let's get started so the first issue which comes quite often is suddenly my app stopped working in production because of some updates and when i look at the configuration of the project it's always something like this in your package.json file you have a dependency at sap cds latest and there's no package lock json whatsoever and the reason why this is bad is that npm install determines the version based on the npm registry and if you execute npm install at one point in time the versions could differ to an npm install at a later stage in time for example when you deploy to production so there might be surprises and the solution to fix this problem is to manage your dependencies and this is one thing which is uh great about microservices is that you are in control of your dependencies there's no single central system where all the versions are fixed you can actually choose and pick the version you like so you should always manage your dependencies and one way to do this is to use a file called package lock json so we want you to stay up to date but we also don't want you to break your productive app and this package lock json works like this when you run an npm install it will automatically create a file called package lock json and all the versions which you use during that npm install will be stored there and it freezes the versions that means the next time you run an npm install again it will install the exact same versions so there will be no surprises and you have a deterministic build you should always commit this file to your github repository to your git sorry git repository that means when you push your app to production you also push the package lock json to production and the npm installation process on your on cloud foundry for example will use the exact same versions which you use to develop and test your application so there should not be any surprises and once you have this package log json and you want to manually update you can run the commands npm outdated to show a list of outdated packages as well as npm update to then trigger this update process and what we recommend you doing is that you write the following in your package package json file sap cds carrot 540 and we adhere to semantic versioning that means we have here three numbers separated by digits uh separate by by points and the first number is the major version the next one the minor version and the patch version and with this carrot you automatically upgrade the miner and the patch version and with the tilde operator you automatically update the patch version so let's look at this in an example dependency management so i have here my package.json file and in line 9 you can see that i'm using at sap cds with carrot500 that means update this and this automatically now i already installed the packages some time ago and if i want to see if there are any outdated packages i run npm outdated and you can see that my current version is 506 and my wanted version is 553 so now i can run npm update to update my dependencies and the versions are stored in this packagelog.json file you should never look into it because it's quite lengthy but here you can see all the versions installed in this npm install process so they are they're fixed and there are no surprises okay let's go to your next issue sometimes my app behaves in a very unexpected way and this is quite a a common generic issue and this usually has to do something with error handling also not very cup specific but more knowledge as specific if i look at the code i sometimes see things like this so it's a function pay customers it takes a customer's object and then for each of those customers it sets the payments paid property to true and for whatever reason sometimes people write try catch around it to catch for errors which could occur and this is usually a bad practice and there was also a scientific paper once which analyzed bugs in production with respect to how much code you put between a try and the catch block and they found out the mod code you put between a trying to catch block um the more boxed in production you actually have so we should reduce this and the reason why this is extremely problematic is just imagine that you have a customers array so the for each method is there but the fifth customer of that array doesn't have a payments property then all the customers before they got paid the fifth one will raise an error and all the others don't get paid afterwards so that's really bad and the only thing you see is some console output which you don't look at it and you don't look at it anyway so this is this is fab so the reason why this is bad is that also programming errors are caught and you should never never catch programming errors they need to be fixed so they need to be fixed and for unknown programming errors the app must crash fail loudly and then fix and i come to that point also later so um the way you should do it is kind of like this and it totally depends on your code so for example if you know that customers is always an array then you always know that there will be a for each method you should know the data structures in your code base and if you know that some customers don't have a payments property then just do an if check but don't use try catch around it that also means don't program in a too defensive way so the same function i could have written with additional checks for example to check if this is an array or if c is defined and so on and it always depends on your code base how far you should go don't go too far don't create too many checks because as you can see it becomes quite unreadable at some point in time and always handle operational errors so let's just say you have here an express handler and you execute some http request that means an external system is involved and whenever you have external systems or user input or whatever um things outside your program then they will always go wrong at some point in time there's not a single external system which is available all the time maybe the connection is broken or anything like that so always make sure to handle those errors in this case um this function could throw in if the system is not available and you have to to catch this error there's no other way to to do it if if this function throws sometimes you also get the status of the response then you can check that one but if this functions throws then you have to catch it then you can log it and send status 502 bad gateway for example by the way caps remote service api does this automatically so if you use cap and you have here a handler to read books and you take an external service and run this query on it and we find out that this external service is not there then we automatically um return that gateway so you don't have to deal with it income so let's go to the next issue after some point in time my app stops working properly and this also has to do with error handling and if i look at the code i sometimes see things like that this is the express middleware to catch all errors that means you catch and you can see it because it has four arguments here error being the first one and in this way you catch all errors which happen during runtime and just send a status 500 to the caller which sounds reasonable at first glance but the problem is that all arrows are caught that means you are also catching unex unexpected errors programming errors which you should not catch and the better way to deal with this problem is to let your app crash when there are unexpected errors you always have a supervisor which will restart the app automatically you should you should not leave it in a zombie state because there might be side effects so in principle one can think that it's safe because an application is stateless that means you can interchangeably use different instances of your of your same app and everybody can handle your requests in the same way there's no state start but the truth is that sometimes the state is start if you cache something or things like that and if you have programming errors then all things can happen and there were many people who tried to recover the app um to not restart the app to to somehow catch the the errors and continue but it all failed and in the end the javascript community i think they they they all say the same thing crash your app there's a programming language called erlang which has a quite sophisticated error handling approach they have uh supervisor tree trees to to [Music] to recover uh some parts of the application which would crash when there is an error javascript unfortunately does not have this but at least we can reboot the whole app and usually you have several instances of it anyway so you will not have a downtime so when there are unexpected errors crash fail loudly so you can actually get notified fix it and that's the way to go the safest way to go the cab server also crashes when there are programming errors so we we have some central error handler but we always check that if it's one of those arrows type error reference error syntax error and so on that we always crash the server no matter what so the next issue there's an error in my app but i can't find the root cause this is very common and very annoying if you're a issue processor and you have to find the root cause then sometimes you see something like this you get a stack trace with some error happened quite generic and you don't know what actually happened at some main function at some irrelevant location chairs line three column nine and then you look at the code and it's something like this so a try catch block around some function which might throw and then there's just some error some error happened which doesn't tell you anything and then you you look at it and you have no idea what actually happened um so the error information is lost when you re-throw the error and that's a bad thing what you should do instead is not lose this information when you re-throw errors so how can we fix it we can just throw the new error as before but we can attach using object assign some new property causing cos where we store the original error of this uh of this problem and if we do that then we can see a stack trace like this error some error happened at a relevant location this is the same as before but then we also have this course property the original arrow at the important function at the important location and then we can actually find out what what went wrong so this is super easy to do super important for error handling uh fun fact there's also a new feature in v8 the javascript engine which powers node as well as chrome and in version 9.3 there's a new syntax for things like that or not syntax but a new new way to do things like that you can just write thrown your error some error happened and then provide the second argument where you can provide the course so apparently the notes as folks they found out that this is super important so that they implemented it in the in the standard next issue and now let's uh come to the more cup specific things after this is a very common issue after the first request my app doesn't respond anymore so that means the first request is fine data is loaded but then the next request doesn't return anything and then i look at the code and usually it's something like this you have a cup handler service on read books you take the request you write cds.tx brackets dot run select from books it looks correct at the first glance but there's something missing as a in the argument of this tx function you don't provide the request object and the reason why this is bad is because cds tx without any arguments starts a new unmanaged transaction which you have to commit and rollback manually so the solution is to bind your transaction to the request so it works like this the same code but here you provide the original request object and what happens is that once you do this it's linked to the request because our database operation they always start with begin and they must end with a commit if everything is fine or roll back if some error happened in sqlite there are no parallel transactions so you could have a deadlock if one transaction is not committed and the other one wants to create a new transaction it will wait until the first one is committed if the commit never happens you have a deadlock and the server hangs now if you write cds tx rack then we link the live type lifecycle of the transaction to the lifecycle of the request and once the request is succeeded we automatically perform a commit or rollback so it kind of works like this in a simplified way you have your request start then during the request at some point you have some database interaction then we automatically send a begin and then we immediately register handlers for the succeeded or failed event of the request and if it succeeded we perform a rollback if it's failed we if it succeeded we perform a commit if it's failed we perform a role back and then we execute the actual database statement and once the request is succeeded or failed then we emit succeeded or failed to execute those those handlers and because this is such an important issue i want to show that in an example transactions so here i have my cat service and i have the same handler i've shown you before without providing the rack object in in this handler so if i run this um i run this application [Music] and i go to localhost you can see the data is coming so it looks fine but now if i refresh it you can see the spinner here that the server hangs nothing happens and this is the usual thing you would see and whenever this happens whenever your server hangs what you should do is you should enable debugging to actually see what's going on so what we can do is we can set the debug variable the debug environment variable to sqlite for example and if we run our app again we can see all database database statements so you can see for example during the bootstrapping some insertion of test data and you always see begin commit begin commit if there's a commit missing then something's wrong so if we send this request again you can see a begin but there's no commit because this is a manual manually handled transaction and there's no auto commit so let's see what happens if we provide the request object and do the same thing again now you can see begin commit and this is how it should be now if i refresh my page everything works fine begin commit so this is super important so a very related issue is after the first request to my express handler my app doesn't respond anymore so this looks exactly the same thing you have here some express middleware um sometimes it's needed for you to to have some express handlers instead of cup handlers and you also do something similar you write cdstx rack run select from books and one could say that okay you provide the request object so the transaction is managed everything's fine the problem is it's not because the request object of express is not the request object of cup these are different things and you cannot use them interchangeably so once you you're in express you have to use your own transaction and manage them on your own so way to do this is to write constitx equals to cdstx to create a new manually handled transaction then you can run your statements and then you can await commit commit or in case of errors you can roll back and um here when you catch errors you also need to make sure in principle to not catch programming errors so you can check that but i i didn't put that for simplicity there's also in the newest version another syntax to do this which is a bit simpler so in your cds tx function you can also provide a function a callback function which provides gives you the tx object and then you can just run tx run select from books return this as your result and if there are errors then we roll back if everything's fine we perform the commit automatically so this is also a way you can you can do it another issue um which is quite common uh that background database operations have a strange behavior so background database operations are usually something like this you have your cup handler on read books where you want to perform some background task which is an asynchronous function doing some database stuff but you deliberately don't want to await the this function because you're not interested in whether or not there are errors or there are there's a result or anything you just want to return your next the result of your next handler as soon as possible because the the user maybe is not interested in it at all so you don't write a weight but the problem with this approach is that uh sorry i i forgot one thing um async local storage because to understand this issue you first have to understand async local storage and this is something which i really like it's a a node feature node.js feature which not many people know but which is super useful so that's why i dedicated a section to it so instead of joining the transaction to the request object manually like like here cdstx rack you can also just write select from books and return this so select from books is actually a cqn object an object representing the query but if you await this uh this object then we execute it and we will look at the corresponding transaction to join it to that transaction and it's a bit like magic because we don't provide any rack object here so how how does it work how does how does the cup framework know which transaction to use which tenant to use which locate to use and so on and the reason is that we store the current transaction or the information about the current transaction in a property called cds context and cds cds is a global object so you would think that context is also a global object but it's not a global variable it's local with respect to the async context in and in order for you to understand how this is possible i provided another example async local storage and this again is completely unrelated to cup but we use it inside car so we require the package async hooks which you automatically have so you don't need to install anything and there's something which is called async local storage and it's a it's a very magical magical class so we can create a new storage object using this thingy and store it here in this scope [Music] to which both functions here have access to so it's kind of a global variable and let's just assume for a second that this is just a normal global variable um we define two functions and we run first the first one and then the second one so if i run function one then i run this run function on the storage object and this sets the store to value one okay and then i sleep and because i don't await this function call function2 is executed which sets the storage to the store to value two and then prints the store and once this sleeping is done function one prints the store so if this would be a normal global variable what would happen is this stop would set to value one then the star would would be set to value two would be printed and then printed again so we would expect value to value two but because this is not just a global object um this is not happening so let's run this and you can see value one value two so this function did not override uh this uh this this this value because this storage is local with respect to the continuation and here you have a different continuation than here and that's why you have different values super useful which we also use inside of the inside of car so let's go back to this background task now you also understand a little bit why this might be problematic because if you just run this uh background task then we see that you await a sql and object that means we know because of this continuation which transaction to use to join it to but then you will have nasty race conditions because we use the same transaction as the original request but we don't await the result and that's super nasty so this is really problematic and you will have race conditions so the way to fix this is also to use a new function which we also introduced in one of the latest versions cts spawn so you can do the same thing the same background task but instead of just running it without awaiting it you can just write cds spawn and provide this function here and then we will use an own transaction i'm going to show you that in example for background tasks so here i have my cancer visits exactly the same example and let me also enable sql light debugging i run my application now i trigger this book's end point and you can see that we have here a begin we have a commit so it looks kind of correct but the background task is in the same transaction as your read request to books and this is something we should not do at all it should be completely discharged from it so what we do instead we use cds spawn to to run this background task so let's run this again i refresh and now it's correct now you can see that the original request has one transaction and it's committed everything's fine the result is brought to the user but then in another disjunct transaction we actually do what the background task is doing a lot a lot better and there are no race conditions whatsoever so the next issue some requests fail during high load and there are some potential issues uh which causes for this problem uh one course could be for example that you didn't allocate enough memory for your application and in cloud foundry it's directly correlated to how much cpu you get so the more memory you provide the more cpu you get and that could be a problem that you run out of memory but one common reason is that you configure your pool in a wrong way or in a bad way so what happens in cup is that we have a we when a request comes into the cup server we don't open a new database connection for every request because that would be really slow what we do instead is we we keep a pool of connections and whenever request comes in we just take one connection out of this pool and use that and then give it back to the pool so the next request can can use it and for this pool there are two important options one is acquire timeout minis and one is max acquire timeout millis gives you an option an option to set how long you're allowed to wait to get to acquire a connection out of this pool and if it takes too long we will throw an error and usually this this value is set to belittle and that's why some some requests get i think it's a 503 if i'm not mistaken and the other option you can set is max so make sure this is um that you have enough time to acquire a connection from the pool so set it to whatever is appropriate and the other option is max which is the maximum amount of connections we keep in our pool so unfortunately there's no one-size-fits-all solution so you have to a little bit test how how to adjust these values for your needs it totally depends how much load you have how much memory you have and so on we try to use reasonable defaults for example timeout releases i think one second and max is roughly 100 but adjust it to your needs and you can do a lot with those two options so the way to configure this in your require section you can configure your database in this case kantana and then you can say okay i want to have a connection pool where acquire timeout melees is five seconds and my maximum amount of connections is let's say a thousand all right next issue i can't use kibana to analyze my logs and kibana is a way to monitor the locks in your productive environment and uh usually people write something like this plain sample console lock my custom lock output and the problem with that is that you have no control how it's printed to the console because except if you overwrite the console.log function which you shouldn't do and the better way to deal with it is to use log with a kibana formatter so we provide a function called cds log where you can provide a custom prefix and then you can use this function to let's say write an info message my custom block output and then later on in production you can set features kibana formatter to true and then we structure this output so that key banner actually understands it so let's look at this in example five key banner logger so again we have our cad service as usual and here it's the same thing i just showed you we use cds lock with a custom prefix and then we log in for i am reading books whenever books are read so let me run this application [Music] and you can see once i trigger this endpoint custom i am reading books so so far so good now we can enable the kibana formatter using cds features kibana formatter equals to true and this only has an effect once we are in production so we can set our node environment to production and run it again and now you can see that all this log output is in a structured format and if i run this endpoint again you can see that everything here is i am reading books but it's in a structured way which can be understood by kibana and now you also know why we don't enable this by default because it's just unreadable i i can't i can't read anything here but kibana can and that's the important part okay next issue uh how can i register generic handler handlers for all services so that's also something which comes up occasionally that uh usually if you want to um register custom handlers you you create a new file with the same name as your cds file and then you can export a function which takes this service as an argument and then you can register handlers for the service but sometimes you also want to do it generically and the way you can do it is by defining an own implementation of the app service so in your requires section there's this one special section called app dash service and here you can override the default implementation which is used to power all those application services like a catalog service and so on and you can provide an own implementation file and this implementation file could look like this you create a class my app service which extends our usual application service and then you can do whatever you want you can override the init function for example which happens during bootstrap and then you can write a call away super in it and then you can for example register some handler which always runs and always perform some lock output like like like shown before okay so the next issue how can i easily switch my environment so usually you have a debug environment where you are develop environment where you develop your app using local tools sqlite or local messaging and things like that then sometimes you may have a hybrid environment where you run your app locally but connect to the external services in the cloud or you have a productive enviro production environment where everything is in the cloud and sometimes you want to easily switch that and the good thing about cap is that we have profiles which allows you exactly to to do that so here's a one very trivial example in your cds require section you can always have sections which begin and end with a bracket here and inside this fraction bracket you can provide the profile name in this case production and what it does is if the environment is set to production it will take the stuff which is written under it and move it one one thing up overwriting whatever you put them and this way you can easily change your configuration based on some conditions which is which is a great way so to actually choose profiles you can set environment variables uh for example to go to production as it's done in cloud foundry or you can use dash dash profile for various commands for example cdsm to look at the environment profile or cds run dash dash profile and i'm going to show you that in in this example here example 6 environment so here i have a package.json file and i have here a require section and what i want for example in i always want sqlite but in production i want hana or in production i also want authentication which i really don't want in during development and regarding messaging during development i want local messaging but in production i want enterprise messaging mqp so um it can be quite sophisticated you know many different profiles many different ways to override stuff and sometimes you're just interested in in what is my effective configuration so for this you can just write cdsm and this will print the effective configuration and it's quite a big list of many entries and you can also write cds and get and then whatever you're interested in for example requires messaging and then you will only see that you can also grab the list if you want to and to see the effective configuration for a certain profile you can write the same thing but with profile and then let's say production and then you can see it switched from local messaging to enterprise messaging mqp and to run it in a certain profile you can also run your app with profile production for example all right now uh one very important aspect to increase the robustness of your app is to actually test it properly using automated tests and we have a quite new package released in the last version called cds test it's also documented in the last version and it's super simple to use first you create the path to your project so for example you can use a path to join the current directory directory with dot dot to go one directory up and then you just write constitute equals to cds test project and then you have this t object and it's quite cool what you can do with it so you can write simple tests uh this is a simple test with an async function and you can just write a weight t get and then the url of your application and then you get the the result of your of your uh request back and you can inspect for example the data property value and you make sure that it contains id 1 stock 100 title weathering heights and i want to show you that in an example so i have here again some bookshop application and i have here a test folder with some sample test and here i do the same thing which i i've just shown you i uh write constitute equals to cds test and then the path to my project then i create a chess test in this case you can also use mocha if you want to and then we write a way to get catalog books and we make sure that it contains the book with id1 then we delete the book with id1 we perform a get request again and then we expect that it does not contain the book id with id1 and then we create a new book we send a post request to catalog books with this new book send the get request again and then we make sure that it's in this list of books so to run it you can for example use chest and it will bootstrap this whole application including all the test data which you provided in your csv files run the tests and you can see it passed and the last issue which is not really an issue but just a hint is to use the wrapper which i really like and it's just a nice way to play around play around with all the cup apis and javascript is a dynamic language and it has a great support for for the wrapper so we should make use for it so we can just write cds rebel in this directory and now you're in the wrapper and what you can also do for example you can write cons t equals to cds test [Music] for this root directory which bootstraps again this this application and now you can actually interactively deal with your running cap application you can for example await t get catalog books and you can get the result of your books you can also connect to your services for example cons srv is a weight cds connect to my catalog service now you have the service and now you can also run some queries for example wait um so we run select from books and you get the result of your books you can also create a secret statement and secret objects using our query api and you can inspect how [Music] we represent queries using our cqn object for example that's also a nice way to inspect it and with that i thank you very much for your attention and i'm open for any questions you might have thank you amazing thank you thank you so much david um do you want to uh please unshare your screen so we can get both of you and me back on the on the zoom which then comes through to the youtube uh davey that was awesome that was absolutely um you know i'm supposed to be the host uh and you know managing the chat and uh but i was just concentrating on what you were saying uh to be honest um two three things come to mind immediately i've written down i've written down loads of notes um some some of the questions here but first of all may i commend you on what a wonderful development environment you have thank you i'm a big fan and again i'll post a link to your youtube channel which talks a lot about that stuff um you know and more right uh i i uh this is one of those videos where you know it's on youtube and therefore we can watch it back the same url you know we all know how live streams and then replays work i'm going to watch that back and pause and watch it back on slow speed because there's so so many gems in there but for me you did save the best to last uh the rebel as a concept generally is just absolutely awesome as uh as you agree i know uh and um i played with the rebel but i've never really got that far so this is a perfect opportunity for me and for all of us to uh to sort of embrace that and especially in the context of this new cds test which you know is an ideal sort of thing to run within within this so um i mean you may or may not have the chat up there you might see but everybody's saying great sessions super nice tips great job etc i'll i'll let you watch that and uh get embarrassed because you know we all think you're awesome um so i've taken some i've written down some glasses i've written down some questions or some comments and also folks if you're watching now while i'm reading this you know if anything else appears that occurs to you ah ivona has said great session from my colleague david um you know just put it in the chat now um so uh yeah mark mark teichmann was talking about um uh getting build errors with uh with mpo when you include package like i think i think gregor and maybe it was uh tobias as well um i think addressed that but i think it i think it was a super important point as well package lock.json um was always one of those files like what is it do i commit it to get do i not commit it to git so i think you've answered that question very nicely thomas right yeah exactly absolutely commit this file if you don't commit it then and you use some dynamic version in your package json then you will be always surprised in production this is something you don't want to be it's funny because um it goes it goes also into the next point you made which was um about fail embrace failure fail fast you know don't catch programming errors i mean who thought we were going to get that on a slide on a monday morning in a best practices week but i think the way you expressed it and the way you explained it it's clear to me that you want things to be ironed out and you want things to fail so that you know in a in a micro service cloud native environment you know you're not building up uh you know error debt right yeah exactly it's it's a bit counterintuitive right um usually one you should strive for is to keep the app running at all costs you know to handle requests as many as you can but in this case it can be quite dangerous and there were many people who tried to recover somehow from unexpected errors but they all gave up and the best thing you can do is to just let it crash i there there were countless and numerous discussions which i had with colleagues with internal and external stakeholders and yeah the best way to crash your app even if it sounds crash crush your app you heard it amazing amazing um so uh somebody was saying ak was saying i think he's his uh client got a bit funny when a bit funny and repeated stuff but um you know he and i think many others would love to see a full web uh you know uh uh course on cap now i've pointed to the uh cap course on open sap uh but you know we're sending good vibes your way david you know feed them back into the team you know whatever you can do would be awesome right and yvonne is on there as well so uh ivona are you listening uh brilliant um so uh there's a question just here and also i wrote down here somebody said will david make the code examples available and also the slides is that something you can do throughout you know if you make them available through me i'll share them on the uh absolutely on the github page for this week that's where they'll be uh brilliant thank you yeah also um the async local storage that you said that was quite a new feature and that was a node.js feature not a capture correct yeah yeah yeah it's kind of kind of new um i think it was released in uh so it was in the experimental phase for a long time but i think in note 12 it was the first time that it went stable and it's it's a great features uh it uses async hooks under under the hood it's uh quite interesting to to dig into it and i also created a uh a youtube video on my channel uh discussing that feature to make it in fact i yeah i'm gonna i'm gonna get the uh get the channel again in a minute one second yeah i'll paste it in um oh yeah i i personally found i've used profiles a little bit but i think your slot on that was super informative because i think many people out there might be wondering you know what this what is this weird thing in square brackets and it doesn't look right in my brain where you've got a kind and then a kind in a child it's like what's going on so that was a great explanation right yeah profiles are awesome i mean uh you always have to switch environments and that's the way to do it in carbon which which i really like i really like this feature yeah yeah one more i think one more thing um i think somebody might have answered this i'm not sure i'm sure i saw somebody say this but uh vladimir's was saying when you were talking about cds test um and the new there was new facilities there vladimir's were saying you know can you use different user roles when testing uh different what sorry user roles user roles uh that is a good question and yes you can do that um i think to be a set um eeg cds.user.default equals cds.user.privileged yes um so uh two things so first of all for uh using cds test it allows you to send requests to your running application so whatever you can do with http you can do in cds test so you can use for example a basic authorization to um to set some user up uh which we do also internally in our internal tests but you can also use the cds apis directly you can for example use srv.run select from books you can also execute things like that in cds test you can also run your handlers in cds test and for this you can also set users and we have some new transaction apis i showed some of them cds spawn i showed so you could use for example cds spawn to also set a user um cdspawn takes another argument let me show you that i i'm not sharing anymore but thank you okay i shall be quick [Music] so let me just uh write it here real quick so you can use cds spawn to run some some function for example a way to select from books and if you want this to have a certain user you can use another uh parameter for this spawn function where you can provide the user oh yeah new cds user privilege i think it's something like this i'm not right something like that yeah yeah and you can also provide the tenant uh the tenant id uh in this object so that's also something which we improved in our recent version that we make it as difficult as possible to mess up your tenant isolation so if you don't provide the tenant here then we use the tenant of the original request which is uh super important for tenant installation definitely got you okay thank you david so okay i think uh one more i'll say i can see some questions in the chat so i'll come to those in a second i'll make sure um what i mean this is this is maybe less a question for you david um uh i know we've owners on uh i don't want to sort of put the owner on the spot but there's there were some comments about the cds documentation as well um i think it was mark that said that um he finds it quite difficult to find what he's looking for maybe we'll take that obviously offline and you know figure out what that is but also somebody somebody said that when they're doing a search they uh you know lots of java results show up as well as node.js i don't know whether this is you know already been discussed in the in the team but uh um you know i just want to say that sort of on the recording so we've got it and we remember it right so that's you know i wouldn't expect you to to answer that unless you want to of course yeah uh there's actually uh one thing um that that's one feature we are discussing so we're not rolling it out whatsoever but uh maybe there will be some global toggle we're discussing it to switch between node.js and java so that means you would one time choose the flavor you want and then don't be bothered with the other one so maybe we can make this work but it would probably solve his problem right you heard it here first look at that what an amazing session so um just just a couple more so semi on and i'm reading this for the first time uh can app service feature help us to create error handlers for all services in our app all together uh yes you can do that um there is this special handler uh to which allows you to register error handlers and you could use app service as a general uh generic service to add this error handler globally so to say for all services and then you would have it yeah fantastic and simeon had another really good sounding question is there any possibilities for inheritance between services you would love to have base service and then add more handlers um yes you can do that uh we have a class-based approach for registering handlers in principle what i showed you before using this class and then you can inherit it and when you inherit it you also get those registered handlers from the original service i mean you've seen it in app service how i did it i have overwritten the init method and in this in overwritten init method i called super a weight super in it and super in it also could in principle register handlers so yeah you can you can build up your your inheritance structure fantastic and i saw just a couple more minutes i saw a question from speeds 77 which gregor wolff has already answered so thank you gregor and thank you everybody for uh being so uh so chatty and uh helpful in the in the conversation so the question was just for those uh wondering the question was uh how to deploy cap to s4hana and the answer is you can't really deploy it to s4hana you know we you you think you need to think in terms of gregor uses the right phrase here this side-by-side approach right exactly yes so the the main use case for cap is not to embed it into above or something that will won't work but you can deploy it on cloud foundry and then use it as a side-by-side extension to talk to s4hana exactly yeah it's very important that you don't pollute as for hana with stuff and it was done in the past way too too often that every extension was inside as for hana or not as far but the predecessors for example and it got bigger bigger bigger and more polluted so uh the the common guideline is if it makes sense don't leave the car clean and use side-by-side extensions next to it absolutely i mean that in itself is a huge best practice right and so very appropriate for this week so one final question from santiago right at the end in the future and i think many of us can answer have a go answering this question uh in the future will it be possible to work with more databases brackets mysql etc right now if you know i'll i'll say right now and i'm sure you know folks in the chat will be shouting hey look at what the community is doing with postgres for example there's some awesome work that you know uh was um showcased in last year's devtoberfest uh on that loads of awesome people working on that stuff but david did you want to say anything extra to that yeah so uh we concentrate on hana and sqlite for local development uh but there is some uh excellent tooling out there for push chris as you just mentioned uh vodka bootsy gigawolf and and and so on and they they did a fantastic job in creating this they did and uh yeah if uh if we want more databases i mean you can write your own client uh i hope in the future it becomes easier to do that there are also some some hiccups in doing this but it's in principle possible but we're working on it to improve it i can't resist one there's there is one more question from a hands-on sap dev regular uh so of course i've got to allow that question uh question from niels in addition to santiago's are there any plans to support more event providers on top of event mesh eg kafka or even some ethereum bridge now i i know that that's possibly a question you might want to answer david yeah we're thinking of uh supporting kafka uh but it's we haven't started uh kafka development yet uh we're just thinking about it so uh i i cannot give a uh a clear statement of course unfortunately but we're at least thinking about it yeah brilliant so i think we're coming to the top of the hour almost i want to give you david a massive massive virtual round of applause i'm not going to clap in front of this microphone uh thank you so much for kicking off uh best practices with such an awesome presentation do you have any last words uh thank you very much for for having me it was uh quite a pleasure i really enjoyed it and uh yeah i i really liked it yeah thank you very much you're very welcome you're more than welcome so uh just as a quick reminder david allin's i'll speak uh later this week we'll put the content um of what you saw uh we'll link it from the devtoberfest week to github repo page and uh an equally massive thanks to everybody for joining uh it's been really great so thank you very much and uh yeah we'll see you for the next session tomorrow morning bye folks yeah bye and we're offline all right david that was
Info
Channel: SAP Developers
Views: 4,333
Rating: undefined out of 5
Keywords: ABAP, Steampunk, Dynpro, ALV, ABAP OO, SAP
Id: WTOOse-Flj8
Channel Id: undefined
Length: 58min 55sec (3535 seconds)
Published: Mon Oct 11 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.