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.

Stefan Henneken: Buchveröffentlichung „Anwendung der SOLID-Prinzipien mit der IEC 61131-3“

Auf Grund der regelmäßigen Artikelaufrufe über die SOLID-Prinzipien hatte ich mich vor einiger Zeit dazu entschlossen, diese Serie auch in Form eines kleinen Buches anzubieten. Ab sofort kann dieses Buch (gedruckt, als auch als E-Book) in allen bekannten Buchhandlungen und digitalen Plattformen bestellt werden. Neben den SOLID-Prinzipien werden in dem Buch auch die Prinzipien KISS, DRY, LoD und YAGNI angesprochen.

Natürlich stehen die bisherigen Artikel auch weiterhin hier auf dem Blog kostenlos zur Verfügung. Somit kann jeder frei entscheiden, ob man die Artikel lieber online, auf dem E-Book Reader oder als gedrucktes Buch lesen möchte. Aktuell liegt das Buch nur in Deutsch vor. Ich gehe aber davon aus, dass ich in einiger Zeit auch die englische Variante anbieten kann.

Der Preis für das knapp 100 Seiten umfassende Buch liegt für die gedruckte Variante (ISBN-13: 9783734746857) bei 6,99 € und für das E-Book (ISBN-13: 9783757870706) bei 4,99 €.

Holger Schwichtenberg: Blog in eigener Sache: Infotag Online, Developer-Update 2023 zu .NET 8.0 und KI

Der Online-Infotag widmet sich diversen Themen rund um C#, .NET und KI-unterstützte Softwareentwicklung.

Holger Schwichtenberg: Neu in .NET 7.0 [14]: Stilauswahl für neue WebAPI-Projekte

Wer WebAPI-Projekte mit ASP.NET Core erstellt, hat die Wahl zwischen dem in .NET 6.0 eingeführten Minimal-API-Stil und dem ursprünglichen API-Stil.

Holger Schwichtenberg: Neu in .NET 7.0 [13]: Vereinheitlichungen bei dotnet new

Microsoft hat in .NET 7.0 den Umgang mit Befehlsnamen und deren Parametern auf der Kommandozeilen vereinheitlicht.

André Krämer: Lebensdauer von SQLite-Datenbankverbindungen in .NET MAUI und Xamarin.Forms: Kurz- oder Langlebig?

Kürzlich erhielt ich eine Frage von einem Leser meines Buches Cross-Plattform-Apps entwickeln mit Xamarin.Forms, der auf Seite 336 des Buches auf meine Behandlung von SQLite-Datenbankverbindungen in Xamarin.Forms aufmerksam wurde. Der Leser bemerkte, dass ich im Beispielcode eine Verbindung im Konstruktor öffnete und diese dauerhaft geöffnet hielt, ohne Close oder Dispose aufzurufen. Der Leser befürchtete, dass dies zu Speicherlecks oder sogar Datenverlust führen könnte und wies darauf hin, dass in Foren oft empfohlen wird, Verbindungen nur kurz zu öffnen und sofort wieder zu schließen.

Golo Roden: Livestream-Special von the native web: enterJS, Gäste und Gewinnspiel

Der Livestream bringt am Mittwoch um 18 Uhr spannende Einblicke und Hintergründe zur enterJS, interessante Gespräche mit Gästen und ein Gewinnspiel.

Holger Schwichtenberg: Neu in .NET 7.0 [12] : Rückkehr des klassischen Startcodes in Projektvorlagen

.NET 7.0 bietet für Konsolen- und Webprojekte wieder den klassischen Startcode mit einer Programklasse inklusive Main()-Methode in den Projektvorlagen.

Thorsten Hans: YouTube Premium much cheaper with VPN Argentina

Is it possible to get YouTube Premium much cheaper with a VPN? Yes, as it turns out, YouTube Premium is offered at a very cheap price in Argentina. We’ll show you a simple trick that will let you enjoy YouTube Premium (without ads) at a much cheaper price. With a reliable VPN service, like the one from CyberGhost* or the slightly more expensive from ExpressVPN*, you can watch YouTube Premium for much cheaper. Just read on to find out how you can use the VPN service and why it’s the easiest (and safest) way to get YouTube Premium at a reasonable price.

VPN Provider Description Rating
CyberGhost Best value overall
Get CyberGhost
ExpressVPN High class VPN
Get ExpressVPN
Private Internet Access Good VPN, great value
Get PIA VPN

YouTube Premium is very cheap in Argentina

YouTube advertising is really annoying. If you want to enjoy the video platform ad-free, you have to pay for YouTube Premium. However, prices vary depending on the country. In Germany, for example, YouTube charges a very high price per month for the Premium variant.

Let’s now take a look at the prices for YouTube Premium in Argentina:

Single tariff: 389 ARS / 2,12 Euro per month

Family tariff: 699 ARS / 3,82 Euro per month

Those Argentinien prices are way lower in comparison with most of the other countries. In Germany, for example, you have to pay 11.99 euros per month for the single rate. The family plan costs 17.99 euros per month. This is a significant saving that justifies the use of a VPN in any case.

How to use a VPN for YouTube Premium – a quick guide

If you want to take advantage of the low YouTube Premium prices in Argentina, you first need to create an account abroad. And this is where a VPN service comes in handy. With a VPN, you can go to virtually any country in the world and easily bypass digital country blocks.

Time needed: 15 minutes

Follow these simple steps and watch YouTube Premium at a much lower price via a VPN server in Argentina:

  1. Choose a VPN

    We recommend two trusted providers with good reputation – CyberGhost*. CyberGhost offers 48 servers in Argentina. Again, the speed is perfect for the purpose.

  2. Install the VPN app/client

    Once you have chosen a VPN service, you should install the software and launch the program.

  3. Choose a server in Argentina

    Open the app/client. Then open the server or country selector and choose Argentina. Once you have connected to the Argentine VPN server, go to the YouTube Premium website.
    Check if you are really connected to the Argentine YouTube site – the YouTube logo should have the abbreviation “AR” in the upper left corner. The prices should be displayed in Argentine pesos (ARS).

  4. Create a new Google Account

    You need a Google Account to get YouTube Premium. Create a new Google Account. You can set it up later as a secondary YouTube account. Go to the YouTube Premium homepage. Click Sign in and follow the steps to set up the new Google Account.

  5. Go to YouTube Premium

    If you now have a new Google account, go back to the YouTube Premium home page. Again, make sure the VPN connection to Argentina is up. When you’re logged in, you should see your shortcode in a colored circle at the top right of the site. Now:

  6. Fill out the form

    On the home page, click the Free Trial button for the Standard Package. For the Family Package click on the Family Membership link. Then click on Try for free.
    You will see a form to fill out. Enter your billing address and credit card information. Important: Visa credit cards are no longer accepted, but you can use other credit cards. Enter an Argentine address. Choose a random address through Google Maps and make sure you enter the correct zip code and province. Complete your subscription by clicking the Buy button.

  7. From now on, enjoy YouTube Premium at a great price!

    From now on, you can sign in with your new Google Account and enjoy YouTube Premium at a very affordable price.

YouTube Premium – The advantages

YouTube Premium means videos without ads. That’s a big plus, because we all know how annoying those ads can be. They can really ruin your online experience.

With the Premium subscription, you can also download on the go. So you can download videos and music quickly and easily. You also get background playback – the feature plays videos in the background without interruption, you can open another app or even turn off the screen.

YouTube Music Premium, YouTube Kids, and YouTube Originals are part of the Premium plan. YouTube Originals includes original movies, series, and live events. While these events, movies, and series can occasionally be seen on the YouTube Originals channel, only Premium members can enjoy them without ads, watch all episodes, and get access to interesting bonus material. You also get the YouTube Gaming app.

FAQs – Frequently Asked Questions

Is it legal to buy YouTube Premium in Argentina with a VPN?

Subscribing to YouTube Premium in Argentina is perfectly legal, but you are still in violation of the provider’s terms of service. YouTube is aware that there are geographical restrictions. The platform requires its users not to provide inaccurate or misleading information to falsely impersonate residents of a country where the paid services are accessible. Violations of YouTube’s terms of use may result in account suspension or deletion.

Can I use a free VPN service for YouTube Premium in Argentina?

