Thorsten Hans: Formula 1 Calendar 2023: All Races Detailed

Red Bull Racing clearly leads the pack as the team to beat in the 2023 Formula 1 season. This became even more evident when their main competitors, Ferrari and Mercedes, encountered significant challenges during the 2023 pre-season tests, especially in race simulations. Sergio Perez of Red Bull demonstrated consistent speed over race distances, while George Russell of Mercedes lagged behind by nearly nine-tenths on average. Nevertheless, Ferrari appears to be closing the gap to Red Bull’s championship-winning team. Both Carlos Sainz and Charles Leclerc of Ferrari struggled to match the pace set by Red Bull’s drivers. This is notably disheartening for Charles Leclerc, who has his sights set on the 2023 championship title, a feat Ferrari hasn’t achieved since Kimi Räikkönen’s triumph in 2007. The unfolding of the 2023 Formula 1 season remains to be seen. Below is a rundown of all F1 races scheduled for 2023.

List of Formula 1 Races in 2023

Here’s a chronological overview of all F1 races for the year 2023:

Nr.Grand PrixDateCET Start Time
1Bahrain / Sakhir05.03.202316:00
2Saudi Arabia / Jeddah19.03.202318:00
3Australia / Melbourne02.04.202307:00
4Azerbaijan / Baku30.04.202313:00
5USA / Miami07.05.202321:30
6Italy / Imola21.05.202315:00
7Monaco / Monte Carlo28.05.202315:00
8Spain / Barcelona04.06.202315:00
9Canada / Montreal18.06.202320:00
10Austria / Spielberg02.07.202315:00
11Great Britain / Silverstone09.07.202316:00
12Hungary / Budapest23.07.202315:00
13Belgium / Spa-Franchorchamps30.07.202315:00
14Netherlands / Zandvoort27.08.202315:00
15Italy / Monza03.09.202315:00
16Singapore17.09.202314:00
17Japan / Suzuka24.09.202307:00
18Qatar / Doha08.10.202316:00
19USA / Austin22.10.202321:00
20Mexico / Mexico City29.10.202321:00
21Brazil / Sao Paulo05.11.202318:00
22USA / Las Vegas19.11.202307:00
23United Arab Emirates / Abu Dhabi26.11.202314:00

Streaming Formula 1 Races in 2023 for Free

This year, there are plenty opportunities to watch Formula 1 races for free abroad. Using a robust and reliable VPN service like NordVPN or CyberGhost makes this seamless. You can enjoy F1 races with commentary in German, Belgian, French, Luxembourgish, and other languages from abroad through a VPN.

Formula 1 Drivers and Teams for the 2023 Season

There have been significant changes for German Formula 1 fans compared to last year. Sebastian Vettel has retired, and Mick Schumacher has been replaced by Nico Hülkenberg at Haas. For this season, Schumacher serves as a reserve driver for Mercedes.

TeamDriver 1Driver 2
Red BullMax VerstappenSergio Perez
MercedesLewis HamiltonGeorge Russell
FerrariCharles LeclercCarlos Sainz
AlpineEsteban OconPierre Gasly
McLarenLando NorrisOscar Piastri
Alfa RomeoValtteri BottasGuanyu Zhou
Aston MartinFernando AlonsoLance Stroll
HaasKevin MagnussenNico Hülkenberg
AlphaTauriNyck de VriesYuki Tsunoda
WilliamsAlexander AlbonLogan Sargeant

Formula 1 Results from the Previous Year

Last year, Max Verstappen of Red Bull claimed the World Champion title once again. Here’s a summary of the races from the previous year, including the winners of each Grand Prix.

Nr.RaceWinner
1SakhirCharles Leclerc – Ferrari
2JeddahMax Verstappen – Red Bull
3MelbourneCharles Leclerc – Ferrari
4ImolaMax Verstappen – Red Bull
5MiamiMax Verstappen – Red Bull
6BarcelonaMax Verstappen – Red Bull
7MonacoSergio Pérez – Red Bull
8BakuMax Verstappen – Red Bull
9MontrealMax Verstappen – Red Bull
10SilverstoneCarlos Sainz – Ferrari
11SpielbergCharles Leclerc – Ferrari
12Le CastelletMax Verstappen – Red Bull
13BudapestMax Verstappen – Red Bull
14SpaMax Verstappen – Red Bull
15ZandvoortMax Verstappen – Red Bull
16MonzaMax Verstappen – Red Bull
17SingaporeSergio Pérez – Red Bull
18SuzukaMax Verstappen – Red Bull
19AustinMax Verstappen – Red Bull
20Mexico CityMax Verstappen – Red Bull
21São PauloGeorge Russell – Mercedes
22Abu DhabiMax Verstappen – Red Bull

Formula 1 Driver Standings for the 2022 Season

Here’s a summary of the driver standings from the previous year, with Max Verstappen securing the Formula 1 World Championship title with 454 points.

PlaceNameNationTeamPoints
1Max VerstappenNetherlandsRed Bull454
2Charles LeclercMonacoFerrari308
3Sergio PérezMexicoRed Bull305
4George RussellUKMercedes275
5Carlos SainzSpainFerrari246
6Lewis HamiltonUKMercedes240
7Lando NorrisUKMcLaren122
8Esteban OconFranceAlpine F1 Team92
9Fernando AlonsoSpainAlpine F1 Team81
10Valtteri BottasFinlandAlfa Romeo49
11Sebastian VettelGermanyAston Martin37
12Daniel RicciardoAustraliaMcLaren37
13Kevin MagnussenDenmarkHaas F125
14Pierre GaslyFranceAlphaTauri23
15Lance StrollCanadaAston Martin18
16Mick SchumacherGermanyHaas F112
17Yuki TsunodaJapanAlphaTauri12
18Guanyu ZhouChinaAlfa Romeo6
19Alex AlbonThailandWilliams4
20Nicholas LatifiCanadaWilliams2
21Nyck de VriesNetherlandsWilliams2
22Nico HülkenbergGermanyAston Martin0

The post Formula 1 Calendar 2023: All Races Detailed appeared first on xplatform.rocks.

Holger Schwichtenberg: Neu in .NET 8.0 [10]: Plattformneutrale Abfrage der Privilegien

In der Klasse System.Environment hat Microsoft in .NET 8.0 die Eigenschaft IsPrivilegedProcess hinzugefügt.

Code-Inside Blog: First steps with WinUI 3

Developing desktop apps for Windows is quite complex in 2024. There are some “old school” frameworks like WPF or WinForms (or even older stuff) and there is this confusing UWP (but I think it’s dead). The “modern stack” seems to be WinUI - so let’s take a look.

x

See here

What is WinUI?

