Keep it up! Do not let the bozos get you down!

When answering the question “Why we address system development the MDriven way” we most of the time come back to the fact that it is a great idea to separate the true knowledge of the domain – The Gist – from the fast aging technology choices (Modernity) – and from the even faster changing look-and-feel choices (Fashion). This is contrary to traditional development that mixes it all up with hard to read, non reversible code.

The main protests we get against this argumentation is oddly enough that the true knowledge of the domain (the gist) is so complex so no one can comprehend it. Ok – how to retort to that? If it was true, we can just all lay down and die anyway – if there is no way to understand anything – we should not build any system with any methodology, period.

People touting the idea that “this area is so complex so do not even try, you will never make it” most often has a clear case of the emperor-has-no-clothes-syndrome, i.e. they make a big bombastic claim and hope that it will not be scrutinized – if it isn’t – they win – otherwise they lose. They will do anything to get acceptance for their claim – everything rides on this single claim  – and debating with people like that is tiresome and probably a waste of time.

Why do they do it? Why do we meet so many seemingly professional business persons that argue that a certain area-of-anything is beyond the grasp of human understanding? Well there is ALWAYS an agenda – they are not really saying that THEY cannot understand the area – they are saying that YOU cannot understand the area – and that YOU cannot describe the area perfectly with an easy to read, transparent, easy to maintain timeless UML-model that executes in an MDriven-environment. That is what they really say. And that is what we see MDriven-developers all over the world prove wrong time and time again.

As NOTHING is beyond comprehension – nothing is beyond declaration – and hence nothing is beyond system supported execution.

Keep it up! Do not let the bozos get you down!

Is MDriven really no-code?

To answer this you really must define “code” first. Luckily I already did that here.

There is no getting away from that someone must understand the problem that is to be managed by a software system.

MDriven raises the level of abstraction so that once you do understand – you are done. The fact that you can refine your understanding indefinitely is another story – but MDriven has you covered here as well.

MDriven also keeps a high level description of your understanding in a timeless non-aging standardized format : UML.

This leads me to claim that MDriven is no-code in an even bigger way than top-brand-no-code-products because all?/most take your understanding of the problem to solve and helps you codify it into their own proprietary format – albeit with visual tools – that then is executed.

None of these tools claim to be a clear description of the problem to solve – they only claim to be a solution for the implementation of a problem you want solved. Hmm a solution codified from your understanding – an understanding you keep in your memory or other documentation. So they are not really no-code, are they?

Doing stuff later

When you have an MDrivenServer you can do a lot of useful things in serverside jobs.

Up until now there has been one common and one fantastic way to trigger serverside jobs:

  1. The common way: Timer/Clock to run a Query periodically to check information criteria’s and start the job for the returned results.
  2. The fantastic way:  Cache invalidation – where the job is analyzed on what members it uses and those member-instances are remembered in a cache manifest. And whenever anything is updated in the system that touches the information used – the server cross reference the manifests and invalidate the exact  caches, whereupon the jobs can be started to update them again. Extremely lean close to the theoretical optimum.

#1 is a simple straightforward robust way to handle things. It will discover objects that meet a criteria by checking regularly.

#2 is the holy grale and solves one of the hardest problems in information technology – but it is not fit for all jobs – since keeping cache manifests  costs resources.

In production systems we rely heavily on serverside jobs for tasks like these:

  1. To assign unique numbers to stuff (the “exclusive access” problem, back in the days this used to be solved with a serializable transaction on database-level )
  2. To communicate with other systems (integration, send data to and receive data from others)
  3. Updating persisted calculated values (the cache problem).
  4. Check some automated step in a state machine or the like and move it forward (the self playing piano problem, or orchestration)

The #1-“exclusive access”-need is possible to solve with timer/clock+information but not ideal since a number should be assigned quickly – and it is not ideal to have a lot of these clock jobs that almost never do anything but must be checked as often as possible.

The #2-integration-need is best solved with a timer/clock+information-based trigger ; “It has passed 10 minutes, do we have the need, then execute”. There is often no other signal to react on other than passage of time.

The #3-cache-need is best solved with Cache Invalidation – so that the system automatically sees when dependent data is changed and reacts accordingly – very lean. But you could use a timer/clock to recalculate the cache ever so often – even though it may not be needed (resource waste, but sadly very common practice).

The #4-orchestration can also be done with timer/clock+information check but again- as in #1 – it is not ideal since they will most of the time – when clock-criteria is fulfilled – not have the information criteria fulfilled and we have done a check in vain.

Every need is addressable with timer/clock+information check – but it is not the most lean way to do tasks of type 1 and 4.

This is why we now introduce a new third way to trigger work on the server – or as we also may call it – asynchronous work.

The SysAsyncTicket