It would work if you could find a VPN provider with reliable free servers in Argentina. I have not been able to do that.
If you use streaming platforms frequently, it would generally be a good idea to use a reliable paid VPN service like ExpressVPN* and CyberGhost*.

Why is YouTube Premium no longer an option for India?

India offers cheap YouTube Premium prices. But because of some new laws in India, most of the top VPN providers have pulled out of the country. The new law requires VPNs to log their users’ traffic. VPNs like CyberGhost continue to operate servers with India as their geolocation, but in some cases these servers cannot be reliably cloaked. As a result, YouTube either detects that you’re using a VPN or displays incorrect prices.

The post YouTube Premium much cheaper with VPN Argentina appeared first on xplatform.rocks.

Thorsten Hans: Stream Russian TV over the Internet

Are you wondering how to stream Russian TV over the Internet? I have a great news for you. You can do that with CyberGhost*! It is one of the few VPN providers that still operates servers in Russia.

With CyberGhost you can stream Russian TV over the Internet.

Quick guide: Watch Russian TV online

In order to watch all Russian TV online, you need a VPN that provides servers in Russia. So you need a Russian IP address. There are not so many of them anymore, because the legal situation in Russia regarding VPNs is questionable.

Time needed: 10 minutes

How to get a Russian IP address outside of Russia to stream Russian TV

  1. Take a VPN with servers in Russia

    One of the few VPN providers that still runs well-functioning servers in Russia is CyberGhost*. The good thing about the service is that it offers a money-back guarantee on the long-term package and is also one of the cheapest providers on the market.

  2. Install VPN apps

    Consider on which devices you want to watch Russian TV. As with many VPNs, you can install CyberGhost on multiple devices and that’s why you can run it on your smartphone, laptop and tablet simultaneously. Currently, CyberGhost allows 7 simultaneous connections and that’s a lot. The VPN supports the most popular operating systems and devices: Android, Windows, iOS, macOS and Linux as well.

  3. Connect to a Russian server

    For Russian TV programs you need a Russian IP address. Therefore, you need to connect to a server in Russia. Then you can stream Russian TV online. That’s it. That’s all you really need to do. It’s actually as simple as it sounds.

Stream better protected

Internet censorship and surveillance is a problem in Russia and therefore you can protect yourself better with a VPN. Your Internet traffic is encrypted by the VPN and no one except the VPN provider can see what you are doing online. Of course, you have to have a certain trust in your VPN provider.

CyberGhost has a no-logs policy and does not collect any data. That’s why it can’t share anything with authorities and third parties, even if the service is asked for it.

Russian broadcasters use geo-blocking and then you need a Russian IP address to watch the corresponding show.

These Russian channels work with VPN

Of course, we tested whether you can safely stream Russian TV over the Internet with a VPN. We took a look at the most popular services and platforms.

Important note: Some of the listed services and streams might be illegal. We could not 100% understand what is legal and illegal because we don’t speak the language and don’t know exactly what the law is. So please inform yourself what is legal and illegal in your country so that you don’t get into trouble!

A popular Russian sports channel is Match TV. There you can find Bundesliga, Premier League, Formula 1 and how to stream Champions League for free. There are many sports events that you can watch there for free in Russian. Match TV belongs to the Gazprom Group.

Among the most important Russian TV channels is ntv.ru (state TV channel from Moscow).

1TV.ru is the first channel of the semi-public Russian broadcaster Perwy. I was also able to watch this portal with CyberGhost* without any problems.

Equally interesting is Planeta-Online.tv. The online TV portal provides access to eight Russian TV channels.

Other streams and channels you can watch with a VPN

Here are a few more portals that work with a VPN, but they can be shady. Extreme caution is advised here, so that you don’t get into conflict with the law.

  • Fubo TV
  • Rutube
  • TVCenter
  • Okko
  • STS
  • Videomore
  • TVZavr
  • Russian VoD
  • Kinopoisk
  • Ren TV
  • Amediateka
  • Zoomby
  • KinoPoisk HDTV
  • TV-Novosty
  • TV-Mania
  • TV-Pressa
  • NTV Plus
  • YuppTV
  • TV 1000
  • TVCatchup

FAQ – Streaming Russian TV

Here are some answers to questions that interest you.

Can I stream Russian TV with a free VPN?

I doubt it, at least for the shows that are geoblocked. I don’t know of any free VPN that offers servers in Russia. Even if they do, reputable free VPNs have severe limitations, such as data volume. Then you can only stream for a short time and the pleasure quickly comes to an end. The problem at this point is that there are many dubious free VPN providers that are not trustworthy. They collect and sell your data to third parties, and in the worst case, they install malware and trackers on your device. Reputable providers like CyberGhost are cheap and have no restrictions. Moreover, they offer functioning servers in Russia.

Does Russian streaming offer other languages?

As far as I saw during my tests, you can’t switch to any other language. I was able to use the translation feature of the browsers to help me navigate the site more easily. However, the streaming, i.e. the comments and the language itself always remained Russian.

Which is the best Russian channel for sports?

If you are interested in sports events such as the Champions League, Formula 1 and so on, then Match TV is definitely your first port of call. The other channels are interesting for you if you are interested in news or other Russian programs. So it depends on your needs what is the best Russian channel.

The post Stream Russian TV over the Internet appeared first on xplatform.rocks.

Stefan Henneken: IEC 61131-3: SOLID – The Open/Closed Principle

Inheritance is a popular method for reusing existing function blocks. It enables new methods and properties to be added or existing methods overwritten without requiring access to the source code for the base function block. Designing software so that it can be extended without modifying the existing code is the key concept behind the Open/Closed Principle (OCP). But using inheritance also has disadvantages. These disadvantages can be minimised by employing interfaces – and this is not the only advantage of this method.

To put it another way, software behaviour should be open to extension without needing to modify the software. Based on our example from my previous posts, we’re going to develop a function block for managing lamp control sequences. We will then add additional functionality to extend this function block. We will use this example to illustrate the key concept underlying the Open/Closed Principle (OCP).

Starting situation

Our main starting point is the function block FB_SequenceManager. This provides access to the individual steps in a sequence via the aSequence property. The Sort() method provides a means to sort the list in accordance with various criteria.

The aSequence property is an array and contains elements of type ST_SequenceItem.

PROPERTY PUBLIC aSequence : ARRAY [1..5] OF ST_SequenceItem

To keep our example simple, we define our array as having fixed upper and lower bounds of 1 and 5. Array elements are of type ST_SequenceItem, which contains a unique ID (nId), the output value for the lamps (nValue) and the duration (nDuration) before switching to the next output value.

TYPE ST_SequenceItem :
STRUCT
  nId        : UINT;
  nValue     : USINT(0..100);
  nDuration  : UINT;
END_STRUCT
END_TYPE

In this example, we will not concern ourselves with methods for processing the sequence. Our example does, however, include a Sort() method for sorting the list by various criteria.

METHOD PUBLIC Sort
VAR_INPUT
  eSortedOrder : E_SortedOrder;
END_VAR

The list can be sorted in ascending order only by nId or nValue.

TYPE E_SortedOrder :
(
  Id,
  Value
);
END_TYPE

In the Sort() method, the eSortedOrder input parameter determines whether the list is sorted by nId or nValue.

CASE eSortedOrder OF
  E_SortedOrder.Id:
    // Sort the list by nId
    // …
  E_SortedOrder.Value:
    // Sort the list by nValue
    // …
END_CASE

Our example is a simple monolithic application which can be put together quickly to meet our requirements.

The UML diagram shows the monolithic structure of the application very clearly:

This does not, however, take account of the amount of work required to realise future extensions.

Sample 1 (TwinCAT 3.1.4024) on GitHub

Extension of the implementation

We are going to extend the application so that, in addition to nId and nValue, we can also sort the list by nDuration. Currently, the list is always sorted in ascending order. We would also like to be able to sort it in descending order.

How can we modify our example to meet these two client requirements?

Approach 1: Quick & dirty

One approach is to simply extend the existing Sort() method so it can also sort by nDuration. To do this, we add the field eDuration to E_SortedOrder.

TYPE E_SortedOrder :
(
  Id,
  Value,
  Duration
);
END_TYPE

We also need a parameter to indicate whether we want to sort in ascending or descending order:

TYPE E_SortedDirection :
(
  Ascending,
  Descending
);
END_TYPE

So the Sort() method now takes two parameters:

METHOD PUBLIC Sort
VAR_INPUT
  eSortedOrder      : E_SortedOrder;
  eSortedDirection  : E_SortedDirection;
END_VAR

The Sort() method now contains two nested CASE statements. The outermost of these deals with the sort direction, the innermost with the parameter by which to sort the list.

CASE eSortedDirection OF
  E_SortedDirection.Ascending:
    CASE eSortedOrder OF
      E_SortedOrder.Id:
        // Sort the list by nId in ascending order
        // …
      E_SortedOrder.Value:
        // Sort the list by nValue in ascending order
        // …
      E_SortedOrder.Duration:
        // Sort the list by nDuration in ascending order
        // …
    END_CASE
  E_SortedDirection.Descending:
    CASE eSortedOrder OF
      E_SortedOrder.Id:
        // Sort the list by nId in descending order
        // …
      E_SortedOrder.Value:
        // Sort the list by nValue in descending order
        // …
      E_SortedOrder.Duration:
        // Sort the list by nDuration in descending order
        // …
    END_CASE
  END_CASE
END_CASE

This approach is quick to implement. For a small application with a reasonably small amount of source code, this is absolutely a reasonable approach. But for this approach to be feasible, we have to have access to the source code. In addition, we need to ensure that FB_SequenceManager isn’t shared with other projects via, for example, a PLC library containing FB_SequenceManager. By adding a parameter to the Sort() method, we have also changed its signature. This means that program components that call this method with just a single parameter will no longer compile.

The UML diagram shows clearly that the structure is unchanged – it’s still a highly monolithic application:

Sample 2 (TwinCAT 3.1.4024) on GitHub

Approach 2: Inheritance

Another way to add features to the application is to use inheritance. This allows us to extend function blocks without having to modify the existing function block.

We start by creating a new function block which inherits from FB_SequenceManager:

FUNCTION_BLOCK PUBLIC FB_SequenceManagerEx EXTENDS FB_SequenceManager

The new function block contains a SortEx() method which takes two parameters specifying the required sort direction and order:

METHOD PUBLIC SortEx : BOOL
VAR_INPUT
  eSortedOrder      : E_SortedOrderEx;
  eSortedDirection  : E_SortedDirection;
END_VAR

Once again we add a data type E_SortedDirection which specifies whether the list should be sorted in ascending or descending order:

TYPE E_SortedDirection :
(
  Ascending,
  Descending
);
END_TYPE

Rather than extending E_SortedOrder, we create a new data type:

TYPE E_SortedOrderEx :
(
  Id,
  Value,
  Duration
);
END_TYPE

We can now implement the required sort functions in the SortEx() method.

To sort in ascending order, we can use the Sort() method from the base function block (FB_SequenceManager). We don’t need to reimplement the existing sorting algorithm. All we need to do is add the additional sort type:

CASE eSortedOrder OF
  E_SortedOrderEx.Id:
    SUPER^.Sort(E_SortedOrder.Id);
  E_SortedOrderEx.Value:
    SUPER^.Sort(E_SortedOrder.Value);
  E_SortedOrderEx.Duration:
    // Sort the list by nDuration in ascending order
    // …
END_CASE

Sorting in descending order needs to be programmed from scratch, however, as this cannot be achieved using existing methods.

If a new function block extends an existing function block, the new function block inherits the functionality of the base function block. The addition of further methods and properties enables it to be extended without needing to modify the base function block (open for extension). By using libraries, it’s also possible to protect the source code from modification (closed for modification).

Inheritance is therefore one way of implementing the Open/Closed Principle (OCP).

Sample 3 (TwinCAT 3.1.4024) on GitHub

This approach does, however, have two disadvantages.

Excessive use of inheritance can end up generating complex hierarchies. A child function block is absolutely dependent on its base function block. If new methods or properties are added to the base function block, every child function block will also inherit these new elements (if they are PUBLIC), even if the child function block has no intention of exposing these elements externally.

In some circumstances, extension by inheritance is only possible where the child function block has access to internal state information from the base function block. Access to these internal elements can be enabled by marking them as PROTECTED. This restricts access to child function blocks only.

In the example given above, the only reason we were able to add the sorting algorithms was because the setter for the aSequence property was declared as PROTECTED. If we did not have write access to the aSequence property, the child function block would not be able to modify the list, so would not be able to sort it.

This means, however, that the developer coding this function block always has to take into consideration two use cases. Firstly, a user making use of the function block’s public methods and properties. Secondly, users using the function block as a base function block and adding new functionality via PROTECTED elements. But which internal elements need to be marked as PROTECTED? And to enable their use, these elements also need to be documented.

Approach 3: Additional interface

Another approach is to use interfaces rather than inheritance. This, however, needs to be considered during the design phase.

If our aim is to design FB_SequenceManager so that users can add whatever sorting algorithms they want, then we should remove the code for sorting the list. The sorting algorithm should instead access the list via an interface.

In our example, we would add the interface I_SequenceSortable. This interface contains the SortList() method, which contains a reference to the list to be sorted.

METHOD SortList
VAR_INPUT
  refSequence  : REFERENCE TO ARRAY [1..5] OF ST_SequenceItem;
END_VAR

Next we create the function blocks containing the various sorting algorithms, each of which implements the I_SequenceSortable interface. As an example, we will take the function block for sorting by nId in ascending order.

FUNCTION_BLOCK PUBLIC FB_SequenceSortedByIdAscending IMPLEMENTS I_SequenceSortable

We can call the function block whatever we want; the crucial point is that it implements the I_SequenceSortable interface. This ensures that FB_SequenceSortedByIdAscending contains the SortList() method. The actual sorting algorithm is implemented in the SortList() method.

METHOD SortList
VAR_INPUT
  refSequence  : REFERENCE TO ARRAY [1..5] OF ST_SequenceItem;
END_VAR
// Sort the list by nId in ascending order
// …

The Sort() method of FB_SequenceManager takes a parameter of type I_SequenceSortable. When calling the Sort() method we pass to it a function block (e.g. FB_SequenceSortedByIdAscending) which implements the I_SequenceSortable interface and therefore also contains the SortList() method. FB_SequenceManager’s Sort() method calls SortList() and passes to it a reference to the aSequence list.

METHOD PUBLIC Sort
VAR_INPUT
  ipSequenceSortable  : I_SequenceSortable;
END_VAR
IF (ipSequenceSortable <> 0) THEN
  ipSequenceSortable.SortList(THIS^._aSequence);
END_IF

This means that a reference to the list to be sorted is passed to the function block containing the implemented sorting algorithm.

We create a separate function block for each sorting algorithm. This means we have access both to FB_SequenceManager containing the Sort() method, and to function blocks containing the sorting algorithms and implementing the I_SequenceSortable interface.

When it calls the Sort() method, FB_SequenceManager passes to it a function block (in our case FB_SequenceSortedByIdAscending). This function block contains the I_SequenceSortable interface subsequently used to call the SortList() method.

PROGRAM MAIN
VAR
  fbSequenceManager              : FB_SequenceManager;
  fbSequenceSortedByIdAscending  : FB_SequenceSortedByIdAscending;
  // …
END_VAR
fbSequenceManager.Sort(fbSequenceSortedByIdAscending);
// …

This approach avoids the use of inheritance. The sorting algorithm function blocks could employ their own inheritance hierarchy if required. These function blocks could also implement additional interfaces, since it is possible to implement multiple interfaces.

Using this interface realises a clear separation between data storage (the list) and data processing (sorting). The aSequence property does not need write access. We also avoid the need to access internal FB_SequenceManager variables.

In addition, we no longer need the E_SortedOrder and E_SortedDirection data types. The sort type is determined solely by which function block we pass to Sort().

We can also add new sorting algorithms without needing to modify or change existing elements.

Sample 4 (TwinCAT 3.1.4024) on GitHub

Optimization analysis

There are various methods for extending the functionally of an existing function block without having to modify it. As well as inheritance – a key feature of object-oriented programming (OOP) – interfaces may provide a better alternative.

Using interfaces brings greater decoupling. But the individual interfaces do have to be implemented in the software design. This means that we need to consider in advance which areas need to be abstracted via interfaces and which don’t.

With inheritance too, when we develop a function block we have to consider which internal elements should be made accessible (by using the PROTECTED keyword) to function blocks derived from it.