WinUI is the “modern” version of WPF without the (dumb?) constraints from UWP. You can of course use your typical “Windows” programming languages (like C# or C++).

If you heard of UWP. The “Universal Windows Platform” was a good idea but failed, because - at least from my limited testing - the platform was very strict and you couldn’t do the same stuff that you can do with WPF/WinForms.

WinUI 1 and 2 were targeted at UWP (if I remember correctly) and with WinUI 3 Microsoft decided to lift those UWP constraints and with it we get a modern desktop stack based on the “known” XAML.

In summary:

WinUI 3 apps can be used for apps that run on Windows 11 and Windows 10 and can be distributed via the Microsoft Store and you can do the same crazy stuff that you love about WPF/WinForms.

Does anybody outside of Microsoft use WinUI?

WinUI is used in Windows 11, e.g. the settings or the new explorer - which is nice, but it would be good, if we found a non-Microsoft app that uses this tech, right?

Thankfully last week Apple decided to release Apple Music (and other apps) as a native Windows app and it seems (this is not confirmed by Microsoft or Apple) like it was written with WinUI:

x

If Apple uses this tech, it seems “safe enough” for some exploration.

How to get started?

You will need Visual Studio 2022. Be aware, that even if you check all those desktop related workloads in the installer the WinUI 3 templates are still missing.

x

For the WinUI 3 templates you will need to install the Windows App SDK.

Visual Studio Templates

After the Windows App SDK is installed we finally have the templates in Visual Studio:

x

The default Blank App, Packaged (WinUI 3 in Desktop) is… well… quite blank:

x

If you start the application, you will see this:

x

Packaged vs. Unpacked

If you check the toolbar, you will notice the App 6 (Package) debug button. Packaged Apps can access some Windows APIs (e.g. custom context menu extensions) that Unpackaged Apps can’t. Unpackaged Apps on the other hand act like WPF apps - e.g. they have a “normal” .exe and can be distributed like any .exe-file.

This documentation page should cover this topic.

Let’s say we want to have a “proper” myApp.exe app, then the Unpackaged App is the way to go. If you choose the App 6 (Unpackaged) debug option you might see this weird error:

XamlCheckProcessRequirements();

Exception Unhandled:
System.DllNotFoundException: 'Unable to load DLL 'Microsoft.ui.xaml.dll' or one of its dependencies: The specified module could not be found. (0x8007007E)'

To fix this, you will need to add this to the .csproj:

	<PropertyGroup>
		...
		<WindowsPackageType>None</WindowsPackageType>
        ...
	</PropertyGroup>

After that the debug button should start the application and you should be able to start the .exe.

Samples

Ok, the most basic steps are done - now what?

To get a feeling about what is possible and what not, you should install the WinUI 3 Gallery app.

x

This application should give a some guidiance.

Hope this helps!

Note: I’m a beginner with WinUI 3 and just want to show other people the first few steps - if I miss something, just write me a comment! Thanks <3

Holger Schwichtenberg: Neu in .NET 8.0 [9]: Neue und erweiterte Datenannotationen

In .NET 8.0 hat Microsoft die Annotationsklassen im Namensraum System.ComponentModel.DataAnnotations erweitert.

Holger Schwichtenberg: Neu in .NET 8.0 [8]: Verbesserungen für nameof() in C# 12.0

Der in C# 6.0 eingeführte Operator, der den Namen eines Bezeichners als String liefert, hatte bisher einige Einschränkungen, die in C# 12.0 entfallen.

Golo Roden: Vanilla-Web: Der Frontend-Trend 2024?

Die Entwicklung von Web-UIs erfordert zu viele Frameworks und Tools, die zudem aufwendig und komplex zu integrieren sind. Könnte sich das im Jahr 2024 ändern?

Holger Schwichtenberg: Neu in .NET 8.0 [7]: Optionale Parameter in Lambda-Ausdrücken in C# 12.0​

Die aktuelle Version von Microsofts Programmiersprache C# erweitert sowohl reguläre Lambdas als auch Statement Lambdas.​

Holger Schwichtenberg: Neu in .NET 8.0 [6]: ref readonly in C# 12.0

In der aktuellen Version von C# lassen sich Methodenparameter als unveränderlich deklarieren.

Code-Inside Blog: How Windows locates an executable via PATH or App Paths

If you’ve ever worked with the Windows operating system, especially in a programming context, you might have used the Process.Start(yourapp) (e.g. Process.Start(Outlook)) method in languages like C#. This method is used to start a process - essentially to run an executable file. But have you ever stopped to think about how Windows knows where to find the executables you’re trying to run? Let’s dive into the inner workings of Windows and uncover this mystery.

Understanding the PATH Environment Variable

One of the first things that come into play is the PATH environment variable. This variable is crucial for the operating system to locate the executables.

What is the PATH Variable?

The PATH environment variable is a system-wide or user-specific setting that lists directories where executable files are stored. When you run a command in the command prompt or use Process.Start(...), Windows looks through these directories to find the executable file.

The PATH environment variable can be viewed via the system settings:

x

… there is also a nice editor now build into Windows for the PATH environment variable:

x

How Does PATH Work?

If the executable is not in the current directory, Windows searches through each directory specified in the PATH variable. The order of directories in PATH is important - Windows searches them in the order they are listed. If it finds the executable in one of these directories, it runs it.

However, the PATH variable isn’t the only mechanism at play here.

The Role of App Paths in the Windows Registry

Another less-known but equally important component is the “App Paths” registry key. This key is located in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths.

Understanding App Paths

The App Paths key is used to specify paths to specific applications. Each application can have its entry under the App Paths key, which means that Windows can find and run these applications even if their directories are not listed in the PATH variable.

x

How Do App Paths Work?

When you use Process.Start(...) and specify an application name like “OUTLOOK”, Windows first checks the App Paths registry key before it checks the PATH variable. If it finds an entry for the application here, it uses this path to start the application. This is particularly useful for applications that are not in common directories or have multiple executables in different locations.

Conclusion

Both PATH and App Paths play significant roles. While PATH is great for general-purpose directory searching (especially for system utilities and command-line tools), App Paths is more specific and tailored for individual applications.

There are probably even more options out there besides PATH and App Paths - Windows is full of hidden gems like this 😉.

Fun fact: I only discovered App Paths while debugging a problem. We use Process.Start(OUTLOOK) to start Microsofts Outlook Client and I was wondering why this even works.

Hope this helps!

Holger Schwichtenberg: Kostenloser Vortrag zu den Neuerungen in .NET 8.0 und C# 12.0 am 31. Januar

Die Vorträge in Ratingen behandeln die Neuerungen in der Syntax von C# 12.0 sowie in ASP.NET Core 8.0, Blazor 8.0 und Entity Framework Core 8.0.

Code-Inside Blog: .NET ('.NET Core') and Proxy Settings

If your .NET (“.NET Core”) program is running on a system that specifies strict proxy settings, you must either handle these settings in your application itself or use these environment variables.

Since I had this problem from time to time and the procedure was not 100% clear to me, I am now recording it here on the blog.

“DefaultProxy”

If you don’t specify any proxy, then the DefaultProxy is used and depending on your operation system the following will be used:

(Copied from here)

For Windows: Reads proxy configuration from environment variables or, if those are not defined, from the user’s proxy settings.

For macOS: Reads proxy configuration from environment variables or, if those are not defined, from the system’s proxy settings.

For Linux: Reads proxy configuration from environment variables or, in case those are not defined, this property initializes a non-configured instance that bypasses all addresses. The environment variables used for DefaultProxy initialization on Windows and Unix-based platforms are:

HTTP_PROXY: the proxy server used on HTTP requests. HTTPS_PROXY: the proxy server used on HTTPS requests. ALL_PROXY: the proxy server used on HTTP and/or HTTPS requests in case HTTP_PROXY and/or HTTPS_PROXY are not defined. NO_PROXY: a comma-separated list of hostnames that should be excluded from proxying. Asterisks are not supported for wildcards; use a leading dot in case you want to match a subdomain. Examples: > NO_PROXY=.example.com (with leading dot) will match www.example.com, but will not match example.com. NO_PROXY=example.com (without leading dot) will not match www.example.com. This behavior might be > revisited in the future to match other ecosystems better.

Scenario: Web-App that needs external & “internal” Web-APIs

We often had the following problem: Our web application needs to contact external services. This means, that we must use the proxy. At the same time, our web application also wants to communicate with other web APIs on the same machine, but the proxy does not allow this (the proxy can’t return the request to the same machine - not sure why).

It should be noted that the “IIS account” or “Network Service” did NOT have a proxy setting itself, i.e. the “User Proxy Settings” were always empty.

Solution:

We used the following proxy settings and it worked:

ALL_PROXY = proxyserver.corp.acme.com
NO_Proxy = internalserver.corp.acme.com

Our web application and our internal web api were running on “internalserver.corp.acme.com”. Each request to external services were routed through the proxy and each “internal” request didn’t touch the proxy.

IE-Proxy Settings:

This solution should work fine on “Server-Environments”. If you have a desktop application, then the “Default Proxy” handling should do the trick. In some special cases the “IE proxy setting” handling might be needed. If you want to learn more about this, read this blogpost: How to use IE proxy settings with HttpClient.

Hope this helps!

Holger Schwichtenberg: Neu in .NET 8.0 [5]: Typaliasse in C# 12.0

Typen können in der aktuellen Version von C# durch das Schlüsselwort using einen alternativen Namen erhalten.

Holger Schwichtenberg: Neu in .NET 8.0 [4]: Collection Expressions in C# 12.0

Das aktuelle Release der Programmiersprache C# vereinfacht das Initialisieren von Collections wie Listen.

Holger Schwichtenberg: Neu in .NET 8.0 [3]: Primärkonstruktoren in C# 12.0

Die Programmiersprache C# bietet in Version 12.0 die Möglichkeit, über eine Parameterliste hinter dem Typnamen einen Primärkonstruktor zu definieren.

Holger Schwichtenberg: Neu in .NET 8.0 [2]: Neue Anwendungsarten

Blazor bekommt in .NET 8.0 einen Auto-Rendering-Modus und Blazor Static-Server-Rendering.

Stefan Henneken: Book release „Use of the SOLID principles with IEC 61131-3“

Due to the regular calls for articles about the SOLID principles, I decided some time ago to offer this series in the form of a small book. This book can now be ordered (as a paperback and as an e-book) from all well-known bookshops and digital platforms. In addition to the SOLID principles, the book also addresses the KISS, DRY, LoD and YAGNI principles.

Of course, the previous articles are still available free of charge here on the blog. This means that everyone is free to decide whether they would prefer to read the articles online, on an e-book reader or as a printed book.

The price for the almost 100-page book is €6.99 for the printed version (ISBN-13: 9783757892227) and €4.99 for the e-book (ISBN-13: 9783758356148).

Stefan Henneken: IEC 61131-3: The Principles KISS, DRY, LoD and YAGNI

The 5 SOLID principles were presented in the previous posts. In addition to the SOLID principles, however, there are other principles that are also briefly presented here. What all these principles have in common is the goal of making software more maintainable and more reusable.

Don’t Repeat Yourself (DRY)

The DRY principle states (as the name suggests) that program code should not be duplicated unnecessarily. Instead, a function should be implemented only once and called at desired points in the program.

The DRY principle can help improve the maintainability of code, as it becomes easier to make changes to a function if it is implemented in only one place in the program code. In addition, the DRY principle can help reduce errors in the program, since duplicated code often leads to unexpected behaviour when a change is made in only one of the duplicated locations. Thus the DRY principle is an important principle in the software development, which can contribute to the improvement of the code quality.

Although the DRY principle is easy to understand and implement, it is probably the most disregarded principle. Because nothing is easier than to repeat source code by copy & paste. Especially when the time pressure is particularly high. Therefore, you should always try to implement shared functions in separate modules.

The following short example shows the application of the DRY principle. A PLC program receives different temperature values from several sensors. All temperature values are to be displayed in an HMI and written to a log file. To make the temperature values more readable, the formatting should be done in the PLC:

FUNCTION F_DisplayTemperature : STRING
VAR_INPUT
  fSensorValue  : LREAL;
  bFahrenheit   : BOOL;
END_VAR
IF (fSensorValue > 0) THEN
  IF (bFahrenheit) THEN
    F_DisplayTemperature := CONCAT('Temperature: ', 
                    REAL_TO_FMTSTR(fSensorValue, 1, TRUE));
    F_DisplayTemperature := CONCAT(F_DisplayTemperature, ' °C');
  ELSE
    F_DisplayTemperature := CONCAT('Temperature: ',
                    REAL_TO_FMTSTR(fSensorValue * 1.8 + 32, 1, TRUE));
    F_DisplayTemperature := CONCAT(F_DisplayTemperature, ' °F');	
  END_IF
ELSE
    F_DisplayTemperature := 'No sensor data available';
END_IF

In this example the function F_DisplayTemperature() is implemented only once. For the formatting of the temperature values this function is called at the desired places in the program. By avoiding duplicated code, the program becomes clearer and easier to read. If, for example, it is necessary to change the number of decimal places, this only has to be done in one place, namely in the function F_DisplayTemperature().

In addition to the use of functions, inheritance can also help to comply with the DRY principle by relocating a functionality in a base FB and using it by all derived FBs.

However, there may be cases in which the DRY principle should be deliberately violated. This is always the case if the readability of the source code is worsened by the use of DRY. Thus for the circle computation the formula for the circumference (U=2rπ) or for the area (A=r2π) is sufficiently readable. An outsourcing into separate functions does not increase the code quality, but only the dependence to further modules, in which the functions for the circle computation are. Instead, a global constant should be created for π and used in the calculations.

In summary, the DRY principle helps make program code cleaner and shorter by avoiding code duplication.

Law Of Demeter (LoD)

The Law of Demeter is another principle whose observance can significantly minimize the couplings between function blocks. The Law of Demeter specifies that only elements in the immediate vicinity should be accessed from a function block (or method or function). In concrete terms, this means that only accesses to the following elements are permitted:

  • Variables of the own function block (everything between VAR/END_VAR)
  • Methods/properties of the own function block
  • Methods/properties of the function blocks that were created in the own function block
  • Parameters passed to methods or function blocks (VAR_INPUT)
  • Global constants or parameters contained in a parameter list

The Law of Demeter could therefore also be called: Don’t talk to strangers. Strangers are elements that are not directly present in the function block. In contrast, the own elements are called friends.

Also this principle originates from the 1980iger years, thus from the time, in which the object-oriented software development increased strongly in popularity. The name Demeter is to be led back on a software project of the same name, in which this principle was recognized for the first time (Demeter is in the Greek mythology the sister of Zeus and the Goddess of the agriculture). At the end of the 1980s, this principle was further elaborated by Ian Holland and Karl J. Lieberherr and published under the title Assuring Good Style for Object-Oriented Programs.

The following graphic is intended to illustrate the Law of Demeter in a little more detail:

FB_A contains an instance of FB_B (fbB). Therefore, FB_A can directly access the methods and properties of FB_B.

FB_B contains an instance of FB_C. Therefore, FB_B can access FB_C directly.

FB_B could offer a property or a method that returns the reference to FB_C (refC). Access from FB_A to the instance of FB_C via FB_B would thus theoretically be possible:

nValue := fbB.refC.nValue;

The instance on FB_C is created in FB_B. If FB_A accesses this instance directly, a fixed coupling between FB_A and FB_C is created. This fixed coupling can lead to problems in the care, maintenance and testing of the program. If FB_A is tested, not only FB_B must be present, but FB_C as well. A frequent violation of the Law of Demeter is therefore also helpful in the early detection of maintenance problems.

Even creating a corresponding local variable in which the reference to FB_C is stored does not solve the actual problem:

refC : REFERENCE TO FB_C;
refC REF= fbB.refC;
nValue := refC.nValue;

At first glance, these dependencies are not always apparent, as FB_C is accessed indirectly via FB_B.

Example

Here is a concrete example that illustrates the problem again and also offers a solution.

The function blocks FB_Building, FB_Floor, FB_Room and FB_Lamp represent the structure of a building and its lighting. The building consists of 5 floors, each containing 20 rooms and each room contains 10 lamps.

Each function block contains the corresponding instances of the underlying elements. The function blocks each provide a property that offers a reference to these elements. FB_Lamp contains the property nPowerConsumption, via which the current power consumption of the lamp is output.

A function is to be developed that determines the power consumption of all lamps in the building.

One solution could be to access each individual lamp via several nested loops and add up the power consumption:

FUNCTION F_CalcPowerConsumption : UDINT
VAR_INPUT
  refBuilding : REFERENCE TO FB_Building;
END_VAR
VAR
  nFloor, nRoom, nLamp : INT;
END_VAR
IF (NOT __ISVALIDREF(refBuilding)) THEN
  F_CalcPowerConsumption := 0;
  RETURN;
END_IF
FOR nFloor := 1 TO 5 DO
  FOR nRoom := 1 TO 20 DO
    FOR nLamp := 1 TO 10 DO
      F_CalcPowerConsumption := F_CalcPowerConsumption + refBuilding
                                  .refFloors[nFloor]
                                  .refRooms[nRoom]
                                  .refLamps[nLamp].nPowerConsumption;
    END_FOR
  END_FOR
END_FOR

The „diving‟ into the object structure down to each lamp seems somehow impressive. But this makes the function dependent on all function blocks, even those that are only indirectly addressed via a reference.

The access of refBuilding to refFloors does not violate the Law of Demeter, since refFloors is a direct property of FB_Building. However, all further accesses to the references have the consequence that our function also becomes dependent on the other function blocks.

If, for example, the structure of FB_Room or FB_Floor changes, the function for power consumption may also have to be adapted.

To comply with the Law of Demeter, each function block could offer a method (CalcPowerConsumption()) in which the power consumption is calculated. In each of these methods, the underlying method CalcPowerConsumption() is called:

The CalcPowerConsumption() method in FB_Building only accesses its own elements. In this case, it accesses the property refFloors to call the method CalcPowerConsumption() of FB_Floor:

METHOD CalcPowerConsumption : UDINT
VAR
  nFloor : INT;
END_VAR
FOR nFloor := 1 TO 5 DO
  CalcPowerConsumption := CalcPowerConsumption +                                
                             refFloors[nFloor].CalcPowerConsumption();
END_FOR

In CalcPowerConsumption() of FB_Floor, only FB_Room is accessed:

METHOD CalcPowerConsumption : UDINT
VAR
  nRoom : INT;
END_VAR
FOR nRoom := 1 TO 20 DO
  CalcPowerConsumption := CalcPowerConsumption +
                             refRooms[nRoom].CalcPowerConsumption();
END_FOR

Finally, the power consumption of all lamps in the room is calculated in FB_Room:

METHOD CalcPowerConsumption : UDINT
VAR
  nLamp : INT;
END_VAR
FOR nLamp := 1 TO 10 DO
  CalcPowerConsumption := CalcPowerConsumption +
                             refLamps[nLamp].nPowerConsumption;
END_FOR

The structure of the function F_CalcPowerConsumption() is thus much simpler:

FUNCTION F_CalcPowerConsumption : UDINT
VAR_INPUT
  refBuilding : REFERENCE TO FB_Building;
END_VAR
IF (NOT __ISVALIDREF(refBuilding)) THEN
  F_CalcPowerConsumption := 0;
  RETURN;
END_IF
F_CalcPowerConsumption := refBuilding.CalcPowerConsumption();

After this adjustment, F_CalcPowerConsumption() is only dependent on FB_Building and its method CalcPowerConsumption(). How FB_Building calculates the power consumption in CalcPowerConsumption() is irrelevant for F_CalcPowerConsumption(). The structure of FB_Room or FB_Floor could change completely, F_CalcPowerConsumption() would not have to be adapted.

The first variant, in which all function blocks were iterated through, is very susceptible to changes. No matter which function block the structure changes, an adjustment of F_CalcPowerConsumption() would be necessary every time.

Sample 1 (TwinCAT 3.1.4024) on GitHub

However, it must be taken into account that nested structures do make sense. The Law of Demeter does not have to be applied here. It can be helpful to distribute the configuration data hierarchically over several structures in order to increase readability.

Keep It Simple, Stupid (KISS)

The KISS principle states that code should be as „simple‟ as possible so that it is as easy to understand as possible and thus effective to maintain. Here, „simple‟ is also to be understood as „plain‟. This means a simplicity that tries to leave out the unnecessary but still fulfils the customer’s requirements. By following the KISS principle, a system is:

  • easy to understand
  • easy to extend
  • easy to maintain

If the requirement is to sort ten million records, using the bubblesort algorithm would be simple to implement, but the low speed of the algorithm will not meet the client’s requirements. Therefore, a solution must always be found that meets the customer’s required expectations, but whose implementation is as simple (plain) as possible.

Basically, two types of requirements are to be distinguished:

Functional requirement: The customer or stakeholder demands a specific feature. The exact requirements for this feature are then defined together with the customer and only then is it implemented. Functional requirements extend an application with clear functions (features) desired by the customer.

Non-functional requirements: A non-functional requirement is, for example, the splitting of an application into different modules or the provision of interfaces, e.g. to enable unit tests. Non-functional requirements are performance features that are not necessarily visible to the customer. However, these may be necessary so that the software system can be maintained and serviced.

The KISS principle is always about the non-functional requirements. The focus is on the „how‟. In other words, the question of how the required functions are achieved. The YAGNI principle, which is described in the following chapter, refers to the functional requirements. Here the focus is on the „what‟.

The KISS principle can be applied at several levels:

Formatting source code

Although the following source code is very compact, the KISS principle is violated here because it is difficult to understand and thus very error-prone:

IF(x<=RT[k-1](o[n+2*j]))THEN WT[j+k](l AND NOT S.Q);END_IF;
IF(x>RI[k+1](o[n+2*k]))THEN WO[j-k](l OR NOT S.Q);END_IF;

The source code should be formatted in such a way that the sequence is better recognised. Also, the identifiers for variables and functions should be chosen in such a way that their meaning is easier to understand.

Unnecessary source code

Source code that does not help to improve readability also violates the KISS principle:

bCalc := F_CalcFoo();
IF (bCalc = TRUE) THEN
  bResult := TRUE;
ELSE
  bResult := FALSE;
END_IF

Although the source code is well structured and the identifiers have been chosen so that their meaning is easier to recognise, the source code can be significantly reduced:

bResult := F_CalcFoo();

This one line is much easier to understand than the 6 lines before. The source code is „simpler‟, with the same range of functions.

Software design / software architecture

The design or structure of software can also violate the KISS principle. If, for example, a complete SQL database is used to store configuration data, although a text file would suffice, the KISS principle is also violated.

The division of a PLC programme into several CPU cores only makes sense if it also produces a practical benefit. In this case, appropriate mechanisms must be built into a PLC program to synchronise access to shared resources. These increase the complexity of the system considerably and should only be used if the application requires them.

I have deliberately placed the chapters on the KISS principle and the YAGNI principle at the end. From here, I would like to take a brief look back at the beginning of the series on the SOLID principles.

When introducing the SOLID principles, I occasionally pointed out the danger of overengineering. Abstractions should only be provided if they are necessary for the implementation of features.

To clarify this, I will use the example for the explanation of the SOLID principles again (see: IEC 61131-3: SOLID – The Dependency Inversion Principle).

There is a fixed dependency between the three lamp types and the controller. If the application is to be extended by another lamp type, it is necessary to adapt the programme at various points. By applying the Dependency Inversion Principle (DIP) and the Single Responsibility Principle (SRP), the programme became much more flexible. The integration of additional lamp types has been significantly simplified. However, the complexity of the programme was also significantly increased by these adjustments, as the UML diagram shows:

(abstract elements are displayed in italics)

Before additional levels of abstraction are realised by applying the SOLID principles, one should always critically question the extra effort involved.

The structure of the first variant is completely sufficient if the program is used exclusively in a project to this extent. The program is small enough to understand the structure of the software and to make small adjustments. The KISS principle was followed. No more complexity than necessary has been built in.

However, if the first variant is only an intermediate step, e.g. in the development of a comprehensive light management system, it is to be expected that the application will increase in complexity. It is also possible that at a later stage the development will have to be distributed among several people. The use of unit tests is another point that justifies the implementation of SOLID principles. Without decoupling the individual lamp types through interfaces, the use of unit tests is difficult or even impossible. Here, too, the KISS principle is not violated. The KISS principle must therefore always be considered in context.

You Ain’t Gonna Need It (YAGNI)

YAGNI stands for You Ain’t Gonna Need It and also means You will not need it. It means that in software development you should only implement the features that are needed. No functions or features should be implemented, which might be needed someday.

In contrast to the KISS principle, which always focuses on the non-functional requirements, the YAGNI principle focuses on the functional requirements.

When developing software, it can be tempting to implement additional features without a concrete requirement. This can be the case, for example, if features are implemented during development without consulting the customer, in the firm belief that the customer will demand them later.

Referring to our example above, the YAGNI principle would be violated if the operating hours recording were implemented (see: IEC 61131-3: SOLID – The Interface Segregation Principle), although this was not requested by the customer.

If it is determined during development that a particular feature could be useful, it should only be implemented after consultation with the customer. Otherwise, a system will gradually receive more and more source code for features that no one needs.

This example makes it clear once again that all the principles described so far are not fixed rules or even laws. However, the principles are a powerful tool for improving the code quality of software.

Stefan Henneken: IEC 61131-3: Die Prinzipien KISS, DRY, LoD und YAGNI

In den vorherigen Posts wurden die 5 SOLID-Prinzipien vorgestellt. Neben den SOLID-Prinzipien gibt es noch weitere Prinzipien, von denen ich einige ebenfalls kurz vorgestellen möchte. All diese Prinzipen haben das gemeinsame Ziel, die Wartbarkeit und die Wiederverwendbarkeit von Software zu verbessern.

Don’t Repeat Yourself (DRY)

Das DRY-Prinzip besagt (wie der Name schon vermuten lässt), dass man Programmcode nicht unnötig duplizieren sollte. Stattdessen sollte eine Funktion nur einmal implementiert und an gewünschten Stellen im Programm aufgerufen werden.

Das DRY-Prinzip kann helfen, die Wartbarkeit von Code zu verbessern, da es einfacher wird, Änderungen an einer Funktion vorzunehmen, wenn sie nur an einer Stelle im Programmcode implementiert wurde. Außerdem kann das DRY-Prinzip dazu beitragen, Fehler im Programm zu reduzieren, da duplizierter Code oft zu unerwarteten Verhaltensweisen führt, wenn eine Änderung nur an einer der duplizierten Stellen vorgenommen wird. Somit ist das DRY-Prinzip ein wichtiger Grundsatz in der Softwareentwicklung, welcher zur Verbesserung der Codequalität beitragen kann.

Obwohl das DRY-Prinzip einfach zu verstehen und umzusetzen ist, ist es wahrscheinlich das am meisten missachtete Prinzip. Denn nichts ist einfacher, als Quellcode durch Copy & Paste zu wiederholen. Gerade dann, wenn der Zeitdruck besonders hoch ist. Deshalb sollte man sich immer bemühen, gemeinsam genutzte Funktionen in separate Module zu implementieren.

Das folgende kurze Beispiel zeigt die Anwendung des DRY-Prinzips. Ein SPS-Programm erhält von mehreren Sensoren unterschiedliche Temperaturwerte. Alle Temperaturwerte sollen in einem HMI angezeigt und in eine Log-Datei geschrieben werden. Damit die Temperaturwerte besser lesbar sind, soll die Formatierung in der SPS erfolgen:

FUNCTION F_DisplayTemperature : STRING
VAR_INPUT
  fSensorValue  : LREAL;
  bFahrenheit   : BOOL;
END_VAR
IF (fSensorValue > 0) THEN
  IF (bFahrenheit) THEN
    F_DisplayTemperature := CONCAT('Temperature: ', REAL_TO_FMTSTR(fSensorValue, 1, TRUE));
    F_DisplayTemperature := CONCAT(F_DisplayTemperature, ' °C');
  ELSE
    F_DisplayTemperature := CONCAT('Temperature: ', REAL_TO_FMTSTR(fSensorValue * 1.8 + 32, 1, TRUE));
    F_DisplayTemperature := CONCAT(F_DisplayTemperature, ' °F');
  END_IF
ELSE
  F_DisplayTemperature := 'No sensor data available';
END_IF

In diesem Beispiel wird die Funktion F_DisplayTemperature() nur einmal implementiert. Für die Formatierung der Temperaturwerte wird diese Funktion an den gewünschten Stellen im Programm aufgerufen. Durch das Vermeiden von dupliziertem Code wird das Programm übersichtlicher und einfacher zu lesen. Ist es z.B. notwendig die Anzahl der Nachkommerstellen zu verändern, so muss dieses nur an einer Stelle, nämlich in der Funktion F_DisplayTemperature(), erfolgen.

Neben den Einsatz von Funktionen kann auch die Vererbung helfen das DRY-Prinzip einzuhalten, indem eine Funktionalität in einen Basis-FB verlagert und von allen abgeleiteten FBs verwendet wird.

Es kann aber Fälle geben, in denen das DRY-Prinzip bewusst verletzt werden sollte. Dieses ist immer dann der Fall, wenn sich durch den Einsatz von DRY die Lesbarkeit des Quellcode verschlechtert. So ist für die Kreisberechnung die Formel für den Umfang (U=2rπ) oder für die Fläche (A=r2π) ausreichend lesbar. Eine Auslagerung in separate Funktionen erhöht nicht die Codequalität, sondern nur die Abhängigkeit zu weiteren Modulen, in denen sich die Funktionen für die Kreisberechnung befinden. Stattdessen sollte für π eine globale Konstante angelegt und in den Berechnungen verwendet werden.

Zusammenfassend lässt sich sagen, dass das DRY-Prinzip dazu beiträgt, das Programmcode sauberer und kürzer wird, indem es die Duplizierung von Code vermeidet.

Law Of Demeter (LoD)

Das Law of Demeter ist ein weiteres Prinzip, dessen Beachtung die Kopplungen zwischen Funktionsblöcken deutlich minimieren kann. Das Law of Demeter legt fest, dass aus einem Funktionsblock (bzw. Methode oder Funktion) nur auf Elemente in unmittelbarer Nähe zugegriffen werden sollte. Konkret bedeutet dieses, dass nur Zugriffe auf die folgenden Elemente erlaubt sind:

  • Variablen des eigenen Funktionsblocks (alles zwischen VAR/END_VAR)
  • Methoden/Eigenschaften des eigenen Funktionsblocks
  • Methoden/Eigenschaften der Funktionsblöcke die im eigenen Funktionsblock angelegt wurden
  • Parameter die an Methoden oder Funktionsblöcke übergeben wurden (VAR_INPUT)
  • Globale Konstanten oder Parameter die in einer Parameterliste enthalten sind

Das Law of Demeter könnte somit auch heißen: Don’t talk to strangers. Als Strangers (Fremde) werden hierbei die Elemente bezeichnet, die nicht unmittelbar in dem Funktionsblock vorhanden sind. Im Gegensatz dazu, werden die eigenen Elemente Friends (Freunde) genannt.

Auch dieses Prinzip stammt aus den 1980iger Jahren, also aus der Zeit, in der die objektorientierte Softwareentwicklung stark an Popularität zugenommen hat. Der Name Demeter ist auf ein gleichnamiges Softwareprojekt zurückzuführen, in dem dieses Prinzip erstmal erkannt wurde (Demeter ist in der griechischen Mythologie die Schwester von Zeus und die Göttin der Landwirtschaft). Ende der 1980iger Jahre wurde dieses Prinzip von Ian Holland und Karl J. Lieberherr weiter ausgearbeitet und unter dem Titel Assuring Good Style for Object-Oriented Programs veröffentlicht.

Die folgende Grafik soll das Law of Demeter etwas genauer verdeutlichen:

In FB_A ist eine Instanz von FB_B (fbB) enthalten. Deshalb kann FB_A direkt auf die Methoden und Eigenschaften von FB_B zugreifen.

FB_B enthält eine Instanz von FB_C. Deshalb kann FB_B direkt auf FB_C zugreifen.

FB_B könnte eine Eigenschaft oder eine Methode anbieten, welche die Referenz auf FB_C zurückgibt (refC). Ein Zugriff aus FB_A auf die Instanz von FB_C über FB_B wäre somit theoretisch möglich:

nValue := fbB.refC.nValue;

Die Instanz auf FB_C wird in FB_B angelegt. Wenn FB_A auf diese Instanz direkt zugreift, entsteht eine feste Kopplung zwischen FB_A und FB_C. Diese feste Kopplung kann zu Problemen bei der Pflege, Wartung und dem Testen des Programms führen. Wird FB_A getestet, so muss nicht nur FB_B vorhanden sein, sondern auch FB_C. Ein häufiges Verletzen des Law of Demeter ist somit auch hilfreich bei der Früherkennung von Wartungsproblemen.

Auch das Anlegen einer entsprechenden lokalen Variablen, in der die Referenz auf FB_C abgelegt wird, löst das eigentliche Problem nicht:

refC : REFERENCE TO FB_C;
refC REF= fbB.refC;
nValue := refC.nValue;

Auf dem ersten Blick sind diese Abhängigkeiten nicht immer zu erkennen, da der Zugriff auf FB_C indirekt über FB_B erfolgt.

Beispiel

Hierzu ein konkretes Beispiel, welches das Problem nochmal verdeutlicht und auch einen Lösungsansatz anbietet.

Mit den Funktionsblöcken FB_Building, FB_Floor, FB_Room und FB_Lamp wird die Struktur eines Gebäudes und dessen Beleuchtung abgebildet. Das Gebäude besteht aus 5 Etagen, in der sich jeweils 20 Räume befinden und jeder Raum enthält 10 Lampen.

In jedem Funktionsblock sind die entsprechenden Instanzen der darunterliegenden Elemente enthalten. Die Funktionsblöcke stellen jeweils eine Eigenschaft zur Verfügung, welche eine Referenz auf diese Elemente anbietet. FB_Lamp enthält die Eigenschaft nPowerConsumption, über der die aktuelle Leistungsaufnahme der Lampe ausgegeben wird.

Es soll eine Funktion entwickelt werden, welche die Leistungsaufnahme aller Lampen in dem Gebäude ermittelt.

Ein Lösungsansatz könnte darin bestehen, dass über mehrere verschachtelte Schleifen auf jede einzelne Lampe zugegriffen und die Leistungsaufnahme addiert wird:

FUNCTION F_CalcPowerConsumption : UDINT
VAR_INPUT
  refBuilding : REFERENCE TO FB_Building;
END_VAR
VAR
  nFloor, nRoom, nLamp : INT;
END_VAR
IF (NOT __ISVALIDREF(refBuilding)) THEN
  F_CalcPowerConsumption := 0;
  RETURN;
END_IF
FOR nFloor := 1 TO 5 DO
  FOR nRoom := 1 TO 20 DO
    FOR nLamp := 1 TO 10 DO
      F_CalcPowerConsumption := F_CalcPowerConsumption + refBuilding
                                  .refFloors[nFloor]
                                  .refRooms[nRoom]
                                  .refLamps[nLamp].nPowerConsumption;
    END_FOR
  END_FOR
END_FOR

Das „Eintauchen‟ in die Objektstruktur bis hinunter zu jeder Lampe wirkt schon irgendwie beeindruckend. Doch dadurch ist die Funktion abhängig von allen Funktionsblöcken, auch von denen, die nur indirekt über eine Referenz angesprochen werden.

Der Zugriff von refBuilding auf refFloors verstößt nicht gegen das Law of Demeter, da refFloors eine direkte Eigenschaft von FB_Building ist. Alle weiteren Zugriffe auf die Referenzen haben aber zur Folge, dass unsere Funktion auch von den anderen Funktionsblöcken abhängig wird.

Ändert sich z.B. die Struktur von FB_Room oder FB_Floor, so muss evtl. auch die Funktion zur Leistungsaufnahme angepasst werden.

Um das Law of Demeter einzuhalten, könnte jeder Funktionsblock eine Methode anbieten (CalcPowerConsumption()), in welcher die Leistungsaufnahme berechnet wird. In jeder dieser Methoden, wird wiederrum die darunter liegende Methode CalcPowerConsumption() aufgerufen:

Die Methode CalcPowerConsumption() in FB_Building greift nur auf die eigenen Elemente zu. In diesem Fall auf die Eigenschaft refFloors, um darüber die Methode CalcPowerConsumption() von FB_Floor aufzurufen:

METHOD CalcPowerConsumption : UDINT
VAR
  nFloor : INT;
END_VAR
FOR nFloor := 1 TO 5 DO
  CalcPowerConsumption := CalcPowerConsumption + refFloors[nFloor].CalcPowerConsumption();
END_FOR

In CalcPowerConsumption() von FB_Floor wird wiederrum nur auf FB_Room zugegriffen:

METHOD CalcPowerConsumption : UDINT
VAR
  nRoom : INT;
END_VAR
FOR nRoom := 1 TO 20 DO
  CalcPowerConsumption := CalcPowerConsumption + refRooms[nRoom].CalcPowerConsumption();
END_FOR

Zuletzt wird in FB_Room die Leistungsaufnahme aller Lampen in dem Raum berechnet:

METHOD CalcPowerConsumption : UDINT
VAR
  nLamp : INT;
END_VAR
FOR nLamp := 1 TO 10 DO
  CalcPowerConsumption := CalcPowerConsumption + refLamps[nLamp].nPowerConsumption;
END_FOR

Der Aufbau der Funktion F_CalcPowerConsumption() gestaltet sich dadurch deutlich einfacher:

FUNCTION F_CalcPowerConsumption : UDINT
VAR_INPUT
  refBuilding : REFERENCE TO FB_Building;
END_VAR
IF (NOT __ISVALIDREF(refBuilding)) THEN
  F_CalcPowerConsumption := 0;
  RETURN;
END_IF
F_CalcPowerConsumption := refBuilding.CalcPowerConsumption();

F_CalcPowerConsumption() ist nach dieser Anpassung nur noch abhängig von FB_Building und dessen Methode CalcPowerConsumption(). Wie FB_Building in CalcPowerConsumption() die Leistungsaufnahme berechnet, ist für F_CalcPowerConsumption() ohne Bedeutung. Der Aufbau von FB_Room oder FB_Floor könnte sich komplett ändern, F_CalcPowerConsumption() müsste nicht angepasst werden.

Die erste Variante, in der durch alle Funktionsblöcke iteriert wurde, ist sehr anfällig gegenüber Änderungen. Egal bei welchem Funktionsblock sich der Aufbau ändert, eine Anpassung von F_CalcPowerConsumption() wäre jedes Mal notwendig.

Beispiel 1 (TwinCAT 3.1.4024) auf GitHub

Allerdings ist zu berücksichtigen, dass verschachtelte Strukturen durchaus Sinn ergeben. Hier muss das Law of Demeter nicht anwendet werden. So kann es hilfreich sein, die Konfigurationsdaten über mehrere Strukturen hierarchisch zu verteilen, um so die Lesbarkeit zu erhöhen.

Keep It Simple, Stupid (KISS)

Das KISS-Prinzip besagt, dass Code so „simple‟ wie möglich sein sollte, damit dieser möglichst einfach zu verstehen und somit effektiv zu warten ist. Hierbei sollte „simple‟ mit „schlicht‟ übersetzt werden. Damit ist eine Schlichtheit gemeint, die versucht Unnötiges wegzulassen aber weiterhin die Anforderungen des Kunden zu erfüllen. Durch die Beachtung des KISS-Prinzips wird ein System:

  • einfach zu verstehen
  • einfach zu erweitern
  • einfach zu pflegen

Besteht die Anforderung darin zehn Millionen Datensätze zu sortieren, so wäre die Verwendung des Bubblesort-Algorithmus zwar einfach in der Umsetzung, doch wird die geringe Geschwindigkeit des Algorithmus nicht den Anforderungen des Kunden entsprechen. Es muss also immer eine Lösung gefunden werden, die den geforderten Erwartungen des Kunden entspricht und deren Umsetzung aber möglichst einfach (schlicht) ist.

Grundsätzlich sind zwei Arten von Anforderungen zu unterscheiden:

Funktionale Anforderung: Der Kunde bzw. Stakeholder fordert ein bestimmtes Leistungsmerkmal. Gemeinsam mit dem Kunden werden dann die genauen Anforderungen für dieses Leistungsmerkmal festgelegt und erst danach wird dieses implementiert. Funktionale Anforderungen erweitern eine Anwendung um eindeutige, von dem Kunden gewünschte, Funktionen (Leistungsmerkmale).

Nicht funktionale Anforderungen: Eine nicht funktionale Anforderung ist z.B. das Aufteilen einer Anwendung auf verschiedene Module oder das Vorsehen von Schnittstellen, um z.B. Unit-Tests zu ermöglichen. Nicht funktionale Anforderungen sind Leistungsmerkmale, die für den Kunden nicht unbedingt sichtbar sind. Diese können aber notwendig sein, damit das Softwaresystem gepflegt und gewartet werden kann.

Bei dem KISS-Prinzip geht es immer um die nicht funktionalen Anforderungen. Das „Wie‟ steht im Mittelpunkt. Also die Frage, wie die geforderten Funktionen erreicht werden. Das YAGNI-Prinzip, welches im folgenden Kapitel beschrieben wird, bezieht sich auf die funktionalen Anforderungen. Hier steht das „Was‟ im Mittelpunkt.

Das KISS-Prinzip kann auf mehrere Ebene angewendet werden:

Formatierung Quellcode

Der folgende Quellcode ist zwar sehr kompakt, doch wird hier das KISS-Prinzip verletzt, da dieser nur schwer zu verstehen und somit sehr fehleranfällig ist:

IF(x<=RT[k-1](o[n+2*j]))THEN WT[j+k](l AND NOT S.Q);END_IF;
IF(x>RI[k+1](o[n+2*k]))THEN WO[j-k](l OR NOT S.Q);END_IF;

Der Quellcode sollte so formatiert werden, dass der Ablauf besser erkannt wird. Auch sollten die Bezeichner für Variablen und Funktionen so gewählt werden, dass deren Bedeutung leichter zu verstehen ist.

Unnötiger Quellcode

Quellcode, der nicht dazu beiträgt, die Lesbarkeit zu verbessern, verletzt ebenfalls gegen das KISS-Prinzip:

bCalc := F_CalcFoo();
IF (bCalc = TRUE) THEN
  bResult := TRUE;
ELSE
  bResult := FALSE;
END_IF

Der Quellcode ist zwar gut strukturiert, auch wurden die Bezeichner so gewählt damit die Bedeutung leichter zu erkennen ist, doch kann der Quellcode deutlich reduziert werden:

bResult := F_CalcFoo();

Diese eine Zeile ist deutlich einfacher zu verstehen, wie die 6 Zeilen zuvor. Der Quellcode ist „schlichter‟, bei gleichem Funktionsumfang.

Softwaredesign / Softwarearchitektur

Auch das Design oder die Struktur einer Software kann gegen das KISS-Prinzip verstoßen. Wird z.B. für das Abspeichern von Konfigurationsdaten eine komplette SQL-Datenbank eingesetzt, obwohl eine Textdatei ausreichen würde, so wird ebenfalls das KISS-Prinzip verletzt.

Das Aufteilen eines SPS-Programms auf mehrere CPU-Cores ist nur dann sinnvoll, wenn es auch einen praktischen Nutzen hervorbringt. In einem SPS-Programm müssen in diesem Fall entsprechende Mechanismen eingebaut werden, um den Zugriff auf gemeinsame Ressourcen zu synchronisieren. Diese erhöhen die Komplexität des Systems erheblich und sollten nur dann zum Einsatz kommen, wenn die Anwendung dieses auch erfordert.

Ganz bewusst habe ich die Kapitel zu dem KISS-Prinzip und zu dem YAGNI-Prinzip an das Ende gesetzt. Von hier aus möchte ich nochmal einen kurzen Rückblick auf den Anfang der Serie über die SOLID-Prinzipien werfen.

Bei der Vorstellung der SOLID-Prinzipien habe ich gelegentlich auf die Gefahr des Overengineering hingewiesen. Abstraktionen sollten nur dann vorgesehen werden, wenn diese für die Umsetzung von Features notwendig sind.

Um dieses zu verdeutlichen, will ich das Beispiel für die Erklärung der SOLID-Prinzipien noch einmal verwenden (siehe: IEC 61131-3: SOLID – Das Dependency Inversion Principle).

Zwischen den drei Lampentypen und dem Controller besteht eine feste Abhängigkeit. Soll die Anwendung um einen weiteren Lampentyp erweitert werden, so ist es notwendig das Programm an verschiedenen Stellen anzupassen. Durch das Anwenden des Dependency Inversion Principle (DIP) und des Single Responsibility Principle (SRP) wurde das Programm deutlich flexibler. Das Integrieren von zusätzlichen Lampentypen wurde dadurch signifikant vereinfacht. Aber auch die Komplexität des Programms wurde durch diese Anpassungen deutlich größer, wie das UML-Diagramm zeigt:

(abstrakte Elemente werden in kursiver Schriftart dargestellt)

Bevor zusätzliche Abstraktionsebenen durch die Anwendung der SOLID-Prinzipien realisiert werden, sollte man den Mehraufwand immer kritisch hinterfragen.

Die erste Variante ist vom Aufbau vollkommen ausreichend, wenn das Programm in diesem Umfang ausschließlich in einem Projekt eingesetzt wird. Das Programm ist klein genug, um den Aufbau der Software zu verstehen und um kleine Anpassungen vorzunehmen. Das KISS-Prinzip wurde befolgt. Es wurde nicht mehr Komplexität als notwendig eingebaut.

Ist die erste Variante allerdings nur ein Zwischenschritt, z.B. bei der Entwicklung eines umfangreichen Lichtmanagementsystem, so ist damit zu rechnen, dass die Anwendung an Komplexität noch zunehmen wird. Auch ist es möglich, dass zu einem späteren Zeitpunkt die Entwicklung auf mehrere Personen verteilt werden muss. Der Einsatz von Unit-Tests ist ein weiterer Punkt, der die Umsetzung der SOLID-Prinzipien rechtfertigt. Ohne die Entkopplung der einzelnen Lampentypen durch Schnittstellen, ist der Einsatz von Unit-Tests nur schwer bzw. gar nicht möglich. Auch hier wird das KISS-Prinzip nicht verletzt. Das KISS-Prinzip muss somit immer im Kontext betrachtet werden.

You Ain’t Gonna Need It (YAGNI)

YAGNI steht für You Ain’t Gonna Need It und bedeutet frei übersetzt Du wirst es nicht brauchen. Es besagt, dass man in der Softwareentwicklung nur die Leistungsmerkmale realisieren sollte, die benötigt werden. Es sollen keine Funktionen oder Features implementiert werden, die vielleicht irgendwann einmal gebraucht werden könnten.

Im Gegensatz zu dem KISS-Prinzip, bei dem es immer um die nicht funktionalen Anforderungen geht, liegt der Fokus bei dem YAGNI-Prinzip auf den funktionalen Anforderungen.

Bei der Entwicklung von Software kann die Versuchung groß sein, zusätzliche Leistungsmerkmale ohne konkrete Anforderung zu implementieren. Das kann z.B. dann der Fall sein, wenn während der Entwicklung Leistungsmerkmale ohne Absprache mit dem Kunden implementiert werden, in dem festen Glauben, dass der Kunde diese später noch fordern wird.

Bezogen auf unser obiges Beispiel, wird das YAGNI-Prinzip dann verletzt, wenn man die Betriebsstundenerfassung implementieren würde (siehe: IEC 61131-3: SOLID – Das Interface Segregation Principle), obwohl dieses vom Kunden nicht gefordert wurde.

Wird während der Entwicklung festgestellt, dass ein bestimmtes Leistungsmerkmal sinnvoll sein könnte, so sollte die Implementierung erst nach Absprache mit dem Kunden erfolgen. Ansonsten erhält ein System nach und nach immer mehr Quellcode für Leistungsmerkmale, die niemand benötigt.

Durch dieses Beispiel wird noch einmal deutlich, dass alle bisher beschriebenen Prinzipien keine festen Regeln oder gar Gesetze sind. Die Prinzipien sind aber ein mächtiges Werkzeug, um die Codequalität von Software zu verbessern.

Martin Richter: WebView2 Build 120 zerstört COM-Infrastruktur

Wieder mal eine tolle Geschichte wie Kunden auf uns als Softwarehersteller sauer werden, weil Microsoft ein nicht funktionierendes Update veröffentlicht.

Die Story:

  • Wir nutzen intern COM für sehr viele Objekte, um unsere eigene Software via VB-Script zu steuern.
  • Wir haben auch die Möglichkeit Controls vom Typ WebView2 anzulegen.
  • Am 07.12. veröffentlichte Microsoft für den WebView2 den Build 120.
  • Unsere Software benutzt im Allgemeinen „Evergreen“, d.h. es wird immer die aktuelle WebView2 ohne eigne Installation benutzt.

Effekt:
Seit dem Update kann man nach dem, ein WebView2 Fenster zerstört wurde, keine COM Class Factory in unserem Programm aufrufen.
Intern scheint das WebView2 CoSuspendClassObjects aufzurufen wenn das Control zerstört wird. Die Folge unser IMessageFilter springt an und es kommt ein Dialog, der auf einen nicht reagierenden COM Server hinweist.

Der nicht reagierende COM-Server ist unsere eigene Anwendung… 😯

Toll! 😥

Einziger für uns möglicher Workaround für uns ist leider, die alte Version 119 auf jedem Client lokal zu installieren. Dann über einen Registry Eintrag (HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\WebView2\BrowserExecutableFolder) den Aufruf von der aktuellen Version umzubiegen.
Netterweise kann man das für jede Anwendung separat steuern.

Details zum Nachlesen auf GitHub.

Nachtrag: Der Bug verschwand mit dem Update 120.0.2210.77 in der evergreen Version. Bei mir wurde der Fix am Montag den 18.12.2023 automatisch installiert.


Copyright © 2017 Martin Richter
Dieser Feed ist nur für den persönlichen, nicht gewerblichen Gebrauch bestimmt. Eine Verwendung dieses Feeds bzw. der hier veröffentlichten Beiträge auf anderen Webseiten bedarf der ausdrücklichen Genehmigung des Autors.
(Digital Fingerprint: bdafe67664ea5aacaab71f8c0a581adf)

Martin Richter: VS-2022 Rollback deinstalliert manche VS-Extensions

Leidvoll musste ich erleben, dass ein Visual Studio 2022 Rollback auf die ältere vormals installierte Version leider auch einige VS-Extensions deinstalliert. Bzw. diese gehen verloren.

Man sollte also einen Rollback mit Vorsicht verwenden. Er eignet sich also nicht einfach und schnell ein Problem zu umgehen. Es sind einige Nacharbeiten nötig.


Copyright © 2017 Martin Richter
Dieser Feed ist nur für den persönlichen, nicht gewerblichen Gebrauch bestimmt. Eine Verwendung dieses Feeds bzw. der hier veröffentlichten Beiträge auf anderen Webseiten bedarf der ausdrücklichen Genehmigung des Autors.
(Digital Fingerprint: bdafe67664ea5aacaab71f8c0a581adf)

Martin Richter: VS-2022 Update 17.8 zerstört Mixed Mode Debugger-Funktionen „Unable to step. Operation not supported. Unknown error: 0x8ede0018.“

In der letzten Zeit habe ich regelmäßig die aktuellsten Visual-Studio 2022 installiert. Ich muss ehrlich sagen, dass ich seit VS-2029 nicht einmal schlechte Erfahrungen gemacht habe.
Das hat sich mit dem heutigen Tag geändert 🙁 !

Nach der Installation des Updates ging keine Step-Debug-Funktion mehr (Step-In, Step-Over, Step-Out, etc.) im Mixed Mode Debugging. Native Mode Debugging scheint zu gehen.

Egal was man macht man bekommt den Fehler:

Unable to step. Operation not supported. Unknown error: 0x8ede0018.

In der Developer Community für VS ist dieser Bug auch bereits bekannt und angeblich gibt es einen Fix. Der ist aber noch nicht öffentlich.

Leider arbeite ich an einigen C++/CLI Modulen und benötige den Mixed-Mode.

Das erste mal habe im Visual Studio Installer einen Rollback versucht. Leider hat der Rollback meine Extension zum Teil deinstalliert. Mein Visual Assist von Whole Tomato war auf einmal nicht mehr vorhanden. Toll… 😯

Nachtrag: Das Problem ist in der Version 17.8.4 behoben, die am 10.01.2024 veröffentlicht wurde.


Copyright © 2017 Martin Richter
Dieser Feed ist nur für den persönlichen, nicht gewerblichen Gebrauch bestimmt. Eine Verwendung dieses Feeds bzw. der hier veröffentlichten Beiträge auf anderen Webseiten bedarf der ausdrücklichen Genehmigung des Autors.
(Digital Fingerprint: bdafe67664ea5aacaab71f8c0a581adf)

Holger Schwichtenberg: In eigener Sache: Fachbuch zu ASP.NET Core Blazor 8.0 ist erschienen

Anhand des Fallbeispiels MiracleList zeigt das neue Buch die meisten Blazor-Funktionen in einem praxisnahen Gesamtzusammenhang.

Kazim Bahar: Die Top 5 KI-Tools für C# Entwickler

Es gibt mittlerweile viele KI-Tools, die C#-Entwicklern bei verschiedenen Aufgaben helfen können, z.B. bei der Codegenerierung, Codevervollständigung, Dokumentation, Fehlersuche und Optimierung. Zum einen fühlt man sich beim Einsatz solcher Tools wie in einer Pair-Programming Session, sprich...

Holger Schwichtenberg: In eigener Sache: C# 12.0 Crashkurs ist erschienen​

Eine Neuauflage des Fachbuchs "C# Crashkurs" bezieht die Neuerungen von C# 12.0 mit ein.

Manuela Rink: Key Benefits of Cleaning Services

Key Benefits of Cleaning Services


Are you tired of cleaning? Discover the advantages of professional cleaning services.

Save time, effort, and enjoy a healthier environment. Don’t miss out on the benefits of hiring a cleaning service.

  • Time-Saving Convenience:
  • Enhanced Health and Hygiene
    Impeccable Cleaning Standa
    rd
    s
  • Customized Cleaning Plans
  • Cost-Effective Solution

Manuela Rink: Why Is It Important to Hire an Insured Gutter Cleaner?

Why Is It Important to Hire an Insured Gutter Cleaner?

Hiring an insured gutter cleaner is crucial for home maintenance.
It ensures safety and protects property and workers.

This article emphasizes the importance of hiring an insured gutter cleaner for homeowners

  • Protection against Accidents and Liability
  • Safeguarding Your Property
  • Professionalism and Reliability
  • Peace of Mind

Manuela Rink: Recognizing Visual Cues For Water Damage

Recognizing Visual Cues For Water Damage

Water damage is costly and can be harmful.

Recognizing visual signs is important.

Let’s explore common signs and how to protect your property.

Manuela Rink: Unlocking Secrets:

  • Unlocking Secrets:

Effective Roof Cleaning Techniques for a Spotless Home


Maintaining a clean roof is crucial for the appearance and structure of your home.

Roofs can gather dirt, debris, algae, and moss, which not only affect the visual appeal but can also cause damage.

This blog post will discuss effective roof cleaning techniques for keeping your roof in excellent condition.

Manuela Rink: Floods are dangerous. Be prepared. Here are 10 flood safety tips

10 flood safety tips

Stay updated on weather alerts. Prepare an emergency kit.

Share an evacuation plan with family. Move valuables to higher ground.

Avoid floodwaters for safety. Follow evacuation orders. Turn off utilities before leaving.

Find higher ground during a flood. Stay connected with a radio or charged phone. Assist others and report emergencies.

Code-Inside Blog: Limit Active Directory property access

Be aware: I’m not a full time administrator and this post might sound stupid to you.

The Problem

We access certain Active Directory properties with our application and on one customer domain we couldn’t get any data out via our Active Directory component.

Solution

After some debugging and doubts about our functionality we (the admin of the customer and me) found the reason: Our code was running under a Windows Account that was very limted and couldn’t read those properties.

If you have similar problems you might want to take a look in the AD User & Group management.

  1. You need to active the advanced features:

x

  1. Now check the security tab, go to advanced view and add a new permission or change a existing one:

x

  1. Here you should be able to see a huge dialog with all available properties. Check if your user is able to read your target property

x

Hope this helps!

Code-Inside Blog: Zip deployment failed on Azure

The Problem

We are using Azure App Service for our application (which runs great BTW) and deploy it automatically via ZipDeploy. This basic setup was running smoth, but we noticed that at some point the deployment failed with these error messages:

2023-08-24T20:48:56.1057054Z Deployment endpoint responded with status code 202
2023-08-24T20:49:15.6984407Z Configuring default logging for the app, if not already enabled
2023-08-24T20:49:18.8106651Z Zip deployment failed. {'id': 'temp-b574d768', 'status': 3, 'status_text': '', 'author_email': 'N/A', 'author': 'N/A', 'deployer': 'ZipDeploy', 'message': 'Deploying from pushed zip file', 'progress': '', 'received_time': '2023-08-24T20:48:55.8916655Z', 'start_time': '2023-08-24T20:48:55.8916655Z', 'end_time': '2023-08-24T20:49:15.3291017Z', 'last_success_end_time': None, 'complete': True, 'active': False, 'is_temp': True, 'is_readonly': False, 'url': 'https://[...].scm.azurewebsites.net/api/deployments/latest', 'log_url': 'https://[...].scm.azurewebsites.net/api/deployments/latest/log', 'site_name': '[...]', 'provisioningState': 'Failed'}. Please run the command az webapp log deployment show
2023-08-24T20:49:18.8114319Z                            -n [...] -g production

or this one (depending on how we invoked the deployment script):

Getting scm site credentials for zip deployment
Starting zip deployment. This operation can take a while to complete ...
Deployment endpoint responded with status code 500
An error occured during deployment. Status Code: 500, Details: {"Message":"An error has occurred.","ExceptionMessage":"There is not enough space on the disk.\r\n","ExceptionType":"System.IO.IOException","StackTrace":" 

“There is not enough space on the disk”?

The message There is not enough space on the disk was a good hint, but according to the File system storage everything should be fine with only 8% used.

Be aware - this is important: We have multiple apps on the same App Service plan!

x

Kudu to the rescure

Next step was to check the behind the scene environment via the “Advanced Tools” Kudu and there it is:

x

There are two different storages attached to the app service:

  • c:\home is the “File System Storage” that you can see in the Azure Portal and is quite large. App files are located here.
  • c:\local is a much smaller storage with ~21GB and if the space is used, then ZipDeploy will fail.

Who is using this space?

c:\local stores “mostly” temporarily items, e.g.:

Directory of C:\local

08/31/2023  06:40 AM    <DIR>          .
08/31/2023  06:40 AM    <DIR>          ..
07/13/2023  04:29 PM    <DIR>          AppData
07/13/2023  04:29 PM    <DIR>          ASP Compiled Templates
08/31/2023  06:40 AM    <DIR>          Config
07/13/2023  04:29 PM    <DIR>          DomainValidationTokens
07/13/2023  04:29 PM    <DIR>          DynamicCache
07/13/2023  04:29 PM    <DIR>          FrameworkJit
07/13/2023  04:29 PM    <DIR>          IIS Temporary Compressed Files
07/13/2023  04:29 PM    <DIR>          LocalAppData
07/13/2023  04:29 PM    <DIR>          ProgramData
09/05/2023  08:36 PM    <DIR>          Temp
08/31/2023  06:40 AM    <DIR>          Temporary ASP.NET Files
07/18/2023  04:06 AM    <DIR>          UserProfile
08/19/2023  06:34 AM    <SYMLINKD>     VirtualDirectory0 [\\...\]
               0 File(s)              0 bytes
              15 Dir(s)  13,334,384,640 bytes free

The “biggest” item here was in our case under c:\local\Temp\zipdeploy:

 Directory of C:\local\Temp\zipdeploy

08/29/2023  04:52 AM    <DIR>          .
08/29/2023  04:52 AM    <DIR>          ..
08/29/2023  04:52 AM    <DIR>          extracted
08/29/2023  04:52 AM       774,591,927 jiire5i5.zip

This folder stores our ZipDeploy package, which is quite large with ~800MB. The folder also contains the extracted files - remember: We only have 21GB on this storage, but even if this zip file and the extracted files are ~3GB, there is still plenty of room, right?

Shared resources

Well… it turns out, that each App Service on a App Service plan is using this storage and if you have multiple App Services on the same plan, than those 21GB might melt away.

The “bad” part is, that the space is shared, but each App Services has it’s own c:\local folder (which makes sense). To free up memory we had to clean up this folder on each App Service like that:

rmdir c:\local\Temp\zipdeploy /s /q

TL;DR

If you have problems with ZipDeploy and the error message tells you, that there is not enough space, check out the c:\local space (and of course c:\home as well) and delete unused files. Sometimes a reboot might help as well (to clean up temp-files), but AFAIK those ZipDeploy files will survive that.

Holger Schwichtenberg: Neu in .NET 7.0 [29]: Microseconds und Nanoseconds

Microsoft erweitert die Klassen DateTime, TimeStamp, DateTimeOffset und TimeOnly in .NET 7.0 um die Eigenschaften Microseconds und Nanoseconds.

Holger Schwichtenberg: Neu in .NET 7.0 [28]: Source-Generator für Platform Invoke

Neben dem Source-Generator für reguläre Ausdrücke führt .NET 7.0 auch einen für den Zugriff auf native Betriebssystemfunktionen ein.

Holger Schwichtenberg: Neu in .NET 7.0 [27]: Leistung des Source-Generators für reguläre Ausdrücke

Ein Vergleich mit anderen Verfahren zeigt, wann es sich lohnt, den neuen Source-Generator für reguläre Ausdrücke zu verwenden.

Holger Schwichtenberg: Neu in .NET 7.0 [26]: Source-Generator für reguläre Ausdrücke

Ein neuer Generator beschleunigt in .NET 7.0 die Verarbeitung Regulärer Ausdrücke und ist kompatibel zu dem Ahead-of-Time-Kompilierung.

Holger Schwichtenberg: Neu in .NET 7.0 [25]: Polymorphismus beim Deserialisieren mit System.Text.Json

Der JSON-Deserializer kann im jüngsten .NET-Framework ebenso polymorph arbeiten wie der JSON-Serializer.

Holger Schwichtenberg: Neu in .NET 7.0 [24]: Polymorphismus beim Serialisieren mit System.Text.Json

Die Annotation [JsonDerivedType] in der JSON-Bibliothek System.Text.Json ermöglicht polymorphes Programmieren.

Holger Schwichtenberg: Neu in .NET 7.0 [23]: Pflichteigenschaften bei der JSON-Deserialisierung

.NET quittiert mit der aktuellen Version das Auslassen von Pflichtattributen bei der JSON-Deserialisierung mit einer Fehlermeldung.

Holger Schwichtenberg: Neu in .NET 7.0 [22]: Angepasste JSON-Serialisierung mit Type Info Resolvers

Das Anpassen der Serialisierung und Deserialisierung von JSON-Inhalten ist nützlich, wenn die zu serialisierende Klasse nicht im Sourcecode verfügbar ist.

Holger Schwichtenberg: Neu in .NET 7.0 [21]: Komprimierte Tar-Archive

Das Verarbeiten von Tar-Archiven ist eine Neuerung in .NET 7.0. Um sie zu komprimieren, sind separate Verfahren wie GZip erforderlich.

Manuela Rink: 6 Benefits of Water Damage Restoration Service

Water Damage RestorationALT

Water damage can occur in homes and businesses due to various reasons such as floods, leaking pipes, or sewage backups. When faced with water damage, it is crucial to take immediate action to minimize the extent of the damage and prevent further problems. This is where water damage restoration services come into play. In this article, we will explore six benefits of water damage restoration services and why they are essential for restoring your property.

6 Benefits of Water Damage Restoration Service

Water damage restoration services are designed to mitigate the effects of water damage and restore your property to its pre-damaged condition. These services employ trained professionals equipped with specialized tools and techniques to address water-related issues efficiently. Let’s explore the benefits of hiring water damage restoration services in more detail.

Swift Water Extraction

One of the primary benefits of water damage restoration services is their ability to quickly extract water from your property. Time is of the essence when it comes to water damage, as prolonged exposure to water can lead to further damage and mold growth. Restoration professionals use powerful pumps and vacuums to remove standing water efficiently. This swift water extraction minimizes the risk of structural damage and reduces the chances of mold formation.

Professional Assessment and Restoration Plan

When you hire water damage restoration services, professionals conduct a thorough assessment of the affected area. They identify the extent of the damage and create a detailed restoration plan tailored to your specific needs. This assessment ensures that all areas, including hidden spaces and structural components, are accounted for during the restoration process. With a well-defined plan in place, restoration efforts are targeted and efficient.

Mold Prevention and Remediation

Water damage often creates an environment conducive to mold growth. Mold can pose serious health risks and cause further damage to your property if left untreated. Water damage restoration services include mold prevention and remediation as part of their comprehensive approach. Professionals use specialized equipment and techniques to detect and eliminate mold, ensuring a safe and healthy environment for occupants.

Drying and Dehumidification

After water extraction, thorough drying and dehumidification are essential to prevent secondary damage. Water damage restoration services employ industrial-grade drying equipment such as air movers and dehumidifiers to remove excess moisture from the air and surfaces. This process eliminates moisture that can seep into walls, furniture, and other materials, minimizing the risk of warping, swelling, or mold growth.

Structural Repair and Restoration

Water damage can weaken the structural integrity of your property, compromising its safety and stability. Water damage restoration services encompass structural repair and restoration to bring your property back to its pre-damaged condition. Whether it’s repairing damaged walls, floors, or ceilings, these professionals have the expertise to restore the structural elements of your property effectively.

Safety and Health Measures

Water damage restoration services prioritize safety and health measures throughout the restoration process. Professionals are equipped with personal protective equipment (PPE) to ensure their safety while working in hazardous conditions. They also take precautions to prevent cross-contamination and ensure the overall safety of occupants during the restoration process. By adhering to strict safety guidelines, water damage restoration services provide peace of mind to property owners.

Conclusion

Water damage restoration services offer a range of benefits when it comes to addressing water-related issues in your property. From swift water extraction and professional assessment to mold prevention and structural repair, these services play a vital role in minimizing damage and restoring your property to its original condition. By hiring water damage restoration services, you can save time, mitigate risks, and ensure the safety and well-being of your property and its occupants.

Holger Schwichtenberg: Neu in .NET 7.0 [20]: Tar-Archive

Dass .NET 7.0 auch Tar-Archive verarbeiten kann, ist der Docker-Anbindung an die .NET CLI zu verdanken.

Manuela Rink: A Step-By-Step Guide to Water Damage Restoration

Water Damage RestorationALT

Water damage can be a distressing and overwhelming experience for homeowners. Whether it’s caused by a burst pipe, heavy rain, or a plumbing mishap, water damage can lead to structural issues, mold growth, and the loss of personal belongings. However, with prompt action and the right knowledge, it is possible to mitigate the damage and restore your property to its pre-loss condition. In this article, we will provide you with a step-by-step guide to water damage restoration, helping you navigate through the process effectively.

A Step-By-Step Guide to Water Damage Restoration

Water damage can be a nightmare for any homeowner. Whether it’s caused by a burst pipe, heavy rainfall, or a leaky roof, the consequences can be devastating. But fear not! With a step-by-step guide to water damage restoration, you can navigate through this challenging process and restore your home to its former glory.

Step 1: Assess the Damage

The first step in water damage restoration is to assess the extent of the damage. Check for structural damage, mold growth, and any items that may need immediate attention. Take photos or videos as evidence for insurance claims.

Step 2: Remove Standing Water

Once you’ve assessed the damage, the next step is to remove any standing water. Use buckets, mops, or wet vacuums to extract the water from your home. Be cautious of potential electrical hazards and wear protective gear if necessary.

Step 3: Dry Out the Area

After removing standing water, it’s crucial to dry out the affected area properly. Open windows, use fans, or employ dehumidifiers to increase air circulation and speed up the drying process. This will help prevent mold growth and further damage.

Step 4: Salvage or Discard

Next, evaluate the items affected by water damage. Determine what can be salvaged through cleaning and drying, and what needs to be discarded. Be thorough in your assessment to avoid potential health hazards or future problems.

Step 5: Clean and Disinfect

To prevent mold growth and ensure a safe living environment, clean and disinfect all surfaces that came into contact with water. Use appropriate cleaning agents and follow recommended guidelines for effective sanitation.

Step 6: Repair and Restore

Once the area is dry and cleaned, it’s time to repair and restore any damaged structures or materials. This may involve fixing structural issues, replacing damaged flooring or walls, and repainting or refinishing surfaces. Hire professionals if needed to ensure proper repairs are made.

Step 7: Monitor for Mold

Even after completing the restoration process, it’s important to monitor for any signs of mold growth. Keep an eye out for musty odors, discolored patches on walls or ceilings, or increased allergy symptoms. If mold is detected, take immediate action to prevent further damage and health risks.

Step 8: Evaluate Prevention Measures

Finally, evaluate Finally, evaluate the prevention measures you can take to avoid future water damage. This may include installing a sump pump, waterproofing your basement, sealing gaps and cracks, or regularly inspecting and maintaining your plumbing system. Implement these measures to minimize the risk of future water damage.

Christina Hirth : Feedback-Based Development

Roman theatre in St. Albans, GB

Important things need to grow to last. The German says “gut ding will weile haben” – good things take time.

The Roman Theatre of Verulamium (St.Albans) built in about 140AD

I did it: almost exactly four years after Nick Tune suggested me a conference in London as the best place to start talking at conferences, I had my first in-person talk at the DDD Meetup in London. Given the timespan, you could say, “What is so special in this? Why should I continue reading?”. Well, you don’t need to 😀. For me, it feels like quite a wonder that by looking at where I was four years ago (I was completely unknown in the international community) and what happened in the meantime, I can put a ✅behind this bucket list item.

Writing about the last four years would transform this post into a small book – I won’t do that now. Instead, I will tell you a bit about the talk and how I applied the same ideas to prepare for it. The talk is about Feedback-driven Product Development. This post is about Feedback-driven Self-Development😉.

Shifting from Projects to Feedback-Based Product Development
slides on miro

With this talk, I wanted to show how broken our product development processes, long and short-term outcomes, hell, the whole industry is, and they don’t need to be! We have everything we need to improve our life as product developers to enjoy this most creative job, but instead, we feel frustrated, overwhelmed and not fulfilled. In the presentation, I talked about the three things organisations (or single persons) can use to change this.

Disclaimer: I don’t mean software developers here. I mean all the different roles and skills needed to create something good.

Now back to the story I want to tell you: how did I use these three ideas to develop the talk and myself at the same time?

Optimise For the Time to Learn

As I said, I have never written a talk with slides and all. I have even switched from Windows to Linux to never land in a situation where I needed to write a PowerPoint presentation. But the talk itself is only the output, it is not my goal. My goal is to learn if I can do this, if I am good at it. If I enjoy it? I started to speak in international circles on Virtual DDD, and the pandemic made it very easy to meet great people. After three years of interactions, it felt natural to me. We became online friends. Last year I proposed my first workshop at the biggest DDD conference in Europe because I wanted to meet them and knew that I wouldn’t be able to support the trip financially otherwise. It worked, and now I am part of this very special community. It stopped becoming a challenge; I needed something new: a talk presented on a podium, completely out of my comfort zone.

You need to know that I am not a consultant (and I still don’t want to become one), so there are not too many reasons for all the effort needed to travel abroad to conferences and give a high-quality workshop or talk. One (and still the main reason) is to meet and exchange with other nerds. The other is my personal development: can I do this? Where are my boundaries?

So that in January, Nick convinced me to dare the next step. We agreed on a date and on a (vague) topic and set the first milestone with this: learn. Learn about the fun, the (lack) of skills in presenting my thoughts, and the reaction of others. If they are interested at all in what I want to say. My slides (the output) needed to be good enough (on my own quality scale) so that I could achieve these goals.

Measure the Outcome

The outcome was great! Even if it was a complicated plan, everything worked out, and I was ready to go. This meetup, in a city where almost no one knew me (so that they were unbiased), with a topic which could have been everything or nothing, the splendid location at Mastercard providing the conference feeling – all this was on purpose to get the most honest feedback. After seeing several people nicking during the talk, making multiple connections on LinkedIn and mastodon directly after the session, and getting several “Thank you for addressing this” comments, I could tick one important question: people want to know what I am speaking about ✅

The question about joy, about having fun, was answered too: yes, I had fun. I had great conversations with myself while I was writing the talk, and I had better conversations with the people in the room ✅.

Embrace the Change

The best outcome I learned by giving this talk was that it is not good enough yet. Imagine the other situation: having it perfect for the first time. Where am I going from here? What a boring (hence scary) thought! After this first practice, I now know (and not guess) that I will need to rework everything, but my first “walking skeleton” is the right one; the first step was exactly in the right direction. The next iterations can come.

The next milestone is at the beginning of October at KanDDDinsky. The steps towards it will be small and several based on feedback from Nick, Andrea, or anyone up to it. My journey to find my boundaries can continue.

Manuela Rink: Residential Water Damage Restoration: How to Quickly Restore Your Home?

Whether it’s a burst pipe, a flooded basement, or a leaky roof, water damage in your home can quickly become a nightmare. Not only can it lead to costly repairs, but it can also pose health risks if left untreated. That’s why it’s essential to address the issue as soon as possible with residential water damage restoration services.

With so many restoration companies out there, it can be overwhelming to know where to start. Today we’ll discuss the necessary steps you should take as soon as possible after discovering water damage in your home. So keep reading for more information. When you need an useful content about water damage restoration, click over here.

Step-by-Step Guide to Quickly Restore Residential Water Damage

Here are some essential steps you need to follow when restoring residential water damage:

Step 1: Assess the Damage

The first step in any water damage restoration process is to assess the damage. This means identifying the source of the water and determining the extent of the damage. It’s important to assess any potential hazards to ensure everyone’s safety. Once you’ve identified the source, shut off the water or electricity if necessary. Remember, if the water damage is severe or contaminated, it’s best to contact a professional rather than attempting to fix it yourself.

Step 2: Remove Any Standing Water

The next step is to remove any standing water from your home. A professional restoration company will use industrial-grade equipment such as pumps, vacuums, and dehumidifiers to speed up the process. Standing water can quickly cause mold and mildew to form, which can be hazardous to your health if not treated quickly.

Step 3: Dry and Dehumidify

After all standing water has been removed, dry and dehumidify the affected areas to prevent further damage. A professional restoration service will use specialized equipment such as air movers and dehumidifiers to ensure that the area is completely dry. They’ll also inspect and replace any damaged insulation or drywall if necessary.

Step 4: Cleaning and Sanitizing

Once the area is completely dry, it’s time to clean and sanitize the affected area. This will ensure that any potential contaminants such as mold and mildew are eliminated. A professional cleaning and sanitizing company will use specialized chemicals and equipment to clean and sanitize your home.

Step 5: Restoration

The final step in the water disturbance restoration process is restoration. This means repairing any damage that has occurred to the property such as replacing drywall, flooring, or insulation. A professional restoration company will ensure that the restoration process is done correctly, preventing any further damage or future issues.

Take Quick Action to Overcome Water Damage

Water damage can be devastating to homeowners, but with the right resources and guidance, it can be overcome. Remember to always address the issue immediately and avoid attempting to solve it yourself if the damage is severe. It’s important to find a reputable restoration company that you can trust to get your home back to its former state. By following the steps mentioned above, you’ll be well on your way to restoring your home and peace of mind.

Holger Schwichtenberg: Neu in .NET 7.0 [19]: Statistiken für den MemoryCache

Die Klasse zum Repräsentieren des Cache im Arbeitsspeicher bietet in .NET 7.0 einige Funktionen für Statistiken der Nutzung des Zwischenspeichers.

Holger Schwichtenberg: Neu in .NET 7.0 [18]: Leistung und Anpassen des Ahead-of-Time-Compilers

Der AOT-Compiler erzeugt ressourcensparende Binaries, aber seine volle Stärke spielt er erst mit den richtigen Einstellungen in der Konfiguration aus.

Holger Schwichtenberg: Neu in .NET 7.0 [17]: Ahead-of-Time-Compiler für Konsolenanwendungen

Der von Microsoft lange Zeit angekündigte Ahead-of-Time-Compiler "Native-AOT" lässt sich erstmalig in .NET 7 nutzen – zumindest in Konsolenprojekten.

Holger Schwichtenberg: Neu in .NET 7.0 [16]: Anpassen des Docker-Deployments mit .NET CLI

Verschiedene Optionen für dotnet publish erlauben individuelle Anpassungen der ohne Dockerfile mit .NET CLI angelegten Docker-Deployments.

Holger Schwichtenberg: Neu in .NET 7.0 [15]: Docker-Deployment mit .NET CLI ohne Dockerfile

Ein neues NuGet-Paket kümmert sich um die passende Docker-Konfiguration für containerisierte .NET-Anwendungen.

Don't contact us via this (fleischfalle@alphasierrapapa.com) email address.