Das Internet der Dinge und die damit einhergehenden Anforderungen der Nutzer an Systeme und Software unterscheiden sich grundlegend von denen traditioneller Systeme. Sensoren und Aktoren werden in intelligente Alltagsgegenstände verbaut und kommunizieren über diese mit ihrer Umwelt. Sie lassen reale und virtuelle Welt miteinander verschmelzen und das Internet der Dinge zur Realität werden. Zunehmende Miniaturisierung, vermehrt drahtlose Übertragungstechnologien und auch Echtzeitanforderungen prägen Design und Entwicklung von Software und Systemen im IoT.
Software Engineering ist ganz allgemein betrachtet "eine Disziplin in der Informatik, die ein ingenieurmäßiges Vorgehen bei der Entwicklung umfangreicher, leistungsstarker Softwaresysteme beschreibt."
Laut dem IEEE "Software Engineering Body of Knowledge" umfasst das Software Engineering dabei die folgenden zehn Teildisziplinen:
Software Engineering ist somit deutlich mehr als die eigentliche Programmierung von Software und beinhaltet darüber hinaus auch Fragen der Qualitätssicherung und des Projektmanagements von Software.
Um Software ingenieursmäßig entwickeln zu können, ist ein strukturierter Entwicklungsprozess erforderlich. Dieser Entwicklungsprozess beinhaltet auch eine Designphase, in der die Komplexität der Software auf ein handhabbares Maß reduziert und das Risiko von Fehlentwicklungen minimiert wird. Hierbei kommen grafische Modellierungssprachen wie z.B. UML (Unified Modeling Language) als Hilfsmittel zum Einsatz, um Softwareobjekte und Beziehungen zwischen diesen zu spezifizieren.
Beispielsweise zeigt folgendes UML-Diagramm die bidirektionale Verbindung zwischen Kunde und Auftrag, definiert die Eigenschaften,
die einen Kunden charakterisieren (z.B. "firmenname") und legt fest, welche Aktionen darauf angewendet werden können (z.B.
Auslesen des Firmennamens).

Eine weitere, besondere Herausforderung beim Software Engineering stellt die Teildisziplin "Test" dar. Grundsätzlich sollten Entwicklungs- und Testumgebung für eine Software durch angemessene Maßnahmen sicher voneinander und auch von produktiven IT-Systemen getrennt sein. Dies kann sowohl durch eine sichere physische (separater Server) oder auch logische Trennung (separate virtuelle Maschinen auf einem physischen Server) erreicht werden. Darüber hinaus sollte sichergestellt sein, dass Entwicklungs- und Testumgebung mit gleicher Hard- und Softwarekonfiguration betrieben werden.
Ist dies nicht der Fall und unterscheiden sich Entwicklungs- und Testumgebung in wesentlichen Konfigurationen (z.B. unterschiedliche Versionen und Patchlevel bei Betriebssystem und Applikationen), wird eine verlässliche Aussage über die Funktionsweise der getesteten Software erschwert bzw. eine Abnahme in der Testumgebung gänzlich unmöglich - Fehler sind hierdurch quasi vorprogrammiert.
Die Herausforderung bei der Entwicklung von Software für verteilte Systeme besteht darin, dass sich diese aus vielen autonomen Komponenten zusammensetzen, die unterschiedliche Funktionalitäten ausführen und für den Nutzer nach außen hin als ein einziges, zusammengehörendes System erscheinen. Ein anschauliches Beispiel für ein verteiltes System ist das Internet selbst. Es besteht aus vielen geografisch verteilten Servern, die über ein Netzwerk miteinander kommunizieren, unterschiedliche Dienste bereitstellen und diese dem Nutzer transparent präsentieren. Sofern eine autonome Komponente zentrale Steuerungsfunktionen für umgebende Hardware abbildet, spricht man auch von einem verteilten eingebetteten System. Beispielsweise kommen solche Komponenten bei der Steuerung von Verbrennungsmotoren in einem Kraftfahrzeug oder der Regelung der Fluglage von Flugzeugen zum Einsatz.
Die in verteilten eingebetteten Systemen zum Einsatz kommende Software muss häufig besonderen Echtzeit- und Zuverlässigkeitsanforderungen genügen, wenn sie z.B. in der KFZ-Elektrik für ABS- oder Airbagsteuerung verwendet wird. Die Entwicklung eingebetteter Systeme unterscheidet sich grundsätzlich von der Entwicklung anderer Systeme. Beispielsweise muss ein Entwickler einer Textverarbeitungssoftware hardwarebezogene Anforderungen in der Regel nicht berücksichtigen. Bei der Entwicklung eingebetteter Systeme spielt die zugrundeliegende Hardware jedoch eine wichtige Rolle, da diese oftmals speziell für einen definierten Anwendungszweck entwickelt wird. Der Zugriff auf diese Hardware erfolgt entweder über maschinennahe Programmierung mit Assembler oder mittels Programmiersprachen wie C/C++ oder Java, die einen vereinfachten Hardwarezugriff erlauben.
Ein besonders für den Einsatz im IoT interessanter Ansatz für eine offene, dynamische und modulare Laufzeitumgebung auf Basis von Java ist OSGi (Open Services Gateway initiative). Die durch die OSGi Alliance (u.a. Oracle, Sun Microsystems, IBM) entwickelte herstellerunabhängige Softwareplattform ermöglicht die Steuerung und Vernetzung diverser Gerätearten und kommt aktuell besonders häufig bei der Vernetzung von KFZs zum Einsatz, z.B. bei der Anbindung von Infotainment-Systemen. Der modulare und dynamische Ansatz von OSGi ist insofern besonders vorteilhaft, da in der Praxis Softwarekomponenten aus der Ferne installiert, gestartet, gestoppt und deinstalliert werden können, ohne ein Gerät neu zu starten, was Wartungs- und Aktualisierungsmaßnahmen deutlich vereinfacht. Ein weiterer, spezieller Aspekt bei der Entwicklung verteilter eingebetteter Systeme ist die Implementierung der Echtzeitfähigkeit unter Berücksichtigung möglicher Einschränkungen durch die Kommunikation zwischen den verteilten Komponenten über Netzwerke unterschiedlichster Art. Da je nach zugrundeliegendem Übertragungsmedium und Übertragungsprotokoll diverse Fehlerzustände zu Problemen bei der Datenübertragung führen können (z.B. Paketverlust), muss bei der Entwicklung verteilter Systeme sichergestellt werden, dass diese die Echtzeitfähigkeit und auch die Zuverlässigkeit des Gesamtsystems nicht negativ beeinflussen.