The definition of the Open/Closed Principle

The Open/Closed Principle (OCP) was originated in 1988 by Bertrand Meyer. It states:

Software entities should be open for extension, but closed for modification.

Software entity: This means a class, function block, module, method, service, etc.

Open: The behaviour of a software entity should be able to be extended.

Closed: This extensibility should not be achieved by modifying existing software.

When Bertrand Meyer defined the Open/Closed Principle (OCP) in the late 1980s, the focus was on C++ as a programming language. He used the concept of inheritance, a familiar concept in the object-oriented programming world. Object-orientated programming – at the time a fairly young discipline – was seen as promising big improvements in terms of reusability and maintainability as a result of the ability to reuse classes as base classes for new classes.

When Robert C. Martin took up Meyer’s principle in the 1990s, he took a different approach to its technical implementation. C++ allows the use of multiple inheritance, which is rare in more recent programming languages. Consequently, Robert C. Martin focused on the use of interfaces. More information can be found in his book (Amazon ad link *) Clean Architecture: A Craftsman’s Guide to Software Structure and Design.

Summary

Adhering to the Open/Closed Principle (OCP) does carry a risk of overengineering. We should only implement extensibility where it is actually needed. It is impossible to design software so that every conceivable extension can be implemented without needing to modify the source code.

This concludes my series of posts on SOLID principles. Other principles are of course available, including Keep It Simple, Stupid (KISS), Don’t Repeat Yourself (DRY), Law Of Demeter (LOD) and You Ain’t Gonna Need It (YAGNI). What all these principles have in common is the goal of making software more maintainable and more reusable.

Holger Schwichtenberg: Neu in .NET 7.0 [11]: Autovervollständigung für Vorlagennamen bei dotnet new

Das aktuelle .NET-Release zeigt Vorschläge für Befehle im Kommandozeilenfenster. Die Autovervollständigung muss man allerdings zunächst aktivieren.

Jürgen Gutsch: Application Security at YOO

For about a year, I was working on a pretty exciting project. I defined and created a new role for our company that is responsible for application security. Actually, application security was never a missing aspect of our development process. All my colleagues were great developers and highly motivated to create secure applications.

The actual problem was a missing standard, that sets up every project in the same secure way, which helps the QA to also test security aspects, use the same tools to improve the software quality and software security and keep the awareness on security during the entire development process.

Defining the new role

Defining and creating this new role also means that I will take over this new role and be responsible, to ensure and to maintain the security standards throughout the entire company. I will also be responsible to keep awareness about security throughout the entire company and to train the developers, the DevOps responsible person as well as the QA. I am not the only person that is responsible for application security in general. My job will be to make all colleagues feel responsible to create secure applications. That they all have security in mind, that all features will be analyzed from the security perspective as well.

And this is why the process of secure software development doesn't start with development or DevOps.

Adding security to the company

Actually, the secure software development process starts at the sales phase. The salesperson needs to know what type of customer he is selling our services to, what type of data the potential customer will be handle with the new project, and what type of possible risks there are. The salesperson needs to know what level of security he needs to sell. (Exactly, we need to sell security. See next section why)

The process continues with the requirements engineering, even the UX and UI specialists need to take care of security. DevOps is following, by setting up the secure software development infrastructure and secure deployments per project. DevOps is also supporting the developers with the right tools that check for software quality and possible vulnerabilities and code flaws while building and delivering the software. In the development phase, required security aspects need to be implemented and QA needs to know how to test this. Maybe tooling will support the QA to make automated security tests.

Selling security

True, we need to sell levels of security because ensuring application security needs some effort. The more secure the more effort during development and afterward, while ensuring and testing the application security. A potential customer in a sensitive or risky environment should know that security is not for free. A bank, a power plant, and other big and risky industry are paying for security personnel that keeps unauthorized people outside of their restricted areas. Such companies should be aware and willing to pay for implementing higher security mechanisms to keep unauthorized people out of their digitally restricted areas as well.

Actually, application security needs to be ensured in every project and the basic level of security won't be charged separately.

What are the standards we use?

It is the OWASP foundation that helps me dive into new topics. We are going to implement the OWAS Application Security Verification Standard (ASVS) and the mobile version of it (MASVS). ASVS already is divided into three levels of security. Level 1 is the basic level of security that all projects need to implement. Actually, Level 1 is quite basic and despite just a few topics, this is all stuff we as developers almost already knew, used, and implemented in the past. If we have thought about it and if the project pressure wasn't that high. Levels 2 and 3 are adding more security mechanisms to the projects to handle sensitive and critical data and infrastructure.

This standard is helping us like a blueprint for all our projects to keep the levels of security and it helps our QA to know what to test from the security point of view.

Actually, since ASVS is adopting and covering many other standards as well, we will be safe with future security audits, no matter what standard will be used during a possible audit.

Will YOO be a secure software company?

The company already creates secure software. Since it was more or less a side aspect in the past, we'll now focus on security by following the standards and the process we have implemented.

So, yes, we can now call ourselves a secure software company. But we are not certified somehow. OWASP and ASVS are no badges nor provide certificates we can put proudly and high-nosed on our website. But we can proudly mention that we are following a standard that was created by well-known and independent security experts.

My main role is still a software engineer :-)

The application security role is only an additional role to my position as a software engineer. In a midsized company like the YOO ensuring secure software is not such a high effort that it is needed to create a new position like an application security engineer. And therefore it is just a new additional role for me.

Despite that, my job title will change a little bit and will be called Software & AppSec Engineer.

Learning about application security

Actually, application security as a global topic was kinda new to me and I never expected that it is needed to have the entire company involved. But that also was the fun part: Talking to other disciplines and talking to people that are not really involved in my day-to-day business. It is not completely technical to implement application security in a software company.

As mentioned, the website of the OWASP Foundation points me to various learning resources. OWASP is full of projects to learn about application security. You might know the OWASP Top 10 list of security risks. I already mentioned the ASVS. But there is a ton more.

Another great learning resource is the Twitter feed of Tanya Janka. Her talks about application security are amazing and her book is a great read, even on vacation at the beaches of Greece while the kids are playing:

Learning about AppSec at the beach of Kos. The Sea and playing kids in the background

If you want to learn about application security, follow her on Twitter, read her blog, read her book, and watch her talks. You also need to dive into the OWASP website and the various projects of the foundation.

Furthermore

And maybe, you as a software-producing company would like to adopt the same standards and processes. If you would like to know, how we created and implemented the secure software process, feel free to ask. If you need help to make your software development process more secure, we would be happy to help as well.

Learn more: https://www.yoo.digital/applicationsecurity

Conclusion

I'm happy to start working on my new role officially this week and I'm happy to bring the YOO a step further in creating and delivering high-quality and secure software. I'm also pretty excited about how it will go and grow over time. The implementation of a secure software process will never be complete and needs to be adjusted whenever it's needed. It is a living process that needs reviews and adjustments regularly.

Holger Schwichtenberg: Neu in .NET 7 [10]: Generische Mathematik

.NET 6.0 hat einige generische Mathematikoperationen für beliebige Zahlentypen eingeführt, die im aktuellen .NET produktionsreif sind.

Holger Schwichtenberg: Neu in .NET 7 [9]: Überladen von Operatoren in Schnittstellen ab C# 11.0

Die jüngste C#-Version ermöglicht das Überladen von Operatoren nicht nur in Klassen, sondern auch in Interfaces.

Code-Inside Blog: First steps with Azure OpenAI and .NET

The AI world is rising very fast these days: ChatGPT is such an awesome (and scary good?) service and Microsoft joined the ship with some partner announcements and investments. The result is of these actions is, that OpenAI is now a “first class citizen” on Azure.

So - for the average Microsoft/.NET developer this opens up a wonderful toolbox and the first steps are really easy.

Be aware: You need to “apply” to access the OpenAI service, but it took less then 24 hours for us to gain access to the service. I guess this is just a temporary thing.

Disclaimer: I’m not an AI/ML engineer and I only have a very “glimpse” knowledge about the technology behind GPT3, ChatGPT and ML in general. If in doubt, I always ask my buddy Oliver Guhr, because he is much smarter in this stuff. Follow him on Twitter!

1. Step: Go to Azure OpenAI Service

Search for “OpenAI” and you will see the “Azure OpenAI Service” entry:

x

2. Step: Create a Azure OpenAI Service instance

Create a new Azure OpenAI Service instance:

x

On the next page you will need to enter the subscription, resource group, region and a name (typical Azure stuff):

x

Be aware: If your subscription is not enabled for OpenAI, you need to apply here first.

3. Step: Overview and create a model

After the service is created you should see something like this:

x

Now go to “Model deployments” and create a model - I choosed “text-davinci-003”, because I think this is GPT3.5 (which was the initial ChatGPT release, GPT4 is currently in preview for Azure and you need to apply again.

x

My guess is, that you could train/deploy other, specialized models here, because this model is quite complex and you might want to tailor the model for your scenario to get faster/cheaper results… but I honestly don’t know how to do it (currently), so we just leave the default.

4. Step: Get the endpoint and the key

In this step we just need to copy the key and the endpoint, which can be found under “Keys and Endpoint”, simple - right?

x

5. Step: Hello World to our Azure OpenAI instance

Create a .NET application and add the Azure.AI.OpenAI NuGet package (currently in preview!).

dotnet add package Azure.AI.OpenAI --version 1.0.0-beta.5

Use this code:

using Azure.AI.OpenAI;
using Azure;

Console.WriteLine("Hello, World!");

OpenAIClient client = new OpenAIClient(
        new Uri("YOUR-ENDPOINT"),
        new AzureKeyCredential("YOUR-KEY"));

string deploymentName = "text-davinci-003";
string prompt = "Tell us something about .NET development.";
Console.Write($"Input: {prompt}");

Response<Completions> completionsResponse = client.GetCompletions(deploymentName, prompt);
string completion = completionsResponse.Value.Choices[0].Text;

Console.WriteLine(completion);

Console.ReadLine();

Result:

Hello, World!
Input: Tell us something about .NET development.

.NET development is a mature, feature-rich platform that enables developers to create sophisticated web applications, services, and applications for desktop, mobile, and embedded systems. Its features include full-stack programming, object-oriented data structures, security, scalability, speed, and an open source framework for distributed applications. A great advantage of .NET development is its capability to develop applications for both Windows and Linux (using .NET Core). .NET development is also compatible with other languages such as

As you can see… the result is cut off, not sure why, but this is just a simple demonstration.

Summary

With these basic steps you can access the OpenAI development world. Azure makes it easy to integrate in your existing Azure/Microsoft “stack”. Be aware, that you could also use the same SDK and use the endpoint from OpenAI. Because of billing reasons it is easier for us to use the Azure hosted instances.

Hope this helps!

Video on my YouTube Channel

If you understand German and want to see it in action, check out my video on my Channel:

Code-Inside Blog: How to fix: 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine

In our product we can interact with different datasource and one of these datasources was a Microsoft Access DB connected via OLEDB. This is really, really old, but still works, but on one customer machine we had this issue:

'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine

Solution

If you face this issue, you need to install the provider from here.

Be aware: If you have a different error, you might need to install the newer provider - this is labled as “2010 Redistributable”, but still works with all those fancy Office 365 apps out there.

Important: You need to install the provider in the correct bit version, e.g. if you run under x64, install the x64.msi.

The solution comes from this Stackoverflow question.

Helper

The best tip from Stackoverflow was these powershell commands to check, if the provider is there or not:

(New-Object system.data.oledb.oledbenumerator).GetElements() | select SOURCES_NAME, SOURCES_DESCRIPTION 

Get-OdbcDriver | select Name,Platform

This will return something like this:

PS C:\Users\muehsig> (New-Object system.data.oledb.oledbenumerator).GetElements() | select SOURCES_NAME, SOURCES_DESCRIPTION

SOURCES_NAME               SOURCES_DESCRIPTION
------------               -------------------
SQLOLEDB                   Microsoft OLE DB Provider for SQL Server
MSDataShape                MSDataShape
Microsoft.ACE.OLEDB.12.0   Microsoft Office 12.0 Access Database Engine OLE DB Provider
Microsoft.ACE.OLEDB.16.0   Microsoft Office 16.0 Access Database Engine OLE DB Provider
ADsDSOObject               OLE DB Provider for Microsoft Directory Services
Windows Search Data Source Microsoft OLE DB Provider for Search
MSDASQL                    Microsoft OLE DB Provider for ODBC Drivers
MSDASQL Enumerator         Microsoft OLE DB Enumerator for ODBC Drivers
SQLOLEDB Enumerator        Microsoft OLE DB Enumerator for SQL Server
MSDAOSP                    Microsoft OLE DB Simple Provider


PS C:\Users\muehsig> Get-OdbcDriver | select Name,Platform

Name                                                   Platform
----                                                   --------
Driver da Microsoft para arquivos texto (*.txt; *.csv) 32-bit
Driver do Microsoft Access (*.mdb)                     32-bit
Driver do Microsoft dBase (*.dbf)                      32-bit
Driver do Microsoft Excel(*.xls)                       32-bit
Driver do Microsoft Paradox (*.db )                    32-bit
Microsoft Access Driver (*.mdb)                        32-bit
Microsoft Access-Treiber (*.mdb)                       32-bit
Microsoft dBase Driver (*.dbf)                         32-bit
Microsoft dBase-Treiber (*.dbf)                        32-bit
Microsoft Excel Driver (*.xls)                         32-bit
Microsoft Excel-Treiber (*.xls)                        32-bit
Microsoft ODBC for Oracle                              32-bit
Microsoft Paradox Driver (*.db )                       32-bit
Microsoft Paradox-Treiber (*.db )                      32-bit
Microsoft Text Driver (*.txt; *.csv)                   32-bit
Microsoft Text-Treiber (*.txt; *.csv)                  32-bit
SQL Server                                             32-bit
ODBC Driver 17 for SQL Server                          32-bit
SQL Server                                             64-bit
ODBC Driver 17 for SQL Server                          64-bit
Microsoft Access Driver (*.mdb, *.accdb)               64-bit
Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb) 64-bit
Microsoft Access Text Driver (*.txt, *.csv)            64-bit

Hope this helps! (And I hope you don’t need to deal with these ancient technologies for too long 😅)

Golo Roden: Jobs in der IT: Stellenanzeigen sind alle gleich (schlecht)

Stellenanzeigen gleichen sich üblicherweise wie ein Ei dem anderen, statt den ersten individuellen Eindruck zu vermitteln, den man von einem Unternehmen erhält.

Thorsten Hans: Watch blocked youtube videos with a VPN

Every now and then you’ll try to watch a movie trailer or a music video on YouTube only to see this message: “This video is not available in your country”. And that can really spoil the fun. But here’s the good news: There is a way to watch blocked youtube videos from anywhere. If you get a reliable VPN service like CyberGhost*, blocked YouTube videos won’t be a problem anymore. VPNs give you access to different geo-locations. Switching countries (virtually) will allow you to watch geo-blocked YouTube videos. VPNs will also encrypt your connection, making it private and secure. So, you can easily watch blocked YouTube videos with a VPN. Let’s see how it works…

VPN Provider Description Rating
CyberGhost Best value overall
Get CyberGhost
ExpressVPN High class VPN
Get ExpressVPN
Private Internet Access Good VPN, great value
Get PIA VPN

Why Are Some YouTube videos blocked?

YouTube is that massively popular video-sharing platform where you can watch tons of interesting stuff. The billion users can watch, like, subscribe, comment, upload and share videos, and it’s completely free. However, as we have already mentioned, you might encounter annoying geo-restrictions.

The site has licensed content including TV shows, movies and even music videos. Some of them are only licensed for specific countries. YouTube is truly heavily restricted in some parts of the world. For example, the popular video platform is completely blocked in Iran, China, Pakistan and North Korea. There can also be other explanations for why certain YouTube videos are inaccessible.

So, in brief, here are the most common reasons why some YouTube videos might be blocked:

  1. Licensing Rights – copyright laws or other laws regarding content distribution have placed restrictions covering certain countries or regions.
  2. Censorship – Some strict countries apply censorship on online content. YouTube can be blocked entirely or partially, depending on the local laws.
  3. Network Blocks – YouTube can be blocked because of the Network blocks on offices or school properties.

How to unblock YouTube videos in your country – A quick guide

