-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathi09.txt
More file actions
322 lines (161 loc) · 75.1 KB
/
Copy pathi09.txt
File metadata and controls
322 lines (161 loc) · 75.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
R1: What do you do professionally in your job? So you're in microservice development, testing, or DevOps right?
I9: I previously worked with [colleagues] on the team. So he was with him on the app server team, I've been on another team since this year. Our task is to operate our software on public cloud infrastructure in the future. So something like AWS or GCP. Instead of somehow own sheet metal, which is somewhere in a data center and all the automation that is necessary to ensure this operation. We want to use automated patterns to make it as automated and self-healing as possible. That is the goal of my team, or actually mine, are a few other teams that are pulling together.
R1: So DevOps is practically very strong and cloud?
I9: Exactly. So we are almost a bit Ops-heavy, but we write code, so we write code that does business, but I don't really write now, I don't really have anything to do with the shop system itself. I don't write a shopping cart calculation or anything. I am writing code that runs other code.
R1: What domain are you in? Backend—
I9: Yes. Very solid backend.
R1: What role do you have in software development? So you're a project manager, Scrum master or developer, right?
I9: developer.
R1: What part of your daily work does software development and programming have?
I9: Very high. To me. So apart from the typical meetings, somehow now daily or somehow planning meetings or something. Or sometimes, no idea, sometimes an all-hands, where somehow the news becomes. Otherwise, mine is, most of my day is practically working on tickets. And they are development-intensive.
R1: Okay, how much experience do you have in software development? How many years?
I9: I was permanently hired, I might say 2014, maybe a year later or. I don't know exactly anymore, but I just say 5 years.
R1: How long has it been here in the organization?
I9: Here in the company or in my current team?
R1: In the company.
I9: For three years.
R1: And team?
I9: Half a year.
R1: What frameworks and tools do you usually work with?
I9: We have - although, no, that's not true when I say most - but I work on a Mac. The colleagues still have Linux. My main tool is probably the IDE, that's where we use IntelliJ. Or I use IntelliJ. Otherwise quite a lot on the console, if you somehow, some things with Git, we do on the console, or we - in my new team, I now work a lot with Kubernetes, there is also this kubectl command line tool, so what is on foot, where you can prototype and play around a bit before you somehow pour it into code. So a lot of commandline, IntelliJ, Git, just the typical, how you as a developer version your stuff and something. We have an issue tracker. Our company decided to build its own issue tracker. I say there is room for improvement now.
R1: frameworks? Do you have a spring boot or anything?
I9: I now work a lot with Kubernetes and the way you program there, that's called the operator pattern and you write a kind of microservice, which also runs in Kubernetes itself and does not provide a REST API but talks to the Kubernetes API. And then he listens to events, he then notices, for example, no idea, some node has been broken, okay, so I have to start up a new one. Something like that, that's the kind of logic we're building. That lives in Kubernetes itself, is somehow deployed there as a Docker container - so we do Docker too - and the canonical way of writing the operator is in Go. We write Go and there is a library with which you can talk to Kubernetes and exactly. This is our daily bread.
R1: Then we get in with configuration. What do you mean by the term configuration?
I9: It is actually very difficult for me because it is somehow very far-reaching. There are different types of configuration, different levels. There is somehow, I don't know, when I write a piece, there are things that I as a developer might want to make adjustable. Wherever you might find something like features toggles, I want to be able to switch a code path left and right. So that somehow I can pull the handbrake in an emergency or only unlock certain things for a customer. It is a kind of configuration. Then of course environmental configuration. Something like, where is my database, what are the credentials? In fact, those are two different things if you say one is secret and the other is not quite as critical. It does exist. What else is there? Of course, the code itself somehow has a build environment that also has configuration, where I set what I have for dependencies, where I build the thing that it has some Jenkins. The Jenkins then somehow still needs credentials to be able to upload artifacts somewhere. But that's probably now - well, but at some point you have to start and somebody must have built it. Isn't that what you go to and fro every day, but it has to be there somehow. I'm sure I haven't covered everything by far, but -
R1: Do you have Kubernetes, or do you have to configure and, right?
I9: Exactly, Kubernetes itself - so the idea of Kubernetes is that there is actually a central type of database that represents the state of the cluster and that is also something that we - the workloads that we actually execute, so what the code I write actually serves is itself a kind of configuration. That you can say I want to start up a shop system and who owns the shop, the shop system and what is it, how big should it be? So that's kind of a configuration too. My code then listens to this configuration and then creates another configuration and then says a pod to the Kubernetes and then there is another place in the Kubernetes that then says, okay, I have to do it somehow now, no idea, one Get a piece of new sheet metal from Google and then start a Docker container or something. So from my point of view, when I say I'm the infrastructure engineer, that's actually useful data. I do not know whether this distinction makes sense, that one says that configuration is what influences my runtime behavior and user data is what my runtime behavior, i.e. what my logic then massages, is the user data. I don't know if you have a term, how you delimit it or something. So from my point of view it is - so it can be that what is useful data for one is the configuration for the next.
R1: Right. Yes exactly. That's why we ask everyone what they mean by this. When do you configure software? At runtime, at compile time?
I9: Well, I had already touched it a bit that there are many different levels. The classic in the Kubernetes world is actually that you have a kind of templatization, that for every thing you instantiate in this Kubernetes world, be it a pod in which a container runs or that one, no idea , a volume, which you then mount somewhere or something. That there are templates in which you can then insert certain values. Then you can say I want to start up a shop system now and that should, no idea, use this database and have this username and the rest will be more or less of its own accord. Now that's the one thing that comes to mind spontaneously. So what I just said, at build time there are other settings that are relevant. In a way, it actually affects every cycle, i.e. every stage of the software life cycle. From, I set up a local build environment at all until I somehow make a CI environment, I might do it, I have it started locally, I may even have a separate configuration for the IDE. I let it start somewhere in a Jenkins as a test, right down to, no idea, preproduction, then production deployment, which then, until the thing runs, every stage actually has its own requirements. So for certain things, something like, I want to let something run, because you probably have the same settings, something like where the database is, is a setting, but depending on the stage, it has different values. Whereas, of course, something like compile time has different settings that you have to set than for the runtime settings.
R1: We often divide between professional and technical configuration. From a technical point of view, it is perhaps more so for the customer, whose features, technical is then CI / CD deployment and so on. To what extent does this functional and technical configuration play a role in your daily work? And maybe the relationship and so on. With you it is of course difficult. Your professional is probably also a technical one at another level.
I9: So what we have is there is a kind of stripped down API. So there is a separate REST API with which you can talk to our platform and say for example I want to have a new sandbox now, this is such a small shop system on which you can fiddle around a bit as an external developer without now somehow breaking other people's stuff, you can say I want a sandbox. There is a REST API and in the REST API is the total amount of _what do I need, what do I need to know to actually somehow drive up a Docker container_, is there evaporated to what the user can and should know. Something like that, certain things depend on when the user is logged in, certain things depend, for example, to which organization does he belong and how does billing work, who do I have to bill for? The user can also set other things himself. But these are very few things and most of the configuration, something like what is the host name of the database, of course the user does not know that, should he not even know, we do that internally. That is actually, much of it is technical and me believe the best way to make this separation is actually between what's in the Kubernetes, the Kubernetes cluster itself or the APIs of which the customer has no access. We do that internally. Everything is included, both technically and technically and we then decide what we want to expose to the outside with a separate API.
R1: And what - a bigger role for you is the technical in your work.
I9: Yes, I would say so.
R1: Are there any interactions between functional and technical configuration? So maybe one of them somehow determines the other?
I9: I don't know right now. We are still relatively early in the phase, which is what I am working on. Relatively many things we think about are more of a non-functional requirement. Something like backup or something that is not exactly what the customer would like to set or do, but in a way what the customer wants also plays a role for us, for no idea, there are customers who are simply bigger Shops have, which may need to get larger instances provisioned from the outset or - And these are mainly things that our product managers discuss and drive with us. As a developer, I am relatively little involved. Either my manager does it or mine, I still have a tech lead with me on the team, which is also very involved. He always hangs on the line with the discussions with Übersee et cetera and prepares it for me ready to mouth.
R1: Are you dealing with the configuration of a monolithic system?
I9: In a way yes, because what we do is the monolith plus a little bit around it, but what we want to boot up is what I built in the previous team. So there are a lot of configuration parameters, which database is still the first example, which comes to mind because I'm working on it, but there are, I don't know how many, so I can't list them all , but it is-
R1: dozens or hundreds or—?
I9: hundreds? Well. But dozens do, yes. So no idea, I would say 50 plus minus somehow. And that will probably not even be enough. It would probably have to be even more or something, but that's what has been around so far. Is a large number.
R1: To what extent do you have to configure the tools and frameworks that you may be using or the infrastructure?
I9: Yes.
R1: Of course now maybe the question is not about ops now—
I9: Wait, I'm having a hard time asking.
R1: For example, if you're developing microservices, you're using Spring Boot for a framework, you have to configure the Spring Boot framework somehow and you might have to configure the build process. The Gradle or what I know (I9: Exactly), you have to configure the Docker somehow—
I9: I think configuring the build process is a consistent topic, which probably affects every developer. So even if you, even the JavaScript people with us who don't have a compiled language now, even they have a process that somehow packages things up and uploads them to a repo and runs tests and - even if no compiler is running, they have to somehow you have to set up your code shovels somehow. So there is always some form of configuration with it, regardless of which compiler is called or even now, but everyone has that kind of build automation. So I hope very strongly, so the times when somehow somehow back and forth individual files with FTP servers and then somehow directly on the productionserver or so, that is hopefully over. At least in our company, that's the way it is. In addition, there is actually quite a lot that goes with it. I have spoken a lot about Kubernetes now. This presupposes that there is already a configured Kubernetes environment. At Amazon and Google you can buy something like a managed service. This takes a lot of your own administration work, but you still have to do it somehow - for example, you have to say okay which version of Kubernetes we have, you have to consider if there are updates, when will I roll them out. That has a certain impact on the workloads and besides the actual mechanism, which manages cluster software and reacts so reactively to events, there are of course other decisions. Something like, on which nodes our workload actually runs. So the sheet metal, what is underneath, what is abstracted from Kubernetes, which, at some point, it runs on something like a VM. How big is it How much RAM does it have? Then of course there is also billing. Authentication is a big topic, there has to be service accounts somehow, we have to somehow determine who can talk to this cloud provider at all. So our developers may do that, but who can do what. Not everyone is allowed to do everything. I just had something, now I've forgotten it. Damn.
R1: Are there any dependencies or interactions of frameworks or tools that you use, maybe infrastructure. So if you now, don't know, your cloud infrastructure, is it dependent on the configuration of what you configure in the framework or something? Or the other way around?
I9: Yes, something like, for example, which Kubernetes version we use, of course also determines in a certain way which APIs we can call or certain things may also become - so new things are added, other things are deprecated. Maybe it will come sometimes - it shouldn't be - but maybe there will be a breaking change somewhere that should have been stable. So that must be a match somehow. Well, what I wanted to say: We still use Terraform for everything that goes around Kubernetes. This is our mechanism to turn one of those nude cloud accounts into one in which we can deploy our things with Kubernetes. This includes something like creating user accounts. Prepare storage items in this way and build the bridge towards tools in the direction of continuous delivery, which then orchestrate a rollout of software. So Terraform is one of them. It doesn't concern me personally, I don't have to work with it, I can assume that it's already there, but a sister team of us who mainly do something like that. They basically form the basis for us and so, in my view, they provide the lower-level things. This is an account that I can simply log into and then everything is there in principle that I can start shooting against Kubernetes.
R1: How would you actually see the importance or the importance of configuration in software development?
I9: Well, it doesn't work without it. So it's pretty clear that you can - yes, every software has some form of dependency on other things or on the rest of the world and of course you rarely want to hardcode that, but mostly you say no idea if you have a shop system, we want to be able to host more than one shop. Then you have to be able to adjust, okay, who owns it now. Which database speaks to, how do you authenticate yourself with it? Exactly, so that's enough for you as _very high_?
R1: Yes of course. Are there differences in the importance in the different software life phases? So when you start with requirements and so on.
I9: Oh, requirements. Of course that's a good point, yes. So that is, it would be extremely desirable, of course, if you had an idea from the outset, so maybe just as a black box view. What do you have to adjust so that in the end some specific result comes out. So when you worry about such an API that you say, okay I want to be able to say as a customer, I am this and that and I need this and that, but I don't want to have to know what is the URL of that and that . So you have to think about what is required, what is maybe even optional and what should be hidden from the end customer. And in a way the same for the quasi-internal stakeholder. He may have to put the things that are hidden, but for him, too, the question arises: what should he know, what should he possibly ask from others or get somewhere, what is optional, what does he omit, what do I do maybe a deprecated feature that you can theoretically set, but we never want to activate it again or something. Exactly, of course that's for - very useful if you can navigate through a story using these interface descriptions. If you know exactly, okay that has to be able to tick off somehow and then you know, okay the way, if I have the setting and I know how it works, then I can get an idea of how I implement it, that this Setting is also respected.
R1: Were you prepared for configurability or configuration during your studies?
I9: I would generally not say that I was particularly well prepared for software development. So of course, you did a programming internship and I can do syntax and semantics of Java, but what actual software looks like via a Hello World example or something that you started from scratch and you can enter 3 + 5 and then there comes somehow - we made relatively many examples so small and did little, yes, scenarios in which it would have been worthwhile to think about questions such as configurability at all. If you only write Hello World, you somehow know that you can type in your name and then the _Hello Olli_ writes, we did something like that, but that's what it is - so what you are talking about I think is more of a problem, how they say programming in the large. When you have really big problems and you have to manage complexity. We didn't really penetrate this domain of complexity in my studies. Or just abstract and I kind of do class diagram or some other UML like Bla, but so really that I say I have an idea how to actually do it or something, I can't confirm. 28:10 is a pity. I think it’s important, but -
R1: Exactly, so my question about it, should it be taught during your studies? So configurability or configuration?
I9: I don't think that's something a classic lecture would fill. So that's kind of a classic crosscutting concern. It somehow affects everyone who does something with software and accordingly that should probably somehow be embedded in _we do something with software_. However the lecture is called. But generally, as I just mentioned before, to face the problem of programming in the large, something like that you even think about build automation, that you think about continuous integration. These are things that I happened to get because I did an internship, a voluntary one, while studying, but unfortunately the university didn't teach me that. But I would find it great.
R1: Let's go over to how to work with configuration. How do you manage and document configurations?
I9: I'll limit myself to Kubernetes again. That is what is now so directly my world and with which I have to deal. The concept in Kubernetes is - as I said before, it is a kind of database and you can create your own custom types and for that there is also a schema and you can say I have an object, that is foo and that has three fields, one is called bar, is a string, the other is baz and is an int or something. And you can also do it directly, so there is a scheme, you can create that with the scheme and Kubernetes says no if what you try to insert does not match the scheme. Kind of like a database table, too. And the schema itself is also an object, which is versioned in Kubernetes and there are also desciption fields where you can actually enter free text. You can also enter certain constraints, you can say this string can only contain the following three values, green, blue and white, or something. This is mainly what we do. I have found in my experience that it is relatively difficult to keep documentation useful if it is not under the same lifecycle as the software. So no idea, I'll say a markdown file, which is in the Git repo, to adjust and then say in a pull request, I will now adapt the document and make the code change, maybe that will work. But something like that, the classic way is to somehow throw documentary, somehow gigantic tables or something into the confluence and one person does a lot of work on it and the next one changes the code and maybe knows nothing about the document and then it drifts apart somehow and then the usefulness of the documentation goes down very quickly if that is somehow no longer applicable, insofar ... So I think it makes a lot of sense to let things live close together, that they somehow share a life cycle and then it is much easier to say - you may even be able to include any, no idea, checks in the CI, that we say we go through our schema and each field must have a description. So if you forget a description, the Jenkins says red. You could do it. We don't have specifics now, but that would be things you could think about, that you see the documentation itself as part of the overall process that is subject to automation.
R1: You said that with the scheme, as you said. What is the biggest advantage of this administration? So I assume you have an object, then a configuration with you then, right?
I9: With us, an object is like a shop. And then there are various things on it. Part of it, as I said, comes from the end user, part of it or a large part, respectively. Different, this object - The lifecycle works like this: If you create an object that is for Kubernetes the request create me a shop system. And others listen to whether an object is being created and react accordingly. That means, for example, that they then create other objects, which are then the actual Kubernetes objects, with which Kubernetes then knows what to do. First it says, drive up the docker container and if it is a production instance, then you drive up three of them so that they are redundant and can somehow do a bit of load balancing, if it is a sandbox, then only one. So starting up this container is what Kubernetes does, but this mapping is what makes our code and the input data for the mapping is - what triggers it, this logic is that such an object is created, such a shop object and then other things flow in , something like there is a configuration that says, there is a database that has the following credentials and URL. There is something like that and there are several of these objects and they have labels and you can then say I'm looking for an object or I'm looking for objects with the label database. Then, for example, three configurations for a database come back and then, when I provision myself a new shop, I can choose which of the three databases I go to.
R1: Then where are these database configurations in?
I9: This is also a kind of map object in Kubernetes itself. There is something called Config Map, which behaves like a map <String, String> in Java.
R1: So a configuration is practical at the beginning, is it composed of several configuration parts and then it is practical, a configuration is then like a graph with sub-configurations? Can you understand that? So-
I9: Well, it is a bit difficult for me, that - it's just such a complete system in which everything somehow always flows a little bit. In so far it is difficult to draw the line. A database configuration in this case would be a standalone object. It's like a folder, it says Host is foo and Adminusername is bar and blablabla. This is a folder and it denotes a database. And this folder still has a label on it, it says _Datenbank_. And the logic that I described earlier, which listens to such a shop system object, would then, if one is created, look okay to which database I put this shop and then query for this name. So these are separate objects, but there is logic, which then, or they flow together in logic and then lead to a certain behavior.
R1: What is the big advantage of this administration?
I9: Now related specifically to Kubernetes, right? How generic do you mean that?
R1: Yes, so what is the advantage of saving our configuration like this, saving Kubernetes or maybe not external to GitHub or something.
I9: You can also do it. The cool thing about Kubernetes, there is this generic API with which you can talk and everything is subject to automatic life cycle management. You can just wad on things, you can listen to something and then the framework calls you. It's like a Hollywood principle, so don't call us, we call you. You get called, something happened here and then you can start your logic and do certain things. And one can also say relatively simply something was wrong, no idea, someone has created a shop system, but no databases are configured, then I crash, then my logic flies away and then Kubernetes knows that I have to try again. And then there is a kind of exponential (? 36: 49) mechanism that calls it again and again and crashes again and again, but maybe somebody saw it at some point, created a database and then the logic goes through. So that's a kind of self-healing mechanism that listens to environmental influences and if he notices something didn't work, then it has an automatic retry that - you have to put a little brainwash into it, think it through wisely, but if you do it right is self-healing. It's actually a really cool mechanism. And that, as you said earlier, concerns quasi professional configuration, that would now be something like the shop system object and also technical configuration, that would be how the database configuration would be such a very classic technical thing. A customer will never see that and it lives, or is subject to the same mechanisms and the same advantages with this I can wade it and it heals itself and so on.
R1: Okay, was ist denn der größte Nachteil dieser Verwaltung?
I9: Es gibt keinen. (lacht)
R1: Das hat bisher von keiner gesagt.
I9: Ich weiß nicht. Ich bin wie gesagt erst tatsächlich relativ neu. Ich habe noch n — das, was ich gebaut habe, hat sich jetzt noch nicht so wirklich im knallharten Produktionseinsatz bewähren müssen, insofern. Da gibt es mit Sicherheit Fallstricke über die ich bisher selten gestolpert bin. Mal gucken, was gibt es denn, was, wenn ich so überlege, über was bin ich so gestolpert? Eine Sache ist natürlich, man kann in dieser Gesamtdatenstruktur Sachen ändern und dann ist die Frage sowas wie Concurrent Access, wenn zwei gleichzeitig versuchen ein Objekt zu ändern, dann, da gibt es kein klassisches Locking oder keine Transaktion in dem Sinne. Also Transaktionen gibt es nicht. Wenn man an zwei Objekten etwas ändern will, dann passiert das sequentiell nacheinander. Man muss hoffentlich so gebaut sein, dass man, falls das in einen widersprüchlichen State kommt, dass man noch mal getriggert wird und das dann ganz biegt oder, wenn zwei gleichzeitig versuchen etwas zu ändern, dann, der erste gewinnt und beim anderen knallt es, da kommt zurück _das Objekt wurde in der Zwischenzeit geändert_ und da würde dann der klassische Retry-Mechanismus wieder einspringen, dass der dann sagt okay ich gebe auf und eine Sekunde später versucht er es noch mal, liest es frisch und dann hat hoffentlich nicht noch mal dazwischen was gelesen. Also es ist halt, ja du hast die klassischen Probleme eines Distributed Systems mit irgendwie State-Management im weitesten Sinne—
R1: Bloß auf Konfigurationsebene jetzt noch?
I9: Genau.
R1: Wie werden denn Konfigurationen bei euch im Team kommuniziert? Also wenn ihr jetzt eine neue Konfiguration anlegt oder so oder änderst eine.
I9: Den Anwendungsfall, dass jetzt wirklich, dass wir jetzt an was konkret gearbeitet haben und plötzlich gab es ein neues mandatory Setting oder sowas, fällt mir jetzt tatsächlich nicht ein, dass wir das schon mal hatten. Hab meistens bisher an, so ein bisschen an anderen Ecken gearbeitet als meine Kollegen gerade aktuell arbeiten. Beziehungsweise man hat sich von vorneherein koordiniert wie man Sachen bauen will. Wir haben jetzt kurzem haben wir etwas refactort, das war in einem Operator und jetzt sind es zwei, aber da haben wir uns vorher überlegt okay der eine liest von dort und dort und der schreibt dann dafür sein Ergebnis wieder dort und dort hin und der andere liest das dann. Darum haben wir uns das von vorneherein überlegt, wie der Handover quasi stattfinden wird und das hat auf magische Art und Weise sogar einigermaßen funktioniert. Also das war okay. Also in gewisserweise trifft es natürlich, spielt das auch in diese Dokumentationsfrage, die wir vorhin hatten, mit rein. Wenn ich irgendwie pulle und ich sehe an dem Readme-File hat sich was geändert oder an irgendwelchen, diesen Schema-Deklarationen oder so, dann würde ich auch einfach mir den Diff angucken.
R1: Werden bei euch denn bei Code-Reviews auch Konfigurationsfiles gereviewt?
I9: Hat mich bisher nicht wirklich betroffen. Also Konfiguration, sowas wie, um mal auf das Datenbank-Beispiel zu kommen, einfach welche Datenbank gibt es in dem Gesamtsystem. Das war immer was, was für mich schon da war. Das hat mich — ich war nicht derjenige, der eine neue Datenbank angelegt hat oder sowas, sondern ich habe die nur benutzt. Was für uns schon eine Rolle spielt sind diese Schemas. Also die Schema-Deklarationen für Konfiguration. Das wird Git-versioniert wie alles andere auch, wie unser Code auch. Das sind irgendwelche YAML-Files aus Gründen ist es bei Kubernetes, ist der kanonische Weg, dass man Sachen mit YAML ablegt. Und die sind mitversioniert, liegen direkt neben den Go-Files und haben den gleichen Lebenszyklus, wie der Code. Und unterliegen damit auch den Codereviews.
R1: Welche Kriterien habt ihr denn und zu welchem Zeitpunkt integriert ihr denn Konfigurationsoptionen in eurem Code? Dass dann irgendwas halt konfigurierbar ist.
I9: Ich würde jetzt sagen bei der Entwicklung, aber das ist wahrscheinlich eine zu allgemeine Aussage.
R1: Genau, also wann entscheidet ihr, dass das jetzt mal konfigurierbar sein kann und nicht—
I9: In gewisserweise ist es bei uns vorgegeben, weil die Soft— oder unser Ziel ist, wir wollen unsere Software in der Cloud ausführen. Und die Software selbst, wenn es total sinnvoll ist sie zu ändern, können wir sie auch ändern, aber das Gros der Funktionalität wollen wir _as is_ benutzen. Insofern müssen wir das umsetzen, was die Software, die wir ausführen wollen, von uns verlangt. 43:06 Also das sind offensichtlich die, die offensichtlichen Konfigurationsoptionen, die wir irgendwie bedienen müssen. Insofern, das ist etwas, was auf jeden Fall vorgegeben ist. Was wir selbst exposen wiederum an zum Beispiel unsere Kunden, die so eine API callen — ich glaube die Frage hatten wir vorhin schon mal, was davon wir exposen, oder —
R1: Ja ne, aber nicht — das war nicht was, ja genau, aber warum, also was sind die Kriterien das anzulegen. Also gut, weil es der Kunde will, aber es kann ja auch sein, dass es sein kann, weil wir jetzt irgendwie Monitoring machen wollen oder sowas.
I9: Ach sowas, ja. Genau, also es gibt bestimmte Sachen, die einfach die Software, die wir ausführen schon von uns verlangt. Dazu zählt auch sowas wie, sie will gerne Metriken wegschreiben. Wo schreiben wir Metriken hin? Müssen wir eine URL hinschreiben, das ist glaube irgendein Graphite oder irgendsowas ist das, irgendso ein Metriksystem. Dann kann dieses System, was wir deployen, das spricht dann spricht dann mit diesem anderen System und schreibt seinen Krams dahin. Ist wieder die Frage, wo läuft das wiederum? Und das ist so ein klassischen Infrastrukturthema: Wie steckt man Sachen zusammen? Datenbank ist natürlich der nächste Anwendungsfall. Authentication hatte ich vorhin schon mal angesprochen, das ist auch so ein Drittsystem und wir haben noch andere Datastores, wo wir irgendwie transiente Daten, wie Warenkörbe oder sowas hinterlegen. Das ist eine andere Art von Datastore, der — wo das Shopsystem wissen muss, wo schreibe ich oder wie spreche ich mit dem Ding. Ich glaube ich bin schon wieder an der Frage vorbei, oder?
R1: Ja, so ein bisschen. Ob ihr irgendwie so Richtlinien habt, wo ihr vielleicht sagt in Zukunft könnte man das vielleicht anders machen, deswegen baue ich jetzt mal hier eine Option ein. Also habt ihr so ein Gefühl — kann ja sein, dass es bei euch einfach so ist wir machen nur das optional, was uns vorgegeben ist und nichts anderes, aber—
I9: Also ganz nach — also quasi als API für den Kunden, die wollen wir tendenziell so schmal halten wie möglich, damit wir selbst viel Raum haben Sachen zu reworken oder zu ändern oder — also das ist das eine. Und für uns intern, wirklich Richtlinien haben wir nicht. Wir lassen halt good Judgement walten von was wissen wir, was steht auf der Roadmap, was wird irgendwann sowieso mal änderbar sein müssen, dann bauen wir jetzt vielleicht das schon ein, auch wenn es aktuell dann, der eigentliche Wert vielleicht trotzdem erstmal immer der gleiche ist, aber dass man es schon mal umbiegen könnte, sowas. Haben wir aber wirkliche Richtlinien oder was bei uns im Team keine.
R1: Wie viel Aufwand ist es denn bei euch eine Konfigurationsoption einzubauen? Also richtig beim Implementieren und so weiter.
I9: Die Frage ist, muss man eine Art Migration machen. Also ist es quasi ein neues mandatory Toggle, dann muss man natürlich irgendwie zusehen wie alle die bisher schon laufen, also keine Ahnung alle Shopsysteme, die wir schon haben, wie konfiguriert man die entsprechend, dass sie das mandatory Toggle auch haben. Ansonsten würde es ja nicht funktionieren. Bei optionalen Sachen ist es natürlich einfach. Also tendenziell baut man die Option ein und wenn es irgendwie geht ist der einfachste Weg, man legt einen Default mit dahinter und dann kann man sagen _okay, man kann es umschreiben und per Default ist es das und das_ und dann überlegt, was hoffentlich sensible ist. Das hängt natürlich von der konkreten Konfiguration ab, ob es etwas ist, was sich ändert, was tatsächlich für jeden verschieden ist, oder ja, fällt mir jetzt keine wirklich allgemeingültige Aussage ein.
R1: Und wie hoch kann der dann sein vielleicht im, sagen wir mal im worst Case? Wenn ich jetzt eine ständig änderbare, die überall schon einen Einfluss hat… Also sitzt man dann einen Tag dran, oder eine Woche oder vielleicht einen Monat oder sowas?
I9: Kommt jetzt ein bisschen darauf an, wo die Konfiguration ist. Wenn wir wieder über Kubernetes sprechen, wäre das wahrscheinlich relativ schnell gemacht. Da gibt es auch wieder, würde man dann auch wieder so eine Operator haben, der lauscht auf die Objekte und würde feststellen, da fehlt ein Configuration Property und würde das dann automatisch in allen ergänzen. Die Operator funktionieren auch so, die lauschen nicht nur auf Änderungen — also die werden gestartet und lauschen dann nicht nur auf Änderungen, die dann kommen, sondern beim Start gehen die immer erst mal durch alle Objekte durch, die schon da sind. Das heißt damit kann man auch relativ einfach sowas wie Migration machen. Da könnte halt — man würde, angenommen es gäbe einen Operator, der hat Versionsstand n und dann kommt die Version n+1 und die hat einen neuen mandatory Konfigurationswert implementiert, der würde bei seinem Startup automatisch durch alle Objekte durchgehen, würde bei allen feststellen, da fehlt was und dann irgendeine Art von Logik invoken, was auch immer das, keine Ahnung, vielleicht spricht er mit einem Drittsystem und holt sich einen Wert oder was auch immer. Wie aufwändig das ist, hängt natürlich von dem konkreten Fall ab, was zu tun ist, aber so prinzipiell, so vom — der Mechanismus selbst mit dem wir arbeiten, macht uns das relativ einfach. Also ich würde mal sagen der Boilerplate drumherum, den kriegt man locker in einem Tag hin.
R1: Okay und der andere Fall? Wo es jetzt dann nicht im Kubernetes ist?
I9: Kann ich wenig zu sagen. Das habe ich bisher nichts mit zu tun gehabt.
R1: Wie viel Aufwand ist es denn eigentlich so eine initiale Einrichtung, was ihr auch vielleicht gerade ja auch ein bisschen macht, einer Konfiguration für Tools, Frameworks und Infrastruktur denn zu schaffen, dass initial mal alles so läuft?
I9: Ist prinzipiell mega viel Aufwand. Dafür gibt es natürlich sowas, wie unser Schwesterteam, deren eigentliche Aufgabe ist, diesen mega Aufwand kleiner zu machen. Also das ist quasi ein eigenes Team, was nur sich diesem Problem widmet, was sich hauptsächlich um initiale Einrichtung und auch in gewisserweise dann auch um fortwährende Updates, aber was diesen ganzen Bootstrap-Prozess sozusagen von ich habe mal irgendwie einen nackigen AWS-Account geklickt bis jetzt könnte man da Shopsysteme starten, das dazwischen abdecken soll. Also das ist sehr viel Aufwand. Das rechtfertig ein eigenes Team.
R1: Wenn es so Versionsänderungen gibt, zum Beispiel, also wir haben immer das Standardbeispiel Spring Boot 1 auf 2, da haben sich Konfigurationsoptionen geändert und so weiter, ist das auch viel Aufwand da irgendwie das nachzuziehen, oder die ganzen Konfigurationen zu ändern oder valide zu machen?
I9: Das kommt natürlich so ein bisschen darauf an, ob die, wie der Lifecycle einmal der konfigurierten Appsachen ist und der die die Konfiguration bereitstellen. Wenn man jetzt zum Beispiel sagt, keine Ahnung, wir ändern die Version unseres Microservices, aber die Art und Weise, wo die Clusterkonfiguration, wie der Microservice ausgeführt wird, liegt irgendwo ganz anders. Dann muss man da natürlich eine Art Handover herstellen, sodass man von einem validen Gesamtsystemzustand in einen anderen validen Gesamtsystemzustand geht. Da kann man ja einfach die Version des Microservices anheben und die Konfiguration anzupassen. Wir benutzen dafür hauptsächlich, oder so, für zum Beispiel so Testszenarien oder sowas, können wir das über Featurebranches zum Beispiel machen. Ich könnte jetzt zum Beispiel sagen ich baue einen Operator von mir, mache einen Featurebranch, der hat dann Version 08/15-Featurebranchname-Snapshot und dann könnte man zum Beispiel sagen wir haben ein Repo, wo die, es gibt ein Repo das heißt, da gibt es etwas, das heißt API-Stack. Das sind so die Gesamtmenge an Operators, die man braucht um unser System zu betreiben, werden da so zusammengezurrt und da könnte ich sagen — oder zum Beispiel das Beispiel, was ich vorhin hatte, das wir aus einem Operator zwei gemacht haben, das ist der Punkt an dem das zusammenläuft. Da hätte man dann einen Branch in dem _wir zurren das zusammen_ Repo und kann dann beide Änderungen dort machen. Wenn wir sagen okay, statt dem einen großen nehme ich jetzt den einen dazu und den anderen dazu und das lebt dann selbst wieder als ein Branch und kann man als eine Änderung ausrollen.
R1: Ist das ein Tool von euch oder? Dieses API-Stack.
I9: Das heißt nur so. Oder diese Entität heißt so. Das Tool, was wir dafür benutzen ist Helm. Hätte ich vielleicht auch erwähnen können. Helm bezeichnet sich als der Paketmanager für Kubernetes. Das ist im Prinzip sowas wie kubectl mit Templating. Also das war auch das, was ich vorhin meinte mit diesem Templating-Mechanismus. Man kann Templates schreiben, dann kann man sagen ich habe ein Volume und einen Pod und einen Service oder sowas. Schreibt da irgendwelche Templatewerte rein für die Sachen, die variabel sein sollen oder kodiert die Sachen, die hart sind und kann dann dieses Template instantiieren.
R1: Und das ist auch ein Configuration-File praktisch dann?
I9: Genau, also die Konfiguration, die man in diese Templates-Engine reingibt, ist auch eine Konfiguration. Und das ist unser Mechanismus um Sachen zusammenzuzurren. Zum Beispiel eben dieser Schwarm an Operatoren. Den zurren wir mit Helm zusammen.
R1: Und diese Konfiguration liegt im Repo, oder? Die für Helm oder die für Helm-Templates.
I9: Bisher ist es so, dass man diesen API-Stack nur einmal deployen kann pro Kubernetes-Cluster. Der ist, die Sachen, die da drin deklariert sind, sind nicht alle konsequent genamespacet. Das ist nur ein, dieser Deployment-Mechanismus, aber wir benutzen die Templatisierung nicht um mehrere Instanzen des gleichen im selben Cluster zu haben. Aber es gibt, wir haben verschiedene Kubernetes-Cluster. Es gibt einen für, oder es gibt mehrere für während der Entwicklung, dann einen Preproduction und Production und zwischen denen gibt es auch noch mal Unterschiede. Zum Beispiel nur die Production-Umgebung arbeitet mit unserem Authentication-Service, der auch die echten Credentials hat und die anderen gehen auf so ein Testsystem. Das ist zum Beispiel eine Konfiguration, die dort auch einfließt und die umgebungsabhängig ist.
R1: Was ist denn der größte Faktor, der den Konfigurationsaufwand bei euch bestimmt? Was dauert da, was ist der Faktor, der dafür sorgt, dass es so aufwändig ist zu konfigurieren?
I9: Wahrscheinlich das System, was wir betreiben wollen. Das ist halt im Endeffekt mein Job so als Ops-Guy, sind wir dem ein bisschen ausgeliefert, was wir halt tun müssen. Insofern, das ist wahrscheinlich in der Hinsicht eine ganz andere Perspektive, als das wahrscheinlich bei BX ist, der halt tatsächlich das System baut, was dann konfigurierbar ist und wir müssen irgendwie mit mehr oder weniger mit klar kommen, was die uns über den Zaun werfen. Ganz so ist es nicht, aber so vereinfacht gesagt. Wir können auch, also was wir auch machen ist, für Sachen wo man feststellt, bestimmte Sachen, die in unseren First-Party-Datacentern funktionieren, funktionieren in unserer Public Cloud nicht. Zum Beispiel Multicast geht nicht, wenn du, also das nutzt halt irgendwie auf Ethernet-Ebene so Broadcastmechanismen, die in so virtualisierten Umgebungen nicht da sind und nicht funktionieren. Dafür braucht man einen anderen Mechanismus. Also es gibt schon Sachen, die wir auch zutückfließen lassen, die wir in unserem Team entwickeln und in das Produkt, was wir betreiben, das ändern wir auch, so dass wir es besser betreiben können. Braucht auch wieder eine eigene Konfiguration. Da muss man dann sagen hey, wir wollen anderes Messaging benutzen und hier sind deine Credentials um stattdessen mit dem Messaging von Google zu sprechen zum Beispiel. Also es gibt da so ein bisschen bidirektionalen Flow, aber das betrifft wenige Sachen. Die meisten Sachen nehmen wir as is.
R1: Benutzt ihr eigentlich auch Konfigurierbarkeit um nicht-funktionale Eigenschaften, wie Performance zu tunen?
I9: Ja.
R1: Und — sehr schön — wie sieht das denn aus? Also tut ihr euer, also ändert ihr häufig Konfiguration dafür und wie wichtig ist das?
I9: Das geht ehrlich gesagt gerade erst los. Wir haben halt angefangen mit diesen schon beschriebenen Sandboxen, was halt so relativ kleine Entwicklungsumgebungen sind und wir wollen perspektivisch natürlich all unsere Umgebungen, also auch echte Productionsysteme, die ganz andere Performance-Charakteristika haben, wollen wir auch mit der selben Plattform und der selben Technologie und der selben Logik und alles wollen wir das betreiben können, so dass es im Endeffekt aus Kundensicht oder aus — naja, der Kunde wird das nicht selber einstellen —, aber aus derjenige, der eine Anfrage an unser System macht _fahr mal einen Shop hoch_, der sagt dann das ist von der Art Production. Und daraus sollten dann bestimmte Sachen abgeleitet werden. Ich weiß nicht genau in welche Richtung, ob man dann auch noch sowas machen würde wie, der Kunde ist jetzt _Enter your T-shirt size here_, dass da irgendwie S, M, L oder irgnendsowas oder ob man komplett uns darauf verlassen, dass wir herausfinden, wie man Autoscaling macht, so dass das auch robust genug ist. Das ist noch nicht entschieden, ob dem quasi Hints geben sollte oder ob das System idealerweise — idealerweise sollte es sich selbst konfigurieren, aber ob das robust genug ist müssen wir noch herausfinden, aber es gibt auf jeden Fall Sachen, die konfigurierbar sind und Einfluss auf non-functional Requirements haben.
R1: Gehen wir zu Konfigurationsfehlern über.
I9: Da war doch letztens was irgendwie von Cloudflare (https://new.blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019/). Die haben irgendwie so einen Regex falsch gesetzt und dann war das halbe Internet irgendwie — das war irgendwie vor ein paar Tagen, da war irgendwie das halbe Internet tot und betroffen waren alle, die Kunden von Cloudflare waren und Cloudflare hat irgendwie eine Konfigurationsproperty falsch gesetzt und dann — […] das war erst irgendwie vor ein paar Tagen.
[…]
R1: Stellt die Konfiguration euch denn bei Systemen, Tools und Frameworks und so weiter vor Probleme?
I9: Ich weiß nicht so richtig, wie ich darauf antworten soll, weil was wir bauen ist halt noch nicht — also ich werde nicht nachts rausgeklingelt wenn bei uns irgendwas klemmt, sondern im schlimmsten Fall schreie ich rüber zu meinem Nachbarkollegen und dann gucken wir mal zusammen rein. Also wir sind in einer Phase in der es zu erwarten ist, dass Sachen brechen, weil wir noch daran schrauben. Idealerweise ist es natürlich so, dass, oder es ist irgendwie so gebaut, dass Fehlkonfigurationen nicht erlaubt werden. Dass man, keine Ahnung, zum Beispiel whitelistet was sind denn valide Werte oder wenn jemand bestimmte Ranges für Zahlen angibt oder sowas. Irgendein Potential, dass man irgendwie foobar als Hostname für irgendwas hinschreibt und dann funktioniert das nicht, hat man natürlich immer. Weiß ich gar nicht, mich selbst, seitdem ich in meinem Team bin, fällt mir jetzt gerade kein Beispiel ein, wo ich mir, also neben der typischen Entwicklertätigkeit natürlich, dass man mal was probiert und das funktioniert nicht auf Anhieb oder man fummelt sich auch mal was kaputt, aber das ist jetzt typische Entwicklungsseiteneffekte, das würde ich jetzt nicht als wirklich _das hat mich jetzt irgendwie eine Nacht gekostet_ oder so beschreiben. Also ich sehe das Risiko auf jeden Fall, war aber noch nicht davon betroffen.
R1: Was sind denn deiner Meinung nach die schwerwiegendsten Probleme im Zusammenhang mit Konfiguration, die auftreten können?
I9: Miskonfigurationen. Na die Frage ist natürlich einmal, _wer_ darf etwas ändern. Das ist zum Beispiel schon mal eine Frage, also da spielt irgendwie Security eine Rolle um zu vermeiden, dass irgendjemand, der vielleicht keine guten Absichten hat — also das ist ein Thema. Das versuchen wir so ein bisschen mit role-based Access Control und sowas da Einschränkungen zu machen. Ansonsten, man darf natürlich nichts Falsches reinschreiben, das war das, was ich gerade schon gesagt habe. Dafür sehen wir halt idealerweise zu, dass möglichst wenig händisch einzustellen ist. Das meiste sollte halt möglichst automatisch provisioniert werden und sich selbst mit irgendeiner Art, man sagt Service-Discovery oder sowas, sich selbst publik machen _Ich bin da und das ist mein Hostname_ und der wird halt irgendwie mechanisch da irgendwie eingetragen ohne, dass da jemand sich abtippt und dann einen Typo reinmacht. Also Automatisierung ist — na gut, du hast nach Problemen gefragt, das ist die Lösung. Naja. Keine Automatisierung ist ein Problem, sagen wir es so.
[Unterbrechung]
R1: Genau, ein schwer zu konfigurierendes Tool oder Framework?
I9: Mir fällt ein gutes Beispiel ein von meiner alten Firma. Also das ist nicht meine aktuelle Rolle. In meiner alten Firma war ich in einem Team und wir haben die Build- und Deploymentautomatisierungstools gebaut. Das war ein ähnliches System, irgendwie großes monolithisches System. muss irgendwie jede Menge Javacode kompiliert werden in der richtigen Reihenfolge irgendwie zusammengesteckt werden. Dann Deployment ist irgendwie Zip-Files auspacken und Placeholder ersetzen oder Properties-Files setzen oder verschiedene Arten von Files, in Files rumfummeln und das irgendwie alles an die richtige Stelle legen und dann noch paar Executable Bits setzen und hoffentlich fährt es dann irgendwie hoch und da haben wir wieder relativ ähnliche Probleme wie man sie vorhin hatten, dass du sagst es gibt einmal Buildtime-Konfiguration und dann Deployments, wo liegt die Datenbank und Build- und Deploymenttooling ist natürlich ein cooler Kandidat, weil alle Entwickler müssen das benutzen. Das ist jetzt nicht, dass du sagst du trainierst halt deine drei Experten, die dort irgendwie die magischen Knöpfe drücken und die wissen das dann wie das funktioniert und dann ist gut, sondern du musst _jedem_ erklären wie es funktioniert. _Jeder_ muss das verstehen und jeder muss das auch tagtäglich benutzen, da kommt er nicht drum rum. Entsprechend groß war natürlich auch so ein bisschen der, ja das Potential, das Sachen schiefgehen und dann haben wir uns vielleicht auch, ja, nicht auf Anhieb alles mit mega guten Fehlermeldungen versehen und nicht alles war so mega intuitiv beim ersten Wurf. Das war halt irgendwie so, also in gewisserweise ein Greenfield-Approach, wir haben tatsächlich so alles wie man Code zusammensteckt und so, diesen Teil komplett neu gemacht. Die Software um die es ging, das war die gleiche, aber alles drumherum haben wir komplett neu gemacht. Ja, das war halt ein großes (?02:17). Konfiguration spielte auch eine zentrale Rolle, das ist halt so das, was der — in unserem Fall war der erste Stakeholder mit dem wir zu kämpfen hatten, waren die Inhouse-Entwickler und ja, da hat das Telefon oft geklingelt. Wir hatten uns da versch— so rückblickend muss ich auch sagen, wir hatten uns damals ein Tool hatten wir Gradle genommen und Gradle benutzt Groovy als DLS. Und idealerweise schreibt man das so, dass da überhaupt kein Code drin ist. Kein For-Each, kein While, kein If, kein irgendwas, sondern du kannst einfach schreiben geschweifte Klammer auf, Name ist gleich foo und Port ist gleich 0815 oder kannst irgendwie, wie eine Art Propertiesfile, so komplett deklarativ schreiben. Das war unsere erste Idee wie wir das machen würden. Dann haben wir festgestellt irgendwie kapieren die Leute das nicht, das war denen zu kompliziert. Dann haben wir irgendwie versucht zu vereinfachen. Dann haben das getemplatet, haben irgendwie gesagt, wir haben jetzt ein Propertiesfile, da musst du ein Subset dessen, was du brauchst, also das Subset dessen, was du als Entwickler wirklich tatsächlich ändern musst, das kannst du in dem Propertiesfile und wird daraus dieses andere File generiert. Das hat dann wiederum zu Verwirrung geführt, was ist jetzt wo und wie korrespondieren die zwei Files zueinander. Das war alles so ein bisschen, naja, und in gewisserweise auch dem geschuldet, dass das System, was konfiguriert werden musste auch zu kompliziert war. Also das hat dann selbst auch irgendwie — da gab es das eine Propertiesfile, da stand irgendwie der Datenbank, die Datenbankverbindung drin, im anderen stand drin auf welchem Port soll das lauschen, für einkommende Request und in einem anderen File steht irgendwie wie ist dein Fully Qualified Domainname, den du dann für URLs rausgeben — das stand alles irgendwie kreuz und quer auch in verschiedenen Files. So nachträglich denke ich mir, das beste wäre es gewesen, wenn unser Deploymenttooling fast gar keine Konfiguration gehabt hätte und man einfach ein Propertiesfile reincopypastet in das Zielssystem und das liest das einfach direkt aus. Dann hast du ein File und Propertiesfile ist eine flache Liste, das verstehen irgendwie die meisten Entwickler. Also gerade so Java-Entwickler, dem kannst du mit Propertiesfiles irgendwie kommen und dann stehen da halt zehn Properties drin und für acht gibt es vielleicht sogar ein Defaultvalue und das wäre irgendwie eine coole Lösung gewesen und wir haben uns für die more sophisticated Variante entschieden, die auch für andere Szenarien ihre Berechtigung hätte, aber für _ich will als Entwickler mal was hochfahren_, das ist halt ein anderes Szenario als _ich will es wirklich produktiv betreiben in einer geclusterten Umgebung_ und so. Und ja, da gab es viel Reibung.
R1: Ist eigentlich bei euch, wenn ihr jetzt die Konfiguration von interagierenden Tools und Frameworks problematisch. Also wenn das eine konfiguriert und das interagiert mit dem anderen. Ist das problematisch oder ist das?
I9: Wollen wir bei irgendeinem Beispiel bleiben.
R1: Jaja, Beispiele sind gut.
I9: In der Kuberneteswelt würde ich sagen ist es relativ gut gelöst dadurch, dass man halt relativ klar definiert hat, welche Schnipsel Logik hören auf welche Daten und produzieren welche anderen Daten. Das ist halt so, wenn man das mal einfach nur so als Black Box betrachtet, so die lesen irgendwas und schreiben irgendwas. Und jemand anderes liest dann vielleicht das Geschriebene und das ist dann so eine Art Kettenreaktion. Da hat man das einigermaßen definiert, wie so die Kollaboration des Gesamtsystems ist. Ein anderes Beispiel wo es nicht gut funktioniert hat, war ja das, was ich gerade beschrieben habe, dass man gesagt hat, wir haben irgendwie ein Propertiesfile und templaten daraus ein anders und dann gibt es aber auch so einen komischen Abstraktionsmismatch, dass man sich wundert, warum funktioniert das eine in dem einen und dem anderen kann ich das aber nicht einstellen. Und das war so ein Fall — ja, hab jetzt nicht spontan eine gute Lösung, wie man das stattdessen hätte machen sollen, aber ja. Also gerade wenn es irgendwie technologieübergreifend ist oder so, gibt es da immer Potential, dass da Sachen sich unerwartet verhalten.
R1: Was sind denn für dich Konfigurationsfehler und wie unterscheiden die sich von normalen Bugs?
I9: Na erstmal, die Frage ist, der Debuggingprozess bis man weiß woran es wirklich liegt, ist wahrscheinlich relativ ähnlich. Man merkt halt irgendwas verhält sich komisch und versucht dann zu graben und zu graben und zu graben und irgendwann merkt man dann entweder da ist ein Bug in meiner Logik oder meine Logik verhält sich genau richtig, aber liest einen falschen Wert oder sowas. Insofern bis dahin ist es wahrscheinlich relativ ähnlich. Die Frage ist natürlich wie man dann damit umgeht oder wie man es löst. Bugs sind halt tendenziell — oder Konfiguration ist halt eine Art von Daten und Bugs sind tendenziell, die sich auf Logik beziehen. Das ist wahrscheinlich so der große Unterschied. Also eine Konfigurationsänderung, also wenn es einen Konfigurationsfehler gibt, der Probleme nach sich zieht, würde man die Konfiguration wahrscheinlich ändern und das ist ja eine Datenänderung, die — kommt drauf an, wie die Daten zustande kommen, wir haben ja schon über Automatisierung gesprochen oder so. Vielleicht auch irgendwelche Änderungen im Git oder so nach sich zieht. Oder vielleicht kann man es auch irgendwie händisch machen, aber — ach, eigentlich ist das alles Mist, wenn man irgendwie händisch Zeug macht. Das fetzt nicht. Klingt nach einer guten Quelle für Konfigurationsfehler: Wenn man Sachen händisch macht.
R1: Welche Auswirkungen von Konfigurationsfehlern sind denn häufig bei euch? Also vielleicht, weil ja gerade ja — du hast ja vorhin gesagt, dass, dann probiert man was rum. Was sind dann die häufigsten Auswirkungen?
I9: Es funktioniert nicht. Bei Kubernetes ist es häufig so, wenn man sich darauf verlässt, dass Sachen da sind, wenn man auf irgendwas zugreifen will und das gibt es nicht, dann hängt es halt. Dann versucht es das halt dann irgendwann noch mal und versucht es noch mal und tut aber erstmal nicht viel. Eine Sache über die ich letztens gestolpert war, war es gibt nämlich einen Mechanismus, dass man sagen kann bevor ich ein Objekt löschen kann, müssen noch bestimmte Sachen passieren. Und das ist so eine Liste, das nennt sich Finalizers und da schreibt man eigentlich nur eine ID rein. Und die ID ist so eine Art Referenz auf mich selbst. Ich als im Sinne eines Operators und der Operator muss dann schauen, hier wird verlangt, dass gelöscht wird, aber meine ID steht noch drin, dann tue ich was auch immer zu tun ist, zum Beispiel Datenbankuser droppen und nehme dann meine ID raus. Und wenn diese Logik aber einen Bug hat und der diese Objekt nie rausnimmt, kann das Objekt nie gelöscht werden. Und dann hat man so ein baumelndes Objekt rumliegen, was eigentlich ein Ergebnis von buggy Code ist, aber dazu führen kann, dass ein Stück Datenobjekt, was vielleicht auch eine Konfiguration ist, nicht ordnungsgemäß weggeräumt werden kann. Dass man so einen inkonsistenten, hängenden Zustand kommt.
R1: Gibt es denn einen Unterschied zwischen falscher und schlechter Konfiguration?
I9: Ja, denke ich schon. Also ein klassisches Beispiel von schlechter Konfiguration sind Sachen, die zu detailliert sind für den Zweck. Es gibt Sachen wie, keine Ahnung, wenn wir jetzt von unseren Kunden erwarten würden, dass sie auswählen auf welche Datenbank sie gehen. Sagen wir, wir haben irgendwie drei Datenbanken. Welche willst du denn? Na, was weiß der denn? Der hat keine Ahnung, dass auf der einen tausend Nutzer sind und auf der anderen nur zwei. Dann würde man den tendenziell vielleicht lieber auf die leerere nehmen. Das weiß er nicht. Also Sachen, die man nicht wissen, plausibel annehmen kann, dass sie bekannt sind, sollte man nicht konfigurierbar machen. Oder Sachen, die derjenige vielleicht nicht konfigurieren können sollte. So zum Beispiel unsere Kunden sollten gar nicht wissen, was es überhaupt, wie unsere interne Netzwerktopologie aussieht oder sowas. Ja, ansonsten um mal auf das Beispiel vorhin zu kommen, auch so das Konfigurationsformat ist eine Frage. Propertiesfiles kann man einem Java-Entwickler zumuten, einem Businessnutzer vielleicht nicht. Aber keine Ahnung, sowas wie Groovy-DSL hat sich nicht wirklich bewährt. Das ist halt so ein klassischer Fall, wo du eigentlich einen IDE-Support brauchst, der irgendwas hast, was dir dann Autovervollständigung bietet. Ansonsten hast du keine wirkliche Chance überhaupt ein valides File zu erzeugen.
R1: Wenn wir an den Unterschied gehen, zu falscher Konfiguration könnte irgendwie was zum abstürzen bringen oder so. Schlechte vielleicht Performance. Siehst du das auch so, dass es da Unterschiede gibt oder sind das für dich eigentlich schon gleiche, kann man gleich bewerten?
I9: Die Konsequenz ist, dass irgendjemand anruft und in den Hörer schreit. Also häufig hängt es ja zusammen. Wenn du sagst du hast irgendwie schlechte Performance, dann merkst du das spätestens wenn mal ein bisschen Druck auf den Kessel kommt. Und dann ist das Ergebnis inzwischen ist es abgestürzt und die Performance ist zu schlecht als dass es überhaupt überleben kann. In gewisserweise auch marginal. Mit Sicherheit gibt es verschiedene Arten von Fehlermodi. Ein gutes Beispiel bei uns sind wahrscheinlich sowas, wie Fehler, die nur einen Kunden betreffen oder Fehler, die die ganze Plattform betreffen. Keine Ahnung, wenn zum Beispiel eine Datenbank abkachelt, sind halt alle Kunden, die betroffen sind, weg. Oder haben erstmal ein Problem versus Sachen, die doch eher ein bisschen isolierter sind, okay für den einen ist jetzt der Tag echt schlecht gelaufen, aber zumindest der Rest läuft weiter. Das sind Sachen, die schon irgendwie einen Unterschied machen. Das fiele mir jetzt ein, genau. In gewisserweise macht es auch einen Unterschied, ob es jetzt, keine Ahnung, Downtime ist, ist ein großes Problem. Das kann halt auch durch schlechte Performance versursacht werden. Also wie ich schon gesagt habe, der Unterschied zwischen zu langsam und ganz weg kann praktisch nicht existent sein. Versus — was gibt es noch? Datenverlust wäre natürlich ganz katastrophal. Das ist auf jeden Fall noch mal ein Unterschied zwischen in einer Stunde ist es wieder da und die Daten sind ganz weg. So das ist ein großer Unterschied. Das sind Sachen, die man natürlich in der Infrastruktur, wenn man tatsächlich mit dem Filesystem, das da tatsächlich direkt dranhängt oder so, wenn man derjenige ist, der das macht und man hat da einen Bug in seinem Code, dann hängt da gleich relativ viel dran. Ich habe letztens die Logik geschrieben, die Datenbankuser droppt und habe mir dabei auch so gedacht, das sollte nicht durch einen Bug ausversehen getriggert werden. Also da hängt echt was dran. So Datenbankuser droppen, das sollte robust sein.
R1: Hast du denn bereits Konfigurationsfehler erlebt oder kannst du von einem besonderen rekapitulieren. Muss jetzt nicht in deinem jetzigen Team sein.
I9: Um noch mal auf das andere Beispiel mit dem, in der alten Firma mit dem Build- und Deploymenttooling zu kommen, da gab es einen Fehler, der ist immer wieder passiert. Ständig. Irgendwann haben wir uns dann mal was anderes überlegt, wie man den ganzen Prozess ein bisschen anders aufzieht, sodass man den Fehler strukturell vermeidet, aber bis dahin ist der immer wieder passiert. Und zwar, das Gesamtsystem, habe ich ja gesagt, war ein großer Monolith mit irgendwie ganz vielen Komponenten. Und wir haben versucht einzelne Bündel zu machen, die Komponenten einzeln zu versionieren und dann war ein Problem wie stecken wir die so wieder zusammen, dass dann am Ende etwas lauffähiges rauskommt. Und da gab es unendlich viele Fälle, wo das Tooling seine Version nicht richtig eingetragen hat und dann haben plötzlich Sachen gegeneinander versucht zu kompilieren, die ganz verschiedene Versionen hatten und dann fliegt natürlich alles um die Ohren. Das ist unendlich oft passiert bis wir das irgendwann mal ganz anders aufgezogen haben und eins der Resultate war, dass wir auch viele Sachen wieder zusammengeworfen haben, wo wir festgestellt haben effektiv leben die eh zusammen, es macht jetzt relativ wenig Sinn die getrennt zu behandeln. Das ist halt so in einem monolithischen System.
R1: Hast du ja eigentlich schon gesagt, aber wie häufig treten Konfigurationsfehler bei euch auf? Also am Tag ein paar mal oder in der Woche ein paar mal?
I9: Für meinen Entwicklungsworkflow sehr häufig, wobei ich das wie gesagt nicht — das ist ja keine wirkliche Problemquelle. Es ist halt so mein eigenes —
R1: Wenn du das jetzt mal so schätzen würdest. Also was bedeutet sehr häufig? Das ist so ein bisschen…
I9: Das ist jetzt die Frage. Ist ein Konfigurationsfehler ein Ding bis ich es behoben habe, oder zählen alle Versuche mit denen ich versuche es zu beheben auch als noch mal falsch konfiguriert? Das ist halt zum Beispiel ein Beispiel. Also man probiert halt viel rum. Also als Entwickler ist man so interaktiv unterwegs und —
R1: Sind eigentlich auch Konfigurationsfehler, ja?
I9: Sind irgendwie auch Konfigurationsfehler, aber ist jetzt — der Impact ist halt marginal. Da hängt nichts dran. Das ist halt meine Arbeitszeit, aber dass ich nicht alles auf Anhieb mit ein paar mal in die Tastatur, niemals den Backspace-Knopf drücke, sofort hinkriege so, ist erwartet. Insofern, wirklich mit Betrieb und auch Auswirkungen für irgendjemanden außer nur mich alleine, wüsste ich gerade nicht. Ich glaube das betrifft mich in meinem aktuell Job gerade noch nicht. Mal gucken, wenn ich so zurückdenke — wie ich vorhin schon gesagt, dieses, in der alten Firma das Build- und Deploymentdings das ist, da hat mehrfach täglich irgendwie mein Telefon geklingelt, weil irgendein Entwickler geblockt war und sich selbst nicht zu helfen wusste und da musste ich dann hingehen und irgendwie selber Commandline-Magic um das irgendwie zu kitten. Das war sehr motivierend das zu lösen. Um das Problem aus der Welt zu schaffen.
[…]
R1: Gibt es generell Unterschiede bei Konfigurationsfehlern zwischen fachlicher und technischer Konfiguration?
I9: In gewisserweise ist die fachliche Konfiguration etwas, das bei meinem Team von außen kommt. Also in gewisserweise ist es not our problem. In anderer Weise natürlich dann schon, weil wenn es jemand versucht zu beheben, dann müssen wir ihm natürlich auch irgendwie die Mittel in die Hand geben, dass er es fixen kann. Wobei bei uns heißt das halt es gibt eine API um Sachen anzulegen und eine API um Sachen zu löschen. Also man kann Sachen auch wieder — Nutzer können Sachen auch selber wegräumen, insofern, das ist für uns relativ simpel.
R1: Wie geht ihr denn typischerweise vor um Konfigurationsfehler zu finden und zu beheben?
I9: Naja, finden ist halt, wie ich vorhin schon gesagt habe, so die klassischen Debuggingsachen so. Man wundert sich, irgendwas klemmt und man hat vielleicht gar keine konkrete Idee wo. Kommt halt immer auf das Tool drauf an. Wenn du jetzt — bei Kubernetes würdest du wahrscheinlich irgendwie kubectl und dann versuchen irgendwie in Sachen reinzugucken in so Objekte, okay was steht denn in dieser Configmap von der Datenbank drin, huch die gibt es ja gar nicht. Sowas in der Art. In der alten Firma gab es dann halt dafür andere Files. Da gab es dann irgendwie so ein so ein Propertiesfile, wo so Umgebungskonfiguration drin sind pro Entwicklungsumgebung. Also man konnte auf einem Rechner mehrere Entwicklungsumgebungen haben und so verschiedene Versionen und so. Aber jede Umgebung hatte so ein File, wo dann drinstand dein Datenbankschema, Username ist blablabla und sowas. Da hätte man klassischerweise reingeguckt und wie gesagt, das war halt das Quellfile aus dem dann templatisiert wurde. Jedenfalls musste man was an dem Templatisierungsmechanismus irgendwas, vielleicht buggy war, wenn man den Verdacht hatte, musste man schon, okay was wird denn aus diesem Propertiesfile, was wird daraus generiert? Stelle dann fest, huch, das Template stimmt gar nicht oder vielleicht wurde der Templatisierungsprozess nicht aufgerufen, das ist ja noch ein outdatetes File obwohl da eigentlich etwas anderes drinstand. Muss man sich dann halt so Stück für Stück durchhangeln. Ja, klassische Debugging—
R1: Macht ihr dann auch Google und StackOverflow auf um irgendwas zu fixen, oder?
I9: Ja, das betrifft halt nur Fremdsysteme. Wir haben halt für unsere internen proprietären Sachen gibt es natürlich keine Antworten auf StackOverflow. Wenn man den begründeten Verdacht zur Annahme hat, dass das Tool was wir benutzen sich vielleicht unerwartet verhält, ist das auf jeden Fall mit dabei, ja.
R1: Und Kollegen sprechen?
I9: Ja, doch das mache ich auch. Also klassischerweise Doku lesen, Kollegen fragen.
R1: Welche Strategien habt ihr denn um Konfigurationsfehlern vorzubeugen?
I9: Na, in gewisserweise hatte ich das schon so ein bisschen angesprochen. Wir versuchen irgendwie viele Sachen zu automatisieren. Möglichst wenig, dass da irgendjemand händisch irgendwelche IP-Adressen eingeben muss oder sowas. Das schreit nur danach, dass man sich vertippt. Viel Automatisierung. Verifikation. Dass man guckt, ist das überhaupt — also als der Konsument der Konfiguration — ist das plausibel oder habe ich alles, was mandatory ist, was ich brauche und wenn nicht, haben wir halt diesen Mechanismus, dass temporäre Miskonfiguration hoffentlich einfach nur dazu führt, dass nichts passiert und sobald das dann konfiguriert oder korrigiert ist, dass es sich selbst heilen kann.
R1: Okay, jetzt sind wir beim letzten Teil, (?22:16) Verbesserungsbedarf. Jetzt kannst du dir wirklich vorstellen du hättest jetzt ein paar Wünsche in Richtung Softwareentwicklung frei und ja, was würdest du dir denn zum Beispiel wünschen bezüglich einer guten Dokumentation von Konfiguration?
I9: Ja, Beispiele. Das erste was mir einfällt sind Beispiele. Ich merke gerade so ein bisschen — ich habe jetzt angefangen Go-Code zu schreiben und vorher habe ich Java gemacht und man kann jetzt über Java eine ganze Menge schimpfen. Dass irgendwie alles so ein bisschen, dass man ganz schön viel Tipparbeit machen muss, aber die Dokumentation von Java — hat jetzt relativ wenig mit Konfiguration zu tun, aber so generell Dokumentationsthema — ist sehr gut. Die sagt einem halt für jede Methode, die man aufrufen kann, okay der Parameter ist für das, der Parameter ist für das. Das sind typische Werte. Ein Beispiel eines Methodenaufrufs. Auch sowas wie, das wird niemals Null zurückgeben oder hier kannst du Null reinschreiben, oder das wird Null zurückgeben wenn das und das ist, sowas. Also so Nullability oder optionale Sachen sind so, das ist da echt explizit dokumentiert. Das steht immer dran, das darf nie Null sein oder das kann Null sein und dann passiert das und das so. Das ist in der Hinsicht sehr explizit und so die ganzen typischen Edgecases über die man stolpern kann, sind dort tendenziell bedacht und schon ausformuliert. Und das ist ein Beispiel, was ich zum Beispiel bei der Doku von Go nicht habe. Da steht dann halt drin ja, das macht das und das. Aber ja, was macht es denn wenn dort Nil reinkommt? Das heißt Nil statt Null, aber verhält sich genauso. Was macht es denn dann? Ja, da muss man dann halt durch den Code durchlesen, das steht nicht in der Doku drin. Das wären halt so klassische Sachen. Also einmal Beispiele geben. Nicht nur so abstrakt irgendwie, das muss jetzt ein blablabla, insert technischer Begriff here, sondern mal sagen okay, wie kann es denn konkret aussehen und so Edge Cases abhandeln. So ist das optional, ist das mandatory, wie verhält es sich, wenn es optional ist aber nicht da ist? Was passiert dann? Was für eine Konsequenz hat das? Sowas explizit behandelt zu sehen finde ich sehr hilfreich.
R1: Kennst du aus deiner Erfahrung Beispiele für eine gute Dokumentation von Konfigurationsoptionen speziell? Oder eine schlechte?
I9: Ja, tatsächlich. Mir fällt als Beispiel ein, noch mal auf die alte Firma bezogen, wir haben als Tooling um unser Build und Deployment zu machen, haben wir Gradle benutzt. Und Gradle selbst hat eine ziemlich gute Dokumentation. Das ist so eine Webseite, die kann man sich angucken. Die ist versioniert je nach Gradle-Version, kann man sagen ich habe Gradle-Version bla und dann sieht man die Doku dafür. Und die Dokumentation selber ist, also da ist auch jede Menge Konfiguration. Also Gradle selbst, man kann es programmieren, aber der Großteil der Sachen, die man erreichen will, würde man eher deklarativ machen. Ist also auch eher eine Konfiguration. Und die Doku hat jede Menge Codebeispiele und die haben einen sehr smoothen Move gemacht. Also erstens, die Dokumentation selbst liegt auch im selben Git-Repo wie das Tool selbst, was dokumentiert ist. Und alle Codebeispiele sind als Includes gemacht aus einem File und dasselbe File wird von Unittests bearbeitet. Das heißt die haben automatisierte Tests in ihrem Jenkins, die sagen ob die Code-Snippets, die in der Doku sind noch funktionieren und so Sachen. Weil das ist immer so der Klassiker, man refactort irgendwas und in der Doku steht aber noch ein Beispiel und alle Newbies copypasten das Beispiel, es geht nicht und sie haben aber keine Ahnung woran es liegt, weil ihnen das tiefere Hintergrundwissen fehlt, was sie genau durch die Doku hätten erlangen sollen, aber nicht können. So also das fiel mir als sehr positives Beispiel auf. Die haben sich da viel Mühe gegeben und die haben auch viel investiert, dass die Doku gut bleibt.
R1: Besonders schlechte Doku?
I9: Ja, ich habe jetzt schon die Go-Doku angesprochen so als — ich weiß jetzt nicht, ob es die schlechteste Doku aller Zeiten ist. Die schlechteste Doku aller Zeiten ist natürlich immer keine Doku, aber sie ist auf jeden Fall im Vergleich zu dem, was man von Javadoc gewöhnt ist, nicht so gut.
R1: Wenn du jetzt Kubernetes ansprichst — viel angesprochen hast — wie findest du da die Doku?
I9: Die ist tatsächlich relativ gut. Für jeden Typ von Objekt, den es da geben kann, gibt es einmal dieses Schema, was ich schon erwähnt hatte, das ist so in YAML definiert und für jedes Field gibt es auch eine Long Description. Und daraus gibt es auch irgendwie so eine Website, die so ähnlich ist wie das, was ich von Gradle gesagt habe. Da gibt es halt einen Versionsschalter, kann man sagen für welche Version von Kubernetes und dann steht halt da okay, es gibt diese Typen und wie verhält der sich, welche Konsequenz hat das, wenn ich ein Objekt von diesem Typ anlege? Was ist mandatory, was ist optional? Was ist deprecated, was ist noch beta? Genau, würde ich als eine der besseren bezeichnen.
R1: Okay, welche Verbesserungen würdest du dir hinsichtlich der Konfiguration von Softwaresystemen und Frameworks und Tools wünschen? Also richtig so frei aus dem Bauch heraus. Was dir dein Leben mit Konfiguration verbessern könnte.
I9: Ich finde den Ansatz von — oder was ich sagen kann, den Ansatz von Kubernetes finde ich einen der besseren. Dass man eine Art zentralen Datastore hat in dem Sachen zusammenlaufen, dass man immer weiß okay, wo schaue ich denn auch nach. Dass man nicht erst anfangen muss zu graben okay, wo steht das jetzt? Das steht halt garantiert irgendwo dort. Dass man automatisch darauf reagieren kann auf so Events und dass man auch automatisch Sachen eintragen kann. Also das ist eine der besseren Sachen, die mir aufgefallen ist. Was ich mir darüber hinaus wünschen würde weiß ich gar nicht. Es gibt halt je nach Anwendungsfall wünscht man sich vielleicht mal zum Beispiel, dass es ein festes Schema gibt und für manche Sachen, wo man sagt wir sind noch so ein bisschen am prototypen, wissen vielleicht noch nicht so genau, sagt man okay, wir nehmen einfach eine Map. Da ist jetzt nicht klar deklariert welche Keys müssen da drinstehen. Das ist halt erstmal unstrukturiert. So dieses Spektrum hat man, das kann man beides machen. Tendenziell wird man halt vielleicht eher mit einer Map anfangen und dann irgendwann, wenn das sich konkretisiert hat, dann in ein wirklich strukturiertes Objekt überführen, wo man dann einzelne Fields auch dokumentieren und mandatory, beta, et cetera machen kann. Dieses Spektrum ist nett zu haben, kann es aber auch — es gibt auch die Wahl zwischen flachen Listen oder hierarchisch strukturierten Daten.
R1: Was würde dir denn helfen schneller vielleicht Fehler zu finden, Konfigurationsfehler oder die schneller zu beheben? Gibt es da irgendwas, was dir helfen würde?
I9: Am besten ist es immer, wenn es leicht verständlich ist. Quasi der, wenn sich Datenfluss leicht nachvollziehen lässt. Wen man weiß, okay, diese Einstellung Auswirkung auf X, Y und Z oder umgedreht, wenn Z gewackelt hat, dann kann das zum Beispiel an X gelegen haben. Solche Flüsse zu visualisieren, das versuche ich auch so ein bisschen mit den Operators, die die Logik sind. Dass man das klug durch Logging macht. Dass man immer Logging sagt, okay, weil jetzt ein Objekt mit dem Namen, und dann schreibt man seine ID rein, angelegt wurde, mache ich jetzt das und das und schreibe wieder die ID hin um so die Verbindung zwischen Sachen herstellen zu können, dass man dann sich von Hopp zu Hopp navigieren kann, wenn man irgendwie auf Fehlersuche ist. Also Transparenz herstellen im weitesten Sinne ist denke ich das sinnvollste, was man tun kann.
R1: Okay und vielleicht noch als letztes, irgendwas was dir hilft irgendwie Konfigurationsfehler vorzubeugen, was es vielleicht noch nicht so gibt oder?
I9: Ist jetzt so ein Unknown Unknown. Ich weiß nicht, was es noch nicht gibt. Ich weiß halt was es gibt und was irgendwie vielleicht eine gute oder eine schlechte Idee ist. Ich weiß, ja, (?30:52) halt irgendwie Konfigurationsfeldern Attribute zu geben. Sowas wie ist das optional oder nicht. Ist es deprecated oder nicht. Kubernetes sagt auch noch ist das Beta oder nicht. Also ist es ganz neu und vielleicht ändert es sich noch mal oder ist es stable, dann lassen wir es sehr lange Zeit so. Sowas explizit dranzuschreiben, zu deklarieren wo muss man vorsichtig sein und auf was kann sich verlassen. Das ist auf jeden Fall hilfreich. Also falls irgendwie was total magisches um die Ecke kommt, dann würde ich das natürlich auch mal ausprobieren, aber fällt mir jetzt aus dem Kopf nichts ein.