The solution on how to easily spin of any kind of work and to do it later – or async –  is implemented by part model-pattern, part framework support and part MDrivenServer support. That being said it is important that you have versions from 2020-feb-28 or later for this to work as described below.

image

The contract that instructs the system that you want this ability is fulfilled by adding a class that is defined like this:

  • Named SysAsyncTicket
  • Has attribute DeleteTime with DateTime-nullable type. This will be set by the server after your work has executed to Now+KeepReceiptMinutes.
  • Has attribute Done with DateTime-nullable type. This will be set by the server when work is done.
  • Has attribute Error with string (nullable optional) type. If there is an initial issue with the ticket – like if the RootId is not valid, or the ViewModel is not existing you will see this property filled with information.
  • Has attribute ExecuteEarliest with DateTime-nullable type. If you want a delayed start you can set this – but leave to null for the server to execute it as soon as possible.
  • Has attribute KeepReceiptMinutes with Integer type – with an initial value set to your liking. Signals that the auto cleaning of a used ticket should happen X minutes after the job finishes.
  • Has attribute RootId with string (nullable optional) type. This is resolved and set by the framework to the external id that the RootObject association points to. If it points to a yet unsaved object the framework will discover this and set this property after a valid key is retrieved. If this extra pass was needed the framework will automatically resave the SysAsyncTicket with the updated rootid property.
  • Has attribute ViewModel with string (nullable optional) type. This must be a valid name of a ViewModel existing in your model – it does not need to be a serverside-viewmodel. Any rooted-viewmodel will make do. You should use the constants found on the class, ie: ticket.ViewModel:=YourClass.ViewModels.SomeViewModelName
  • Has a transient(Persistent=false) single association RootObject navigable in the direction of the most abstract class you ever want to use for async work (ie the SysSuperClass in a standard model). It is important that this link is set to Persistent=false since pointing out a hyper-abstract-class in a persistent association is really bad practice, as it would require the framework to ask all possible subclasses if they have the key (this process is called exactification of a foreign key). In a system with hundreds of classes this means hundreds of queries – ie do not set persistent links to abstract classes if the key is stored outside the abstract class – it will work but it will hurt performance.

Once you have this in your model and the server sees it – the server will create 2 new administrative serverside jobs. One job is looking for SysAsyncTickets that has null in the Done attribute. This job has high frequency – just like a key assigning job would have – but it is more ok for the SysAsyncTicket-job since there is only one of it. The other job deletes tickets that has a DeleteTime older than now – this job has a very low frequency.

The high frequency SysAsyncTicket job will look up the root object from RootId – look up the referred ViewModel – and then execute the viewmodel just as a normal serverside job. Typically this means it will execute the actions on the root-level in order from top to bottom – and then save and changed state that came out of those actions.

Seemingly simple as this is, it do brings a powerful solution to many of the needs we come across building scalable multi user enterprise-grade information systems.

Example

If I have a Customer object and I want to give it a unique identity number. I cannot just assign a number from a known latest-used-number-singleton because I do not know what other users are doing right now – they may want unique numbers for their new customers as well. So I need to have “exclusive access” to the latest number while I increase it, grab it and assign it to my customer.

I can do this by defining a ViewModel and name it TheCustomerNumberAssigner, rooted in Customer that has one action defined like this:

SomeSingleton.oclSingleton.LatestUsedCustomerNumber:=SomeSingleton.oclSingleton.LatestUsedCustomerNumber+1;
self.CustomerNumber:=SomeSingleton.oclSingleton.LatestUsedCustomerNumber

I now want this ViewModel action to execute in a serialized context so that I have exclusive access – and the only place that can be guaranteed is on the server.

To trigger this asynchronous execution I can now go like this from a method inside the Customer class:

let ticket=SysAsyncTicket.Create in (
  ticket.RootObject:=self;
  ticket.ViewModel:=Customer.Viewmodels.TheCustomerNumberAssigner
)

Once the customer and ticket are saved the server will find the Ticket, resolve the customer, find the viewmodel, execute the action (could be many actions – but only one in this case), save.

Once a refresh is done your end-user will see the assigned customernumber – and possibly communicate it to people waiting for it.

This is mostly the exact same behavior that the Timer/Clock-way to solve this problem – but this way will scale better because you want to assign unique numbers to invoices and a hundred other different classes you may have. With this new approach we only have 1 timer/clock triggering, consuming the SysAsyncTickets as they are discovered.

Updates 2020-03-03

Would it not be neat if we could skip the ViewModel step for really small async cases like the number assignment above?

Yes! You can now send in Class.Method in the ViewModel property – the MDrivenServer will execute the method for the root object – it will however first check the PreCondition of the method.

Given this, the sample above would skip the ViewModel+action and instead add a method on the Customer class:

Customer.AssignNumber:

SomeSingleton.oclSingleton.LatestUsedCustomerNumber:=SomeSingleton.oclSingleton.LatestUsedCustomerNumber+1;
self.CustomerNumber:=SomeSingleton.oclSingleton.LatestUsedCustomerNumber

Consider having the precondition of the AssignNumber method set to:

self.CustomerNumber->isnull

And the ticket:

let ticket=SysAsyncTicket.Create in (
  ticket.RootObject:=self;
  ticket.ViewModel:=’Customer.AssignNumber’
)


Twitter!

Please, Please, Please follow us at twitter!

@AtMDriven

image

Zero followers!

I will tweet news in the Framework and retweet stuff in #nocode and #lowcode with comments!

Thank you

Remove the Stupid degrees of freedom

This is what almost all progress in areas of productivity and security is about – remove the stupid degrees of freedom. Sure there are people out there arguing that life is less electric when builders do not fall off skyscrapers in production due to guard rails in front of all +1meter drops. And yes, they will also argue that driving with the seat belt fastened is for people that should not drive a car in the first place.

You may wonder what seat belts and not falling off tall buildings has to do with degrees of freedom? Your body is free to continue in your given speed even when the car halts abruptly if you do not where a seat belt. Hence you have a degree of freedom that will never ever be beneficial to you – and that is what I mean when I say “stupid degree of freedom”. The seat belt effectively removes your freedom to die violently even with collisions in moderate speeds.

Your gut reaction might be to say STOP I want to keep all my degrees of freedom – even the stupid ones – those that will never be beneficial to you. But if you are an intelligent and sane person you will soon come to the conclusion that I am right – stupid degrees of freedom should be removed wherever possible.

We have been removing and reducing the stupid degrees of freedom since intelligence took off. Reducing in like – do not smoke – or at least not continuously – if you want to stay alive. We put up traffic lights – and even if there is nothing stopping you running a red light – most sane people just choose to not use the stupid freedom to crash out in crossing traffic, and most of us appreciate the help the traffic light gives us in order to avoid a possibility that is stupid. We put lids over the sewage-entrances in the street – making it almost impossible for you to fall in – even though you could just as well avoid all those holes. The lids are effectively removing the stupid degree of freedom to fall down in one and break your back.

You get my point. Once you start to look at improvements in any field as reducing stupid degrees of freedom you will see that the description is a good one.

But why do I bring it up?

Well we need to talk about software development.

You think there are a lot of degrees in freedom in the physical world? Well there are millions and millions more degrees of freedom in the software world. Most of those freedoms are stupid and never beneficial – like software bugs.

In the physical world we have an environment that we cannot argue with or redefine; like we cannot walk through a brick wall and we will not turn into smoke for no reason. But in the software world we have no such basic limitations unless we stipulate them ourselves.

Any sane software developer would set up some basic rules to reduce the most stupid degrees of freedom you may think?

Do not be too sure.