VPN usage is without a doubt the most secure and effective way to get around the region filter and watch blocked videos on YouTube. A trustworthy VPN service will allow you to safely browse the web as if you were in a different country. The VPN will trick the blocked site, in this case it’s YouTube, by masking your local IP address and temporarily changing it. YouTube will assume that you are accessing it from a foreign country.

Time needed: 15 minutes

Just follow these steps and you’ll be able to watch blocked YouTube videos in no time:

  1. Get a good VPN

    Our top choice is CyberGhost*,a reliable VPN services with a great reputation. You can try using a free VPN but we definitely won’t recommend that option. It’s not really trustworthy and safe.

  2. Download and install the app

    You’ve chosen a VPN? Great, install it and open the app/client.now connect to a server in the correct region. You have to make sure your traffic is being routed through your VPN. Open up the VPN app and toggle it on.

  3. Go to YouTube and find the video you want to unblock

    It’s time to head to YouTube. Open your YouTube app or go to www.youtube.com. Find the blocked video that you want to watch. If the video is allowed in your VPN’s region, you’ll be allowed to watch it. If it doesn’t then you should check your VPN’s regional settings.

  4. Enjoy YouTube’s content!

    That’s it! It’s a really fast and simple trick that will save you a lot of headaches.

VPN for YouTube: The most important features

How to choose the right VPN to unblock YouTube videos? Here are the most important features to look out for:

  • The speed of the service: You will need fast server speeds in order to stream YouTube videos smoothly. It’s essential to choose a VPN that offers fast speeds.
  • Security credentials: If you’re in a country that has banned YouTube, you’ll want to make sure you have chosen a virtual private network that will protect your online identity. Reputable VPN services offer good security features that will keep you more anonymous.
  • The devices it supports: If you’re planning to watch YouTube videos on your smart TV, streaming stick, mobile phone or games console, make sure that your chosen VPN works on all of the devices you’re wanting to use.
  • The reputation: Why do people always search for the reviews of all sorts of products? Because a good advice and opinion from someone who has already tried a certain product/service is always helpful. It can guide you in your decision making process. It’s important to get a VPN that has a good reputation and a solid customer support.

About CyberGhost – Watch blocked YouTube videos with CyberGhost

So why is CyberGhost* our top recommendation?

CyberGhost is based in Romania and boasts a plethora of excellent security features that you can fully trust. With this provider, you’ll have access to top-notch encryption (AES 256-bit), split tunneling, integrated ad, and malware protection, SmartDNS, private DNS, and even an automatic kill-switch to safeguard your online activities if your VPN connection unexpectedly drops. The service also operates over 6,000 servers across the globe.

A crucial element to note is the stringent No-Logs policy that CyberGhost adheres to. This means that CyberGhost neither retains nor tracks your data. There’s no data storage or sharing – your digital footprint stays yours alone. Hence, CyberGhost becomes an ideal choice for those who are anxious about government surveillance and censorship, those who seek anonymity and privacy, and those who simply desire a safe and secure online experience.

FAQ – Frequently Asked Questions

Why is my YouTube video blocked?

Some YouTube videos may be unavailable because video owners have chosen to make their content available only to certain countries/regions due to licensing rights. YouTube can also block certain content to comply with local laws. The governments in some countries can block videos because of censorship. For example, a certain video might be at odds with a country’s culture and beliefs. So, it will be blocked.
Sometimes, even offices and schools would ban YouTube. That’s because if employees and students are able to watch videos during their work hours they won’t be focused and productive.

How do I unblock YouTube videos?

A trustworthy VPN with a flawless reputation is the best way to enjoy blocked YouTube videos. Get a VPN browser extension, select any country and try opening the video. VPNs hide your real IP address, temporarily replacing it with an address from the country you have selected. That’s an easy way to bypass any geological restrictions that a YouTube video might have.

Is unblocking YouTube safe?

Yes, it should be perfectly safe when you’re using a dependable VPN service. And not only will a virtual private network (VPN) unblock any YouTube video, so you can watch it without a problem, but it will also encrypt everything you do on the internet. That means you can remain completely anonymous, keep your online activities private and stay protected from hackers and other third party snoopers.

The post Watch blocked youtube videos with a VPN appeared first on xplatform.rocks.

Code-Inside Blog: Resource type is not supported in this subscription

I was playing around with some Visual Studio Tooling and noticed this error during the creation of a “Azure Container Apps”-app:

Resource type is not supported in this subscription

x

Solution

The solution is quite strange at first, but in the super configurable world of Azure it makes sense: You need to activate the Resource provider for this feature on your subscription. For Azure Container Apps you need the Microsoft.ContainerRegistry-resource provider registered:

x

It seems, that you can create such resources via the Portal, but if you go via the API (which Visual Studio seems to do) the provider needs to be registered at first.

Some resource providers are “enabled by default”, other providers needs to be turned on manually. Check out this list for a list of all resource providers and the related Azure service.

Be careful: I guess you should only enable the resource providers that you really need, otherwise your attack surface will get larger.

To be honest: This was completly new for me - I do Azure since ages and never had to deal with resource providers. Always learning ;)

Hope this helps!

Holger Schwichtenberg: Neu in .NET 7 [8]: Statische abstrakte Properties & Methoden in Interfaces in C#

In der neuen Version von Microsofts Programmiersprache C# dürfen Schnittstellendeklarationen von Properties und Methoden als static abstract deklariert sein.

Stefan Henneken: IEC 61131-3: SOLID – Das Open/Closed Principle

Vererbung ist eine beliebte Methode, um bestehende Funktionsblöcke wiederzuverwenden. Dadurch lassen sich Methoden und Eigenschaften hinzufügen oder bestehende Methoden überschreiben. Hierbei ist es nicht notwendig, den Quellcode des Basis-FB zur Verfügung zu haben. Software so zu designen, dass Erweiterungen möglich sind, ohne die vorhandene Software zu verändern, ist die Grundidee des Open/Closed Principle (OCP). Doch die Anwendung von Vererbung hat hierbei auch Nachteile. Der Einsatz von Schnittstellen minimiert diese Nachteile und bietet zusätzliche Vorteile.

Mit anderen Worten: Das Verhalten von Software sollte erweiterbar sein, ohne dass sie modifiziert werden muss. Angelehnt an das Beispiel aus den bisherigen Posts, soll ein Funktionsblock entwickelt werden, um Sequenzen für die Ansteuerung von Lampen zu verwalten. Anschließend wird der Funktionsblock um zusätzliche Funktionen erweitert. Anhand dieses Beispiels wird die Grundidee des Open/Closed Principle (OCP) genauer betrachtet.

Ausgangssituation

Zentraler Ausgangspunkt ist der Funktionsblock FB_SequenceManager. Dieser stellt über die Eigenschaft aSequence die einzelnen Schritte einer Sequenz zur Verfügung. Über die Methode Sort() kann die Liste nach verschiedenen Kriterien sortiert werden.

Die Eigenschaft aSequence ist ein Array und enthält Elemente vom Typ ST_SequenceItem.

PROPERTY PUBLIC aSequence : ARRAY [1..5] OF ST_SequenceItem

Um das Beispiel überschaubar zu halten, wird mit festen Arraygrenzen von 1 bis 5 gearbeitet. Die Array-Elemente sind vom Typ ST_SequenceItem und enthalten eine eindeutige Id (nId), den Ausgangswert (nValue) für die Lampen und die Dauer (nDuration) bis zum Umschalten auf den nächsten Ausgangswert.

TYPE ST_SequenceItem :
STRUCT
  nId         : UINT;
  nValue      : USINT(0..100);
  nDuration   : UINT;
END_STRUCT
END_TYPE

Auf sämtliche Methoden für die Bearbeitung der Sequenz wurde im Rahmen dieses Beispiels verzichtet. Allerdings enthält das Beispiel die Methode Sort(), um die Liste nach verschiedenen Kriterien zu sortieren.

METHOD PUBLIC Sort
VAR_INPUT
  eSortedOrder  : E_SortedOrder;
END_VAR

Die Liste kann aufsteigend nach nId oder nValue sortiert werden.

TYPE E_SortedOrder :
(
  Id,
  Value
);
END_TYPE

In der Methode Sort() wird durch den Eingangsparameter eSortedOrder entschieden, ob nach nId oder nach nValue sortiert werden soll.

CASE eSortedOrder OF
  E_SortedOrder.Id:
    // Sort the list by nId
    // …
  E_SortedOrder.Value:
    // Sort the list by nValue
    // …
