Wo drückt der Schuh?
Heute geht’s ans Eingemachte! In diesem Blogbeitrag bekommst du spannende Tech-Einblicke in unsere aktuelle Entwicklung von Mataono, einer webbasierten Beratungssoftware für den Banken- und Versicherungsbereich, die unter anderem mit Emotionsanalyse und Spracherkennung arbeitet. Wir entwickeln Mataono in einem agilen Rolling-Release-Prozess, um kontinuierlich einzelne Komponenten zu testen, Feedback einzuarbeiten und weitere Features hinzuzufügen. Innerhalb unseres Workflows äußerte sich folgendes Problem: Nicht alle Teammitglieder sehen die neuste Version der Software in ihrem Browser. Grund dafür sind hartnäckige Cachedaten. Wie gewährleisten wir also, dass zu jedem Zeitpunkt, browserunabhängig, die aktuelle Version von Mataono sichtbar ist?
So wird ein Schuh draus...
Wir arbeiten mit dem Framework Vue.js, weil es unter anderem mit vielen kleinen Request-Response-Zyklen arbeitet. In kurzen Intervallen werden Anfragen an den Server gesendet. Dessen Antworten wiederum führen nur zu Änderungen an den Stellen im DOM, an denen es benötigt wird. Das vollständige Neuladen einer Seite durch den Browser wird somit vermieden und führt zu einer spürbar besseren Performance. Vue.js manipuliert nicht nur Daten, sondern auch deren Darstellung in den Oberflächen einer Anwendung. Um sicherzustellen, dass bei all der genannten Kleinteiligkeit stets die aktuelle Version im Browser der Nutzer:innen dargestellt wird, ergeben sich zwei grundlegende Schrittfolgen der Problemlösung: Die Vue-App darüber zu informieren, dass eine neue Version vorliegt, sowie die anschließende Verarbeitung und Darstellung dieser Information im Browser.
...und so ein Code!
Step 1 – Die Vue-App informieren
Die Vue-App selbst hat gespeichert, in welcher Version sie vorliegt. Um ihr mitzuteilen, dass sich die Versionen unterscheiden, muss bei jeder Serveranfrage mit einer Information über die aktuelle Version geantwortet werden. Das Backend ist mittels Django programmiert, sodass die Daten mittels Django-REST-Framework ausgeliefert werden. Hilfe bieten an dieser Stelle Middlewares, die sich in die Request-Response-Zyklen hängen. Anhand einer Zwiebel mit ihren einzelnen Schichten (=Middlewares), durch die eine Nadel geschoben wird, lässt sich der Ablauf verdeutlichen: Kommt sie im Zentrum der Zwiebel an, erfolgt dort die Verarbeitung der Anfrage (=Request) und die entsprechenden Informationen für die Antwort (=Response) werden hinzugefügt. In unserem Beispiel sorgt eine Middleware dafür, dass ein Header mit der aktuellen Versionsnummer eingefügt wird. Mit dieser Lösung muss nicht jede Response des Servers separat angepasst werden, sondern die Anpassung erfolgt nur an einer Stelle.
class FrontEndVersionMiddleWare(object):
"""
Middleware which adds a header to determine the currently most recent vue-js-mataono version
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request: HttpRequest):
response = self.get_response(request)
if settings.FRONTEND_VERSION:
response['FRONTEND-SERVER-VERSION'] = settings.FRONTEND_VERSION
return response
Step 2 – Die Nutzer:innen informieren
Im nächsten Schritt müssen die Nutzer:innen darüber informiert werden, dass eine neue Version bereit ist. Dafür benötigen wir einen zentralen Anlaufpunkt in unserer Software.
In der Vue-App benutzen wir axios, welches für das Handling der gesendeten Requests sorgt. Grundsätzlich ergänzt diese Bibliothek die Webadresse von Mataono an den Anfang eines jeden von uns gesendeten Requests. Außerdem können mit mit axios auch sogenannte Interceptoren implementiert werden. Einen dieser Interceptoren verwenden wir beispielsweise, um an jeden Request, den wir zum Server senden auch die aktuelle Sprache des Nutzers in die Header zu schreiben. Somit sorgen wir für eine konsistente Übersetzung.
axiosInstance.interceptors.request.use(function (config) {
const token = localStorage.getItem('authToken')
const language = localStorage.getItem('currentSelectedLanguage')
if (token !== null) {
config.headers.Authorization = 'Token ' + token
}
if (language !== null) {
config.headers.common['Accept-Language'] = language
}
return config
})
Da wir jetzt von jeder Antwort des Servers wissen, welche Version die aktuelle ist, haben wir auch einen Interceptor für die Responses implementiert, welcher die vom Server gesendete Version, mit der selbst bekannten Version vergleicht. Falls diese nicht übereinstimmen, sendet der Interceptor eine interne Nachricht, welche von der Mataono-App verarbeitet wird, sodass den Nutzenden eine Meldung angezeigt wird.
axiosInstance.interceptors.response.use(function checkResponse (successResponse) {
if (successResponse.headers['frontend-server-version'] !== version) {
window.dispatchEvent(
new CustomEvent('vueVersionUpdated')
)
}
return successResponse
}, undefined)
export default axiosInstance
Warum uns das glücklich macht?
Die Lösung mit Update-Notifications bietet zwei wesentliche Vorteile für die weitere Entwicklung von Mataono und lässt sich auch auf andere Anwendungen übertragen: Zum einen muss unser Entwickler:innenteam nicht jede Response einzeln anpassen, sondern kann dies an einer einzigen Stelle tun. Zum anderen erhalten die Nutzenden eine Benachrichtigung, sobald eine neue Softwarekomponente hinzukommt. Ein Popup informiert über die aktuelle Version und es ist nicht mehr notwendig darauf zu achten, alte Cachedaten zu löschen. In unserem täglichen Arbeitsprozess vereinfacht das Testphasen, vermeidet Fehldiagnosen und spart unglaublich viel Zeit.
Ein großes Dankeschön geht an dieser Stelle an Sami und Steffen, die als zwei unserer Backend-Entwickler erheblichen Beitrag zur Umsetzung des Blogbeitrages geleistet haben!