This is were things turn ugly pretty quick – there is a standoff between developers using strongly typed languages (c#, Java, c, c++) and those that use weak/dynamic typing (javascript, assembler ) https://en.wikipedia.org/wiki/Strong_and_weak_typing

In short you can think of strong typing as “I first set up rules – then if I break them the compiler will let me know” – and that is pretty much to say what should be allowed and remove all other stupid degrees of freedom. Dynamic typing removes very few stupid degrees of freedom – and you will need to be very careful or your program will not do what you wanted it to do – very macho – “if you cannot avoid stupid mistakes you should not touch a keyboard in the first place”.

Most software developers has a self image like this:

image

But if you are focused on the result rather than being very cool you are probably looking for someone like this:

image

Who has the most degrees of freedom? Who is looking more professional? Who is almost guaranteed to survive the day?

When it comes to software development you want to ensure that:

  1. You have quality built in so that you need very little test to verify basic function
  2. You should be almost guaranteed success on reaching the functionality you want without people having to act heroic in any way

The way to reach this is by starting to remove many of the none beneficial degrees of freedom from the program/system.

But how can the system know what is beneficial to you and not? Well that is where the specification comes in – what is the system supposed to do? If only there were a way to declare what the system should be all about… Like UML.

What UML does is something that any sane person would want for any endeavor they take on; it defines the base rules on what you want to allow – and it does so in a way that has no alternate interpretation.

That means that UML is the un-ambiguous language you would want to write a specification for anything in. You would want to express your specification for software unambiguously since there are so many possible degrees of freedom that are just plain stupid – but sadly more likely (just because they are so many) than the degrees of freedom you really want.

Ok – I have now reached the point in my argumentation where I have left you with a suggestion to write a perfect specification in order to have a perfect system – and you may think that this is not really helpful – since it impossible to decide in before hand what the specification should look like. After all there were good reasons we ditched the waterfall-planning-strategies of the 1990’s in favor for the agile approaches with short term goals stacked on top each other. True. But I am not finished yet. There is a piece missing.

  1. We must describe what degrees of freedom we actually want in order to be able to avoid the ones we do not want.
  2. If we can manage to describe what we want in a language that has no room for alternate interpretations – then implementation has no degrees of freedom left – it must follow our specification
  3. If the implementation must follow our specification there is no risk involved and we will always succeed

Wow. Success is guaranteed?! Yes – if there is no need for free climbing heroes in the production – it will never fail.

Now let us take this approach one step further: if there are no degrees of freedom left when we follow the specification to get the result – then we can easily build a machine that does it for us – after all – very little smartness is needed following instructions that are complete, exact and with no room for interpretation.

Now you have MDriven.

And now we can take back the agility – but not on the level of implementation and coding – but on the level of specification.

This is the reasoning that has led us to claim that MDriven is a million times faster than traditional coding praxis’s:

MDriven works by allowing you to describe what your system should do – then – a second later – your system allows you to do exactly that.

The true value of your efforts are in the description of the system – just as it should be – this is the intellectual capital that survives tech-shifts that will happen as time goes by.

This piece was written to help you to understand why some of your hero-developers  might be reluctant to adopt MDriven. But a strong hero will always be needed for stuff – we are just saying that you do not need heroism to write 99% of the software you need today and tomorrow – a good evolving specification will do just fine – and you still need really sharp heroes to think out how to evolve the specification to reach your true goals.

Introducing Styles In Model

Before you go berserk and scream at the top of your voice : “STYLING IS A UI THING AND SHOULD NOT GO INTO THE MODEL SINCE IT WILL BREAK THE PRINCIPLE OF VIEW/MODEL SEPARATION ” – before you do that I would like to calmly state that a lot of the time we use styling like color and fonts to convey model based information.

Hmm – got you thinking?

There are two different parts to styling: theme and communication-by-style.

Theme should not go into the model since it will break the View/Model separation.

Communication-by-style; like “Look at me I am all red because you need to fix something”, and “let me bring your attention to this part of the screen that turned all yellow just now”, and “there is a clear divider between numbers on this row and on the other row to make it clear that they mean very different things” – this kind of communication MUST really go into the model with all the other information we use to build a software system.

In MDriven we have had a lot of different technologies (modernity as we call it) over the years. Currently the actively maintained are Windows Presentation Foundation and other Xaml approaches – and HTML5 approaches.

When we introduce Styles in the model – these styles must work (do their thing) in both Xaml and Html clients. And it must be likely that they can work in future implementations of modernity that will surely come.

The inspiration on what should be possible to style is taken from Office apps like Word and Excel – color the background, set a border, change a text font and style.

Word is what it is and styles cannot really change based on rules – but in excel you have conditional styles – that turn on and off depending on data – and that is the functionality we want as well!

Nothing of this is new to MDriven really – you could and can add your own styles in either external CSS or external XAML resource dictionaries – but that is not ideal and a bit complicated. We want to make stuff easy!

The Schematics of a UI-widget is something like this:

image

We will want to target the parts individually in order or to not limit your possibilities.

We also have Grid/Table and they have different schematics:

image

What we did

In the ViewModelEditor we added a “SIM”-button, SIM stands for Styles-In-Model:

image

The SIM-button brings up this new dialog that will hold all the styles you have defined in the model:

image

image

Once we have defined the style we can make use of it :

image

After the ViewModelEditor is opened and closed we will even see the style in the preview.

When we run the WPF prototyper we will see the style:

image

And in turnkey-core or on deployed turnkey-app we will also see the style:

image

Now we see that there are subtle differences – in WPF we apparently treat the ComponentContent as transparent and in web it is the color white. If we think this is an issue we can easily now set the CompoentContent-target to a specific color instead of leaving it blank:

image

Let us true a Blueish color:

In WPF we get this:

image

And in html:

image

What was hard is now easy

To color a specific cell in a data grid depending on some rule used to be really hard. In WPF we needed Styles with DataTriggers for example.

But now it is easy to style YourCell by just adding an addtional column YourCell_Style – have that additional column return a name from your Styles-In-Model and you are done:

image

image

And we get this:

2020-02-24_14h52_01

And for WPF:

2020-02-24_14h58_27

What you need to do

In WPF you must merge the Generated Xaml style dictionary to your other styles:

var stylesinmodelRD=StylesInModelWPF.GenerateResourceDictionaryFromStylesInModel(ViewModelDefinitionsInApplication.GetActionsRuntime(_ecospace.GetType()),_wecpof);
if (stylesinmodelRD != null)
{
   _wecpof.Resources.MergedDictionaries.Add(stylesinmodelRD);
   _rememberoldstylesinmodelRD = stylesinmodelRD;
}

In HTML you will find the generated css under this name:

https://<Yourapp>/NameOfControllerForMVC/StylesInModelCss

For a turnkey application like this: https://hkscratch.azurewebsites.net/Turnkey/StylesInModelCss

Getting data from anywhere- like for example Spotify – that is Oauth2 protected

Number 1 to get a successful integration going is : Read the documentation of the service you want to connect with – also read MDriven wiki and articles like this!

Number 2; remember that security is very often a precision sport – “close” does not cut it and often gives you the same error as “a mile away”.

In this example I will connect as a user (not a server, since a server cannot browse user data, only generic data) to Spotify and use their rest api to get some data that I will persist in my database.

I will also use the AutoForm-functionality in MDriven to get a UI to browse the fetched data with zero effort .

Gaining access

You will need to request an account for the protected service you want to read from. In spotifys case you get a developers account from here https://developer.spotify.com/dashboard/

Once you have that you create an “application” or “client” or “credential” – every service provider seems to call it something new – basically you want the service to become aware of the service you are building. The end goal is to get Client ID and a Client Secret that you will keep safe and private, and you will need to present these to the service at some stages in your integration flow.

image

Above you can see that I have 2 applications registered with the spotify api service, MDrivenRestCase and MDriven2

You can have as many as you need – this level is just to give you a unique key in order to let you in later on.

Starting communication

The spotify documentation states that I must have the user (for which I want to ask the spotify api) to login for me – it is not allowed to browse just any users data – the user needs to offer their consent to give you access.

We must send the user to a page at spotify – and we should send along what we want access for (grants) and how spotify will let us know the session code – if the user allows us to do what we ask:

https://accounts.spotify.com/authorize?response_type=code&client_id=OBFUSCATED394cd100968bd683f&scope=user-read-private user-read-email user-library-read&redirect_uri=’+
SysSingleton.oclSingleton.GetSystemUrl+’DWV?v=SpotifyAccess’

The yellow part: boiler plate and part of the contract with spotify

The green part: my identity as an integrating application that spotify gave me when registering as an app

The orange part: the grants that I want the logging in spotify user to accept the application doing – defined by the spotify documentation

The blueish part: if the user says “ok” spotify will direct the browser to go to the provided address and send along a key that I must use to get further – this key is often referred to as the access code – the url we send in is only a template, spotify will append the code to the end once it actually uses it

Note that we compute the redirect url with some logic and send the result to spotify : SysSingleton.oclSingleton.GetSystemUrl+’DWV?v=SpotifyAccess’

Read up on what SysSingleton.oclSingleton.GetSystemUrl can do for you here: https://wiki.mdriven.net/index.php/SysSingleton_GetSystemUrl , but as you may guess it gives your application address in runtime – if you know it you could just as well have used a fixed string, but it may be practical to defer this to runtime to allow for many environments to use the exact same code.

Further more the sent in url continues with +’DWV?v=SpotifyAccess’ – read more on what the DWV verb can do for you here : https://wiki.mdriven.net/index.php/DisplayWithVariables – basically it will allow you to receive data from the html parameters so that you may use them in your solution.

To do all these steps in MDriven I create a class for a Session and call it OneSession:

image

Then I do ViewModel that is rooted in an object of class OneSession, and a GlobalAction to show this :

image

image


image

I say that the text that comes out of the expression should be treated as a html link in ui – this way the user can click on the compiled link and end up at spotify to enter the credentials – or if spotify finds a valid cookie indicating that the user already did this and it should be considered still valid – then jump right back to us with the code.

image

Spotify will now use the template redirect-url and append it with &code=theaccesscodevalidforthisappforashortwhile

As turnkey gets the call with DWV?v=SpotifyAccess it will look for such a viewmodel and if there are additional parameters – as there will be since spotify append &code=theaccesscode – turnkey will look for a matching viewmodel variable and set its value accordingly.

For this purpose we declare the code variable:

image

Combined it will look like this:

2020-01-27_17h09_05

Get the Access Token from the Access code

Now we have the access code – we now must exchange this for an Access token (this step may seem like a bit of overkill but it is standard Oauth2 stuff ).

I can get the Json containing the Access token with a simple rest Post call if I give all the correct details (it is packed in a json object also called the JWT-token):

accessTokenResult:=selfVM.RestPost(‘https://accounts.spotify.com/api/token’,’OBFUSCATED_CLIENT_IDd683f’,’OBFUSCATED_CLIENT_SECRET3058′,‘HeadersAuth’)

The yellow part is a variable of type string that will hold the returned json

The green part is the client id and secret we got from the app-registration – they will be send as basic authentication as stated in the spotify documentation.

The orange part is the ViewModel nesting class holding the post parameters that we want to send – what they should be must be found in the documentation of the service we connect to:

The bluish part is the address for access token request found in the spotify documentation

image

Note that the we here send in also the value of the variable code – that we got from the redirect after user spotify login.

Putting the above described call in a button and it will look like this:

2020-01-27_17h25_57

The JWT token looks like this:

image

And the property called access_token is the one I want in order to call the api to get any information about the user.

Get your hands on the Access_token so that you can get going

Ok – now we almost have the access_token, I say almost since it is packed in a json formed string – and we need to get its value somehow. Multiple ways to get to content in Json is available in MDriven – I will choose this one selfVM.JsonToObjects(WhatClass,WhatJson) : ObjectOfWhatClass.

It is a common need to unpack Json as data – MDriven has a function to help you with defining matching classes. Copy the JSon so that you have on the clipboard. Then create or pick a class in a diagram – right click and choose “Add attributes, assoc. and classes from clipboard json” – MDriven will populate your diagram to match the json:

image

With the following expression I can now create a new instance of the class DataForAccessToken – and expect all the values from the JWT token to be available in this object.

vDataForAccessToken:=selfVM.JsonToObjects(DataForAccessToken,accessTokenResult)

Using the access token to get some stuff

Finally we are all set to get data from the api. There are loads of possibilities – this will get get the users current tracks with a get:

jsonresult:=selfVM.RestGet( ‘https://api.spotify.com/v1/me/tracks’ ,  ‘Bearer’ ,  vDataForAccessToken.access_token,  ” )

Note that we now use the retrieved access_token as a Bearer token – and this is such a common case that MDriven will understand this if you send in the user as Bearer.

The data comes back as json – and we assign it to the jsonresult variable. It turns out to be a deep hierarchy of stuff:

{
   “href” : “https://api.spotify.com/v1/me/tracks?offset=0&limit=20″,
   “items” : [ {
     “added_at” : “2019-07-25T23:03:21Z”,
     “track” : {
       “album” : {
         “album_type” : “album”,
         “artists” : [ {
           “external_urls” : {
             “spotify” : “https://open.spotify.com/artist/11lfQgLbVZRnR7tbtAnzhk”
           },
           “href” : “https://api.spotify.com/v1/artists/11lfQgLbVZRnR7tbtAnzhk”,
           “id” : “11lfQgLbVZRnR7tbtAnzhk”,
           “name” : “Barcode Brothers”,
           “type” : “artist”,
           “uri” : “spotify:artist:11lfQgLbVZRnR7tbtAnzhk”
         } ],
         “available_markets” : [ “AD”, “AE”, “AR”, “AT”, “AU”, “BE”, “BG”, “BH”, “BO”, “BR”, “CA”, “CH”, “CL”, “CO”, “CR”, “CY”, “CZ”, “DE”, “DK”, “DO”, “DZ”, “EC”, “EE”, “EG”, “ES”, “FI”, “FR”, “GB”, “GR”, “GT”, “HK”, “HN”, “HU”, “ID”, “IE”, “IL”, “IN”, “IS”, “IT”, “JO”, “JP”, “KW”, “LB”, “LI”, “LT”, “LU”, “LV”, “MA”, “MC”, “MT”, “MX”, “MY”, “NI”, “NL”, “NO”, “NZ”, “OM”, “PA”, “PE”, “PH”, “PL”, “PS”, “PT”, “PY”, “QA”, “RO”, “SA”, “SE”, “SG”, “SK”, “SV”, “TH”, “TN”, “TR”, “TW”, “US”, “UY”, “VN”, “ZA” ],
         “external_urls” : {
           “spotify” : “https://open.spotify.com/album/2gHDTP5A75V7oGRtwqIOWN”
         },
         “href” : “https://api.spotify.com/v1/albums/2gHDTP5A75V7oGRtwqIOWN”,
         “id” : “2gHDTP5A75V7oGRtwqIOWN”,
         “images” : [ {
           “height” : 635,
           “url” : “https://i.scdn.co/image/0872f9cca267f2eb85da4cb4a3b9bcc7257865c5″,
           “width” : 640
         }, {
           “height” : 297,
           “url” : “https://i.scdn.co/image/7fd553bb88de2bd52e55d68d5a8037c7011a5545″,
           “width” : 300
         }, {
           “height” : 63,
           “url” : “https://i.scdn.co/image/e4db6b0f9fffe3292ffd715281ec710e1f3dae79″,
           “width” : 64
         } ],
         “name” : “Swipe Me”,
         “release_date” : “2000-01-01”,
         “release_date_precision” : “day”,
         “total_tracks” : 15,
         “type” : “album”,
         “uri” : “spotify:album:2gHDTP5A75V7oGRtwqIOWN”
       },
       “artists” : [ {
         “external_urls” : {
           “spotify” : “https://open.spotify.com/artist/11lfQgLbVZRnR7tbtAnzhk”
         },
         “href” : “https://api.spotify.com/v1/artists/11lfQgLbVZRnR7tbtAnzhk”,
         “id” : “11lfQgLbVZRnR7tbtAnzhk”,
         “name” : “Barcode Brothers”,
         “type” : “artist”,
         “uri” : “spotify:artist:11lfQgLbVZRnR7tbtAnzhk”
       } ],
       “available_markets” : [ “AD”, “AE”, “AR”, “AT”, “AU”, “BE”, “BG”, “BH”, “BO”, “BR”, “CA”, “CH”, “CL”, “CO”, “CR”, “CY”, “CZ”, “DE”, “DK”, “DO”, “DZ”, “EC”, “EE”, “EG”, “ES”, “FI”, “FR”, “GB”, “GR”, “GT”, “HK”, “HN”, “HU”, “ID”, “IE”, “IL”, “IN”, “IS”, “IT”, “JO”, “JP”, “KW”, “LB”, “LI”, “LT”, “LU”, “LV”, “MA”, “MC”, “MT”, “MX”, “MY”, “NI”, “NL”, “NO”, “NZ”, “OM”, “PA”, “PE”, “PH”, “PL”, “PS”, “PT”, “PY”, “QA”, “RO”, “SA”, “SE”, “SG”, “SK”, “SV”, “TH”, “TN”, “TR”, “TW”, “US”, “UY”, “VN”, “ZA” ],
       “disc_number” : 1,
       “duration_ms” : 231986,
       “explicit” : false,
       “external_ids” : {
         “isrc” : “DKBKA0000802”
       },
       “external_urls” : {
         “spotify” : “https://open.spotify.com/track/06MaHjSGleJNvfsugH0mFi”
       },
       “href” : “https://api.spotify.com/v1/tracks/06MaHjSGleJNvfsugH0mFi”,
       “id” : “06MaHjSGleJNvfsugH0mFi”,
       “is_local” : false,
       “name” : “Dooh Dooh”,
       “popularity” : 49,
       “preview_url” : “https://p.scdn.co/mp3-preview/cb2a35fa9334d94af9d22ec482a3195f80d1a7ec?cid=edc3c2acfe634aa394cd100968bd683f”,
       “track_number” : 2,
       “type” : “track”,
       “uri” : “spotify:track:06MaHjSGleJNvfsugH0mFi”
     }

Interpreting the response

Luckily the same MDriven function we used for the access token works with any JsonData – and all properties and associations and new classes are added for us:

image

With this expression I can now transform the JSon-string to objects:

vTrackFetchResult:=selfVM.JsonToObjects(TrackFetchResult,jsonresult)

And to be able to browse all the data I add autoforms for all the classes in the model:

image

Conclusion

In this example I show how to obtain a jwt token from Spotify – and it is more or less the same for all Oauth2 services available.

I show how to retrieve json data from the spotify api and how to use json to automatically expand a model that fits.

I then show how to fill the model with the data from json.

Finally I show how to use the autoforms to gain a UI-access to all the data you have collected.

2020-01-27_18h05_57

The complete work I manually had to do to get here is what is in the ViewModel – and 90 percent of this flow will be the same for any OAuth2 service you want to talk to:

image

Ok but what if…

Now that you have integration infrastructure solved you will probably want to not just add data – you will probably want to update existing data – and merge – remove stuff from your database no longer valid and add new stuff not seen before. You need MDriven Tajson – for more on this read https://blog.mdriven.net/introducing-mdriven-tajson/.

Or maybe you wonder on how to expose your created information as a rest service? For more on this read here: https://wiki.mdriven.net/index.php/Rest_Services_In_MDriven#Exposing_ourselves_as_a_REST_service

Or maybe your use case is more user-centric – how to meet user requirements to pour excel data into your system and extract excel data out from your system. For more on this read here: https://wiki.mdriven.net/index.php/Excel_Plugin_Function

I know that when it comes to exposing information the need of authorization is never far behind – for more on this read here: https://wiki.mdriven.net/index.php/Information_security and https://wiki.mdriven.net/index.php/Access_control_system_in_MDriven

Localization

Localization is the processes of translating a product to work in a new culture or language.

When it comes to MDriven we are in a good seat for handling all the texts that are available in a system.

Since we have the meta model of the system we can in theory know about all texts the system make use of.

Texts in a system comes in many forms:

  1. Labels in UI
  2. Actions, menus and menu groups
  3. Constraints and validations
  4. Static text in a string in an expression used somewhere inside the application

The standard solution to Localization is to instruct all developers to move all texts out to resources and create one resource bundle per supported culture – and involve translators ahead of delivery of the product to create the per culture unique resource bundle. Phew! A lot of work against a moving target… Sounds expensive and slow? Yes it is!

Having a MDriven systems you also change the product more frequently than with traditional development – and that makes it even more likely that your traditional translation process will slow you down too much to be acceptable.

In its simplest form we will need something like the model below. The Translatable is a text that may – or may not – have a Translation for a given Language.

image

If the Pattern from the above model is discovered by your MDriven system you may install the new IMDrivenUITranslation service – then the MDriven system will use the data found in the objects for the model and use them as translations.

The service is installed like this:

MDriven.Translation.MDrivenUITranslationImpl.Install(ecoServiceProvider);// Installs translation services

Newer versions of MDriven Turnkey does this already for you.

The IMDrivenUITranslation has a DefaultLanguage setting. The DefaultLanguage is set by MDriven Turnkey to the Language set in the user browser. Typically this is a value like “en-US” or “sv-SE”.

The new versions of MDriven also introduce a new operator on the string type – called Translate.

‘Translate this’.Translate(‘sv-SE’) is a valid expression that will try to look up a SysTranslatable object with Value equal to ‘Translate this’, it will then look for Translations that points out a Language with code equals ‘sv-SE’. If found the value of the matching SysTranslation object will be returned. If no matching translation is discovered the original value is kept.

It would be a complete pain to create all the SysTranslatables by hand and to help you avoid that you can perform this in an action: ‘Whatever’.Translate(‘SPOOLMISSED’) , sending “SPOOLMISSED” as a language has special meaning and create SysTranslatables for all complete misses that system has seen since start or since last call to SPOOLMISSED.

The actual dictionaries used to do the translations are created at system start up. That means that you will need to restart your system in order to see newly added translations to take effect. This may however not be a possibility for the translators on your team – most likely the translators are just ordinary users or administrators of your system – but they will want to see the effect of an added translation as soon as possible. To mitigate this we have added yet another special meaning lnaguage identifier: ‘Whatever’.Translate(‘RESETCACHE’). This will reset all cached pages in your application since they possibly contain translations – and the next request they will be re-done and thus reflect the new translations made.

Even if the SysTranslatables are created for you – the SysTranslations and SysTranslateLanguage are not. We suggest you use some ViewModels to manage the translations and possibly make use of the Excel-plugin to push large volumes of translations in and out of a system.

Excel Rocks! But…

If you do solutions for colleagues with Excel you have the ability to build enterprise grade multi user information systems with MDriven in about the same time.

Excel is amazing – it empowers you. We want to empower you even more with MDriven.

Excel is so great because you do not need the IT department to get things done – you do not need to explain every tiny detail that you cannot articulate until you see it for yourself. You can work very iteratively and arrive at a solution that works now and can be improved tomorrow. You can do ANYTHING and EVERYTHING.

Excel is however frustrating since your solution is depending on strict definitions on what positions in sheets mean – and there is no easy way to communicate the relations between cells other than using column and row references. It is easy to lose track of the solution as it grows and you go from being very excited to hating it – back to excited – and so on in a rapid pace. Part of this is natural developer angst – and a big part is fixable by raising the level of abstraction with MDriven.

Excel is sadly not very safe when having multiple users because there is no difference between using the solution and changing the solutions – and some of your users will change rather than use, by mistake or curiosity or trying to be helpful – and then you risk to lose track.

  • We want to empower you to build multi user enterprise grade information systems without involving the IT department. We want to give you the power you have with excel but without the limitations.
  • We will enable you to separate “using your solution” from “changing your solution” as is the signum of all robust systems.
  • We will show you have to avoid losing track of a growing solution by using plain English instead of cell references in all your rules.
  • We will show how to incorporate any level of authorization into your system so that you can keep sensitive information in the same solution as open information – and still be safe.
  • We will show you that you can replace not only complex excel spread-sheets but also bulky licensed cots-systems with your own tailored MDriven systems. Doing so will save you licensing fees and make users happier – and put you in the driver seat for improvements.

Now you might think – “I really do love excel and I am not prepared to leave it”. You will not have to leave it! Your MDriven system will work with excel and it will be easy to push and pull data from your MDriven-based-system. You can also easily produce excel-reports from your system.

There are actually only benefits going down the MDriven route – it gives you the abilities of an experienced software developer without the need to learn a lot of technology. We want you to be able to focus on the gist of your solution and leave the tech-stuff to MDriven.

Reverse derived–more than what one may think of

The ability to reverse derive an attribute is practical in many circumstances – but it may not be obvious to everybody just what it can be used for.

What is obvious is that you may have a derivation that collects a couple of strings like self.FirstName+’ ’+self.LastName, and that the reverse derive action can be used to deconstruct what the user entered with an action expression like described in this article https://wiki.mdriven.net/index.php/Reverse_Derivation

And that is all fine – but what if you wanted to create other objects when a user changes a value? Like a log function.

image