END_CASE

Bei dem Beispiel handelt es sich um eine einfache monolithische Anwendung, welche in kurzer Zeit erstellt werden kann, um die gewünschten Anforderungen zu erfüllen.

Das UML-Diagramm zeigt recht deutlich den monolithischen Aufbau der Anwendung:

Dabei wurde allerdings nicht berücksichtigt, mit welchem Aufwand zukünftige Erweiterungen realisierbar sind.

Beispiel 1 (TwinCAT 3.1.4024) auf GitHub

Erweiterung der Implementierung

Die Anwendung soll so erweitert werden, dass nicht nur nach nId und nValue sortiert werden kann, sondern auch zusätzlich nach nDuration. Bisher wurde die Liste immer aufsteigend sortiert. Eine absteigende Sortierung ist ebenfalls gewünscht.

Wie lässt sich unser Beispiel anpassen, damit die beiden Kundenwünsche erfüllt werden?

Ansatz 1: Quick & Dirty

Ein Ansatz besteht darin, die vorhandene Methode Sort() einfach zu erweitern, so dass diese auch nach nDuration sortieren kann. Hierzu wird E_SortedOrder um das Feld eDuration erweitert.

TYPE E_SortedOrder :
(
  Id,
  Value,
  Duration
);
END_TYPE

Zusätzlich wird noch ein Parameter benötigt, der angibt ob in aufsteigender oder in absteigender Reihenfolge sortiert werden soll:

TYPE E_SortedDirection :
(
  Ascending,
  Descending
);
END_TYPE

Somit besitzt die Methode Sort() jetzt zwei Parameter:

METHOD PUBLIC Sort
VAR_INPUT
  eSortedOrder      : E_SortedOrder;
  eSortedDirection  : E_SortedDirection;
END_VAR

Die Methode Sort() enthält jetzt zwei ineinander verschachtelte CASE-Anweisungen. Die Äußere für die Auswahl der Sortierrichtung und die Innere für das Element nach dem sortiert wird.

CASE eSortedDirection OF
  E_SortedDirection.Ascending:
    CASE eSortedOrder OF
      E_SortedOrder.Id:
        // Sort the list by nId in ascending order
        // …
      E_SortedOrder.Value:
        // Sort the list by nValue in ascending order
        // …
      E_SortedOrder.Duration:
        // Sort the list by nDuration in ascending order
        // …
    END_CASE
  E_SortedDirection.Descending:
    CASE eSortedOrder OF
      E_SortedOrder.Id:
        // Sort the list by nId in descending order
        // …
      E_SortedOrder.Value:
        // Sort the list by nValue in descending order
        // …
      E_SortedOrder.Duration:
        // Sort the list by nDuration in descending order
        // …
    END_CASE
  END_CASE
END_CASE

Dieser Ansatz ist schnell umzusetzen. Bei einer kleinen Anwendung, wo der Quellcode nicht sehr umfangreich ist, durchaus ein guter Ansatz. Allerdings muss der Quellcode zur Verfügung stehen, damit diese Erweiterungen überhaupt möglich sind. Außerdem muss sichergestellt sein, dass FB_SequenceManager nicht mit anderen Projekten geteilt wird, z. B. durch eine SPS-Bibliothek in der FB_SequenceManager enthalten ist. Da bei der Methode Sort() ein Parameter hinzugekommen ist, hat sich die Signatur geändert. Programmteile, die die Methode mit einem Parameter aufrufen, lassen sich dadurch nicht mehr compilieren.

Durch das UML-Diagramm ist gut zu erkennen, dass sich die Struktur nicht geändert hat. Es ist weiterhin eine sehr monolithische Anwendung:

Beispiel 2 (TwinCAT 3.1.4024) auf GitHub

Ansatz 2: Vererbung

Ein weiterer Ansatz, um die Anwendung mit den gewünschten Funktionen zu erweitern, ist der Einsatz von Vererbung. Dadurch lassen sich Funktionsblöcke erweitern, ohne dass der vorhandene Funktionsblock verändert werden muss.

Hierzu wird als erstes ein neuer Funktionsblock angelegt, der von FB_SequenceManager erbt:

FUNCTION_BLOCK PUBLIC FB_SequenceManagerEx EXTENDS FB_SequenceManager

Der neue Funktionsblock erhält die Methode SortEx(), mit den beiden Parametern, welche die gewünschte Sortierung vorgibt:

METHOD PUBLIC SortEx : BOOL
VAR_INPUT
  eSortedOrder      : E_SortedOrderEx;
  eSortedDirection  : E_SortedDirection;
END_VAR

Auch hier wird wieder der Datentyp E_SortedDirection hinzugefügt, der angibt ob in aufsteigender oder in absteigender Reihenfolge sortiert werden soll:

TYPE E_SortedDirection :
(
  Ascending,
  Descending
);
END_TYPE

Statt E_SortedOrder zu erweitern, wir ein neuer Datentyp angelegt:

TYPE E_SortedOrderEx :
(
  Id,
  Value,
  Duration
);
END_TYPE

In der Methode SortEx() können jetzt die gewünschten Sortierungen umgesetzt werden.

Bei der Sortierung in aufsteigender Reihenfolge ist der Zugriff auf die Methode Sort() des Basis-FBs (FB_SequenceManager) möglich. Dadurch ist eine erneute Implementierung der schon vorhandenen Sortieralgorithmen nicht erforderlich. Nur die zusätzliche Sortierung muss hinzugefügt werden:

CASE eSortedOrder OF
  E_SortedOrderEx.Id:
    SUPER^.Sort(E_SortedOrder.Id);
  E_SortedOrderEx.Value:
    SUPER^.Sort(E_SortedOrder.Value);
  E_SortedOrderEx.Duration:
    // Sort the list by nDuration in ascending order
    // …
END_CASE

Die Sortierung in absteigender Reihenfolge muss allerdings komplett programmiert werden, da hier nicht auf bestehende Methoden zurückgegriffen werden kann.

Erbt ein Funktionsblock von einem anderen Funktionsblock, so erhält der neue Funktionsblock den Funktionsumfang des Basis-FBs. Durch zusätzliche Methoden und Eigenschaften kann dieser erweitert werden, ohne die Notwendigkeit, den Basis-FB zu verändern (offen für Erweiterungen). Durch den Einsatz von Bibliotheken kann der Quellcode auch komplett vor Veränderung geschützt werden (geschlossen gegen Modifikationen).

Vererbung ist somit eine Methode, um das Open/Closed Principle (OCP) umzusetzen.

Beispiel 3 (TwinCAT 3.1.4024) auf GitHub

Dieser Ansatz hat allerdings zwei Nachteile:

Durch den übermäßigen Einsatz von Vererbung können komplexe Hierarchien entstehen. Ein abgeleiteter FB ist fest an seinen Basis-FB gebunden. Wird der Basis-FB um weitere Methoden oder Eigenschaften erweitert, so erbt auch jeder abgeleitete FB diese Elemente (wenn diese PUBLIC sind), auch dann, wenn der abgeleitete FB diese Elemente nach Außen gar nicht anbieten möchte.

Eine Erweiterung durch Vererbung ist unter Umständen nur dann möglich, wenn die abgeleiteten Funktionsblöcke auf die internen Zustände des Basis-FBs Zugriff haben. Der Zugriff auf diese internen Elemente kann durch PROTECTED gekennzeichnet werden. Somit können nur abgeleitete Funktionsblöcke darauf zugreifen.

Im obigen Beispiel konnten nur deshalb die Sortieralgorithmen hinzugefügt werden, weil der Setter der Eigenschaft aSequence als PROTECTED deklariert wurde. Wäre ein Schreibzugriff auf die Eigenschaft aSequence nicht möglich, so könnte der abgeleitete Funktionsblock die Liste nicht verändern und somit auch nicht sortieren.

Dieses bedeutet aber, dass der Entwickler dieses Funktionsblocks immer zwei Anwendungsfälle berücksichtigen muss. Zum einen den Anwender, der die öffentlichen Methoden und Eigenschaften verwendet. Zusätzlich aber noch den Anwender, der den Funktionsblock als Basis-FB verwendet und auch über die PROTECTED Elemente neue Funktionalitäten hinzufügt. Doch welche internen Elemente sollen als PROTECTED markiert werden? Auch müssen diese Elemente dokumentiert werden, damit eine Anwendung überhaupt möglich ist.

Ansatz 3: zusätzliche Schnittstelle

Ein weiterer Lösungsansatz ist der Einsatz von Schnittstellen anstatt der Vererbung. Allerdings muss dieses direkt bei dem Design berücksichtigt werden.

Soll FB_SequenceManager so entworfen werden, dass der Anwender des Funktionsblocks beliebige Sortieralgorithmen hinzufügen kann, so sollte der Code für das Sortieren der Liste aus FB_SequenceManager entfernt werden. Der Zugriff aus dem Sortieralgorithmus auf die Liste sollte stattdessen über eine Schnittstelle erfolgen.

Bezogen auf unser Beispiel wird die Schnittstelle I_SequenceSortable hinzugefügt. Diese Schnittstelle enthält die Methode SortList(), welche eine Referenz auf die zu sortierende Liste enthält.

METHOD SortList
VAR_INPUT
  refSequence  : REFERENCE TO ARRAY [1..5] OF ST_SequenceItem;
END_VAR

Als nächstes werden die Funktionsblöcke angelegt, in denen die jeweiligen Sortieralgorithmen hinterlegt sind. Jeder dieser Funktionsblöcke implementiert die Schnittstelle I_SequenceSortable. Als Beispiel wird hier der Funktionsblock gezeigt, der nach nId aufsteigend sortiert.

FUNCTION_BLOCK PUBLIC FB_SequenceSortedByIdAscending IMPLEMENTS I_SequenceSortable

Der Name des Funktionsblocks ist beliebig, entscheidend ist die Implementierung der Schnittstelle I_SequenceSortable. Dadurch ist sichergestellt das FB_SequenceSortedByIdAscending die Methode SortList() enthält. In der Methode SortList() wird der eigentliche Sortieralgorithmus implementiert.

METHOD SortList
VAR_INPUT
  refSequence  : REFERENCE TO ARRAY [1..5] OF ST_SequenceItem;
END_VAR
// Sort the list by nId in ascending order
// …

FB_SequenceManager erhält in der Methode Sort() einen Parameter vom Typ I_SequenceSortable. Wird die Methode Sort() aufgerufen, so wird ein Funktionsblock (z.B. FB_SequenceSortedByIdAscending) übergeben, welcher die Schnittstelle I_SequenceSortable implementiert und somit auch die Methode SortList() enthält. In der Methode Sort() von FB_SequenceManager wird SortList() aufgerufen und eine Referenz der Liste aSequence übergeben.

METHOD PUBLIC Sort
VAR_INPUT
  ipSequenceSortable  : I_SequenceSortable;
END_VAR
IF (ipSequenceSortable <> 0) THEN
  ipSequenceSortable.SortList(THIS^._aSequence);
END_IF

Dadurch erhält der Funktionsblock mit dem implementierten Sortieralgorithmus die Referenz auf die zu sortierende Liste.

Für jeden gewünschten Sortieralgorithmus wird ein Funktionsblock erstellt. Somit stehen uns zum einen FB_SequenceManager mit der Methode Sort() zur Verfügung und zum anderen die Funktionsblöcke, welche die Schnittstelle I_SequenceSortable implementieren und die Sortieralgorithmen enthalten.

Wird von FB_SequenceManager die Methode Sort() aufgerufen, so wird ein Funktionsblock übergeben (hier FB_SequenceSortedByIdAscending). Dieser Funktionsblock enthält die Schnittstelle I_SequenceSortable über die anschließend die Methode SortList() aufgerufen wird.

PROGRAM MAIN
VAR
  fbSequenceManager              : FB_SequenceManager;
  fbSequenceSortedByIdAscending  : FB_SequenceSortedByIdAscending;
  // …
END_VAR
fbSequenceManager.Sort(fbSequenceSortedByIdAscending);
// …

Bei diesem Ansatz wird keine Vererbung angewendet. Die Funktionsblöcke für die Sortieralgorithmen könnten ihre eigene Vererbungshierarchie anwenden, falls dieses gefordert wird. Ebenfalls könnten die Funktionsblöcke weitere Schnittstellen implementieren, da das Implementieren mehrerer Schnittstellen möglich ist.

Datenhaltung (Liste) und Datenverarbeitung (Sortierung) sind durch den Einsatz der Schnittstelle klar voneinander getrennt. Die Eigenschaft aSequence benötigt keinen Schreibzugriff. Auch sind Zugriffe auf interne Variablen von FB_SequenceManager nicht notwendig.

Auch die beiden Datentypen E_SortedOrder und E_SortedDirection werden nicht benötigt. Die Auswahl der Sortierung wird ausschließlich durch den Funktionsblock bestimmt, der an Sort() übergeben wird.

Wird eine neue Sortierung hinzugefügt, so ist es nicht notwendig schon vorhandene Elemente zu verändern oder anzupassen.

Beispiel 4 (TwinCAT 3.1.4024) auf GitHub

Analyse der Optimierung

Es gibt verschiedene Techniken, um einen bestehenden Funktionsblock funktional zu erweitern, ohne diesen verändern zu müssen. Neben der Vererbung, eine der Hauptmerkmale der objektorientierten Programmierung (OOP), stellen Schnittstellen evtl. eine bessere Alternative dar.

Bei der Verwendung von Schnittstellen ist die Entkopplung größer. Allerdings müssen beim Softwareentwurf die einzelnen Schnittstellen implementiert werden. Es muss also im Vorfeld überlegt werden, welche möglichen Bereiche durch Schnittstellen abstrahiert werden und welche nicht.

Aber auch bei Verwendung von Vererbung muss bei der Entwicklung eines Funktionsblocks überlegt werden, welche internen Elemente den abgeleiteten Funktionsblöcken per PROTECTED angeboten werden.

Die Definition des Open/Closed Principle

Das Open/Closed Principle (OCP) wurde im Jahr 1988 von Bertrand Meyer formuliert und besagt:

Eine Softwareentität sollte offen für Erweiterungen, aber zugleich auch geschlossen gegenüber Modifikationen sein.

Softwareentität: Damit ist eine Klasse, Funktionsblock, Module, Methode, Service, … gemeint.

Offen: Das Verhalten von Softwaremodule sollte erweiterbar sein.

Geschlossen: Eine Erweiterbarkeit soll nicht dadurch erreicht werden, indem bestehende Software verändert wird.

Als das Open/Closed Principle (OCP) von Bertrand Meyer Ende der 80er definiert wurde, lag der Fokus auf der Programmiersprache C++. Er nutzte die in der objektorientierten Welt bekannte Vererbung. Die damals noch junge Disziplin der Objektorientierung versprach große Verbesserungen bei Wiederverwendbarkeit und Wartbarkeit dadurch, dass konkrete Klassen als Basisklassen für neue Klassen verwendet werden können.

Als Robert C. Martin in den 90er Jahren das Prinzip von Bertrand Meyer übernahm, setzte er es technisch anders um. C++ ermöglicht die Verwendung von Mehrfachvererbung, während in neueren Programmiersprachen Mehrfachvererbung eher selten anzutreffen ist. Aus diesem Grund setzte Robert C. Martin den Fokus auf die Verwendung von Schnittstellen. Weitere Informationen hierzu sind in dem Buch (Amazon-Werbelink *) Clean Architecture: Das Praxis-Handbuch für professionelles Softwaredesign zu finden.

Zusammenfassung

Die Einhaltung des Open/Closed Principle (OCP) birgt allerdings die Gefahr des Overengineering. Die Möglichkeit für Erweiterungen sollte nur dort implementiert werden, wo sie konkret benötigt wird. Eine Software lässt sich nicht so designen, dass jede denkbare Erweiterung umgesetzt werden kann, ohne dass Anpassungen an dem Quellcode notwendig sind.

Damit ist meine Serie über die SOLID-Prinzipien abgeschlossen. Neben den SOLID-Prinzipien gibt es allerdings noch weitere Prinzipien, wie z.B. Keep It Simple, Stupid (KISS), Don’t Repeat Yourself (DRY), Law Of Demeter (LOD) oder You Ain‘t Gonna Need It (YAGNI). All diese Prinzipen haben das gemeinsame Ziel, die Wartbarkeit und die Wiederverwendbarkeit von Software zu verbessern.

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