GitHub Copilot für ABAP: Produktivität mit KI steigern

kategorie
Tools
Veröffentlicht
autor
Johannes

GitHub Copilot ist der KI-Assistent von GitHub/Microsoft, der ABAP-Entwickler ab 2025 massiv produktiver macht. Er versteht ABAP-Syntax, kennt RAP-Patterns und kann Code schreiben, erklären, testen und refactoren – direkt in VS Code oder Eclipse ADT.

Was ist GitHub Copilot?

Copilot = Ihr KI-Pair-Programmer

  • 🤖 Basiert auf OpenAI GPT-4 (trainiert auf Milliarden Zeilen Code)
  • ✍️ Schreibt Code während Sie tippen (Auto-Completion auf Steroiden)
  • 💬 Beantwortet Fragen im Chat (Code-Erklärungen, Debugging)
  • 🔄 Refactoriert Legacy-Code zu modernem ABAP Cloud
  • ✅ Generiert Unit Tests automatisch
  • 🌍 Versteht ABAP-Syntax, RAP, CDS Views, OData

Setup: Copilot aktivieren

Voraussetzungen

  • GitHub Account mit Copilot-Lizenz
    • Individual: $10/Monat
    • Business: $19/User/Monat
    • Free für Students/Open Source Maintainer
  • VS Code oder Eclipse ADT (ab 2025)

Installation in VS Code

Terminal window
# 1. VS Code öffnen
# 2. Extensions → Suche "GitHub Copilot"
# 3. Installieren: "GitHub Copilot" + "GitHub Copilot Chat"
# 4. Sign in mit GitHub Account
# 5. Copilot aktiviert sich automatisch

Status prüfen:

Bottom-right in VS Code: Copilot-Icon
- ✅ Grün = Aktiv
- ❌ Rot = Fehler (Sign-in prüfen)

ABAP-Support aktivieren

settings.json
{
"github.copilot.enable": {
"*": true,
"abap": true, // ← ABAP explizit aktivieren
"plaintext": false
},
"github.copilot.inlineSuggest.enable": true,
"editor.inlineSuggest.enabled": true
}

Code-Generierung: Copilot als Co-Pilot

Beispiel 1: RAP Behavior Implementation

Ihr Kommentar:

" Implement validation to check if customer exists in I_Customer
METHOD validateCustomer FOR VALIDATE ON SAVE
IMPORTING keys FOR Travel~validateCustomer.

Copilot schlägt vor: (drücken Sie Tab zum Akzeptieren)

" Read travel data
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( CustomerId )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
" Get all customer IDs
DATA(lt_customer_ids) = VALUE string_table(
FOR travel IN lt_travel ( travel-CustomerId )
).
" Check if customers exist
SELECT Customer
FROM I_Customer
FOR ALL ENTRIES IN @lt_customer_ids
WHERE Customer = @lt_customer_ids-table_line
INTO TABLE @DATA(lt_existing_customers).
" Report errors for non-existing customers
LOOP AT lt_travel INTO DATA(ls_travel).
IF NOT line_exists( lt_existing_customers[ table_line = ls_travel-CustomerId ] ).
APPEND VALUE #(
%tky = ls_travel-%tky
%element-CustomerId = if_abap_behv=>mk-on
) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-CustomerId = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Customer { ls_travel-CustomerId } does not exist|
)
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.

→ 30 Zeilen Code in Sekunden generiert!

Beispiel 2: CDS View erstellen

Ihr Prompt:

-- CDS View for Sales Orders with customer name and total amount
-- Include association to customer

Copilot generiert:

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Orders with Customer Data'
define view entity ZI_SalesOrderWithCustomer
as select from I_SalesOrder as Order
association [0..1] to I_Customer as _Customer
on Order.SoldToParty = _Customer.Customer
{
key Order.SalesOrder,
Order.SalesOrderType,
Order.SalesOrganization,
Order.SoldToParty,
Order.CreationDate,
@Semantics.amount.currencyCode: 'TransactionCurrency'
Order.TotalNetAmount,
@Semantics.currencyCode: true
Order.TransactionCurrency,
Order.OverallSDProcessStatus,
// Customer data via association
_Customer.CustomerName,
_Customer.CityName,
_Customer.Country,
// Expose association
_Customer
}

Beispiel 3: Unit Test schreiben

Ihr Kommentar:

" Unit test for validateCustomer method
" Test case: Customer does not exist → should fail

Copilot generiert:

CLASS ltc_validate_customer DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_env TYPE REF TO if_cds_test_environment.
METHODS:
setup,
teardown,
test_customer_not_exists FOR TESTING,
test_customer_exists FOR TESTING.
ENDCLASS.
CLASS ltc_validate_customer IMPLEMENTATION.
METHOD setup.
mo_env = cl_cds_test_environment=>create_for_multiple_cds(
i_for_entities = VALUE #(
( i_for_entity = 'ZI_Travel' )
( i_for_entity = 'I_Customer' )
)
).
" Insert test customer
mo_env->insert_test_data(
i_data = VALUE i_customer(
( Customer = '000042' CustomerName = 'Test Customer' )
)
).
ENDMETHOD.
METHOD test_customer_not_exists.
" Arrange: Travel with non-existing customer
MODIFY ENTITIES OF zi_travel
ENTITY Travel
CREATE FIELDS ( CustomerId )
WITH VALUE #( ( %cid = 'T1' CustomerId = '999999' ) )
FAILED DATA(failed).
" Act: Commit triggers validation
COMMIT ENTITIES
RESPONSE OF zi_travel
FAILED DATA(commit_failed)
REPORTED DATA(commit_reported).
" Assert: Should fail
cl_abap_unit_assert=>assert_not_initial(
act = commit_failed-travel
msg = 'Validation should fail for non-existing customer'
).
cl_abap_unit_assert=>assert_bound(
act = commit_reported-travel[ 1 ]-%msg
msg = 'Error message should be present'
).
ENDMETHOD.
METHOD test_customer_exists.
" Arrange: Travel with existing customer
MODIFY ENTITIES OF zi_travel
ENTITY Travel
CREATE FIELDS ( CustomerId )
WITH VALUE #( ( %cid = 'T1' CustomerId = '000042' ) )
FAILED DATA(failed).
" Act
COMMIT ENTITIES
RESPONSE OF zi_travel
FAILED DATA(commit_failed).
" Assert: Should succeed
cl_abap_unit_assert=>assert_initial(
act = commit_failed-travel
msg = 'Validation should pass for existing customer'
).
ENDMETHOD.
METHOD teardown.
ROLLBACK ENTITIES.
mo_env->destroy( ).
ENDMETHOD.
ENDCLASS.

Copilot Chat: Ihr interaktiver Assistent

Chat öffnen

VS Code:
- Strg+Shift+I (Windows/Linux)
- Cmd+Shift+I (Mac)
- Oder: Sidebar → Chat-Icon

Beispiel-Dialoge

Code erklären

You:

Explain this ABAP code:
[Code markieren und reinsenden]
DATA(lt_result) = FILTER #( lt_data WHERE status = 'A' ).

Copilot:

This line uses ABAP's inline FILTER expression to create a filtered
internal table. It:
1. Takes source table lt_data
2. Filters rows where status field equals 'A'
3. Assigns result to lt_result (type inferred automatically)
This is equivalent to:
LOOP AT lt_data INTO DATA(ls_row) WHERE status = 'A'.
APPEND ls_row TO lt_result.
ENDLOOP.
But more concise and performant (single-pass operation).

Refactoring

You:

Refactor this to use modern ABAP syntax:
LOOP AT lt_orders INTO ls_order.
IF ls_order-status = 'O'.
ls_order-priority = 'HIGH'.
MODIFY lt_orders FROM ls_order.
ENDIF.
ENDLOOP.

Copilot:

" Modern ABAP with inline declaration and modify expression:
MODIFY lt_orders FROM VALUE #(
FOR order IN lt_orders WHERE ( status = 'O' )
( CORRESPONDING #( order ) priority = 'HIGH' )
).
" Or even more concise with COND:
lt_orders = VALUE #(
FOR order IN lt_orders
( CORRESPONDING #( order )
priority = COND #( WHEN order-status = 'O' THEN 'HIGH'
ELSE order-priority ) )
).

Debugging-Hilfe

You:

Why does this fail?
SELECT * FROM i_salesorder
WHERE TotalNetAmount > @lv_threshold
INTO TABLE @lt_orders.
Error: "Field TotalNetAmount unknown"

Copilot:

The error occurs because field names in CDS views are case-sensitive
in the ABAP SQL syntax.
Fix: Check the actual field name in I_SalesOrder CDS view.
It's likely "TotalNetAmount" in the view definition, but you need
to use it exactly as defined.
Try:
SELECT * FROM I_SalesOrder
FIELDS SalesOrder, TotalNetAmount, TransactionCurrency
WHERE TotalNetAmount > @lv_threshold
INTO TABLE @lt_orders.
Also note: Use explicit FIELDS clause for clarity and performance.

Prompt Engineering für ABAP

✅ Gute Prompts

" ✅ Spezifisch + Kontext
" Create a RAP determination that calculates TotalPrice
" as BasePrice * Quantity * (1 - Discount/100)
" Trigger: on modify when Quantity or BasePrice changes
" ✅ Mit Beispiel
" Convert this SELECT to use path expressions:
" SELECT * FROM vbak
" INNER JOIN kna1 ON vbak~kunnr = kna1~kunnr
" WHERE vbak~vbeln = @lv_order.
" ✅ Constraints nennen
" Write a validation that checks:
" 1. BeginDate not in past
" 2. EndDate after BeginDate
" 3. Max duration 365 days
" Use message class ZTRAVEL
" ✅ Technologie spezifizieren
" Implement OData V4 action 'approve' for Travel entity
" Input: ApprovalNote (string)
" Output: Updated Travel with Status='A'
" Use RAP Business Object pattern

❌ Schlechte Prompts

" ❌ Zu vage
" Write some validation
" ❌ Zu komplex (in einen Prompt)
" Build a complete RAP application with Travel, Booking, Customer,
" including all CRUD, validations, determinations, actions, OData service,
" Fiori UI, and deployment to BTP
" ❌ Ohne Kontext
" Fix this code:
SELECT * FROM table WHERE field = value.
" → Copilot weiß nicht: Welche Tabelle? Welcher Fehler?
" ❌ Unklare Anforderung
" Make this better
" → Was bedeutet "better"? Performance? Lesbarkeit?

Prompt-Templates

Template: Validation

" Validation for [ENTITY]: [VALIDATION_NAME]
" Business rules:
" 1. [RULE_1]
" 2. [RULE_2]
" Trigger: on save, fields [FIELD_LIST]
" Error message: [MESSAGE_TEXT]
METHOD [methodName] FOR VALIDATE ON SAVE
IMPORTING keys FOR [Entity]~[validationName].

Template: CDS View

-- CDS View: [VIEW_NAME]
-- Purpose: [DESCRIPTION]
-- Data source: [SOURCE_TABLE/VIEW]
-- Include:
-- - Fields: [FIELD_LIST]
-- - Association to: [RELATED_ENTITIES]
-- - Filter: [WHERE_CONDITION if any]

Template: Unit Test

" Unit test for [METHOD_NAME]
" Test case: [SCENARIO]
" Arrange: [SETUP_DESCRIPTION]
" Act: [ACTION_DESCRIPTION]
" Assert: [EXPECTED_RESULT]

Praktische Use Cases

Use Case 1: Legacy Code migrieren

Vorher: Classic ABAP

" Legacy code:
REPORT z_sales_report.
TABLES: vbak.
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln.
START-OF-SELECTION.
SELECT vbak~vbeln vbak~erdat vbak~kunnr kna1~name1 vbak~netwr
FROM vbak
INNER JOIN kna1 ON vbak~kunnr = kna1~kunnr
WHERE vbak~vbeln IN @s_vbeln
INTO TABLE @DATA(lt_orders).
cl_salv_table=>factory(
IMPORTING r_salv_table = DATA(lo_alv)
CHANGING t_table = lt_orders ).
lo_alv->display( ).

Prompt an Copilot:

Convert this classic ABAP report to:
1. CDS View with UI annotations
2. RAP Query (read-only)
3. OData V4 service
4. Fiori Elements UI
Target: ABAP Cloud compatible

Copilot generiert:

-- 1. CDS View
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Report'
@Metadata.allowExtensions: true
@UI: {
headerInfo: {
typeName: 'Sales Order',
typeNamePlural: 'Sales Orders'
}
}
define view entity ZC_SalesReport
as select from I_SalesOrder as Order
association [0..1] to I_Customer as _Customer
on Order.SoldToParty = _Customer.Customer
{
@UI.lineItem: [{ position: 10 }]
@UI.selectionField: [{ position: 10 }]
key Order.SalesOrder,
@UI.lineItem: [{ position: 20 }]
Order.CreationDate,
@UI.lineItem: [{ position: 30 }]
Order.SoldToParty,
@UI.lineItem: [{ position: 40 }]
_Customer.CustomerName,
@UI.lineItem: [{ position: 50 }]
@Semantics.amount.currencyCode: 'TransactionCurrency'
Order.TotalNetAmount,
Order.TransactionCurrency,
_Customer
}
-- 2. Service Definition
@EndUserText.label: 'Sales Report Service'
define service ZUI_SalesReport {
expose ZC_SalesReport as SalesOrders;
}
3. Service Binding: OData V4 - UI
4. Publish → Fiori Preview
→ Fertig! Von 50 Zeilen Report zu Cloud-ready Fiori App

Use Case 2: Komplexe EML-Queries

Prompt:

" Read Travel with all Bookings where BookingDate is within last 30 days
" Also load Customer data via association
" Sort by BookingDate descending

Copilot:

" Read Travel with recent Bookings and Customer data
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
ALL FIELDS
WITH VALUE #( ( TravelId = lv_travel_id ) )
RESULT DATA(lt_travel)
" Navigate to Bookings
ENTITY Travel BY \_Bookings
ALL FIELDS
WITH VALUE #( ( TravelId = lv_travel_id ) )
RESULT DATA(lt_all_bookings)
" Navigate to Customer
ENTITY Travel BY \_Customer
ALL FIELDS
WITH VALUE #( ( TravelId = lv_travel_id ) )
RESULT DATA(lt_customer).
" Filter Bookings (last 30 days)
DATA(lv_cutoff_date) = cl_abap_context_info=>get_system_date( ) - 30.
DATA(lt_recent_bookings) = FILTER #( lt_all_bookings
WHERE BookingDate >= lv_cutoff_date ).
" Sort by BookingDate descending
SORT lt_recent_bookings BY BookingDate DESCENDING.
" Output
WRITE: / |Travel: { lt_travel[ 1 ]-TravelId }|.
WRITE: / |Customer: { lt_customer[ 1 ]-CustomerName }|.
WRITE: / |Recent Bookings: { lines( lt_recent_bookings ) }|.
LOOP AT lt_recent_bookings INTO DATA(ls_booking).
WRITE: / | - { ls_booking-BookingDate DATE = USER }: | &&
|{ ls_booking-CarrierId } { ls_booking-FlightPrice }|.
ENDLOOP.

Use Case 3: Performance-Optimierung

Prompt:

Optimize this code for performance:
[Langsamen Code einfügen]
LOOP AT lt_orders INTO DATA(ls_order).
SELECT SINGLE name1 FROM kna1
WHERE kunnr = ls_order-kunnr
INTO @DATA(lv_name).
ls_order-customer_name = lv_name.
MODIFY lt_orders FROM ls_order.
ENDLOOP.

Copilot:

" Optimized: Single SELECT with FOR ALL ENTRIES
" Avoids N+1 query problem (was: 1 SELECT per order)
" 1. Collect unique customer IDs
DATA(lt_customer_ids) = VALUE kunnr_t(
FOR order IN lt_orders ( order-kunnr ) ).
DELETE ADJACENT DUPLICATES FROM lt_customer_ids.
" 2. Bulk-read customer names
SELECT kunnr, name1
FROM kna1
FOR ALL ENTRIES IN @lt_customer_ids
WHERE kunnr = @lt_customer_ids-table_line
INTO TABLE @DATA(lt_customers).
" 3. Update orders with CORRESPONDING
lt_orders = VALUE #(
FOR order IN lt_orders
LET customer_name = VALUE #( lt_customers[ kunnr = order-kunnr ]-name1 OPTIONAL )
IN ( CORRESPONDING #( order ) customer_name = customer_name )
).
" Performance improvement: O(N) instead of O(N²)
" Example: 1000 orders
" Before: 1000 SELECTs (~10 seconds)
" After: 2 SELECTs (~0.1 seconds)

Copilot Shortcuts

VS Code Shortcuts:
Tab Accept suggestion
Esc Dismiss suggestion
Alt+] Next suggestion
Alt+[ Previous suggestion
Ctrl+Enter Show all suggestions (panel)
Chat:
Ctrl+Shift+I Open chat
/explain Explain selected code
/fix Suggest fix for error
/tests Generate unit tests
/doc Generate documentation
Inline Chat (in editor):
Ctrl+I Inline chat at cursor

Grenzen von Copilot

❌ Was Copilot NICHT kann

" ❌ Firmen-spezifische Logik kennen
" Copilot weiß NICHT:
" - Eure internen Nummernkreise
" - Custom Z-Tabellen-Strukturen
" - Geschäftsregeln eurer Firma
" → Muss manuell angepasst werden
" ❌ Komplexe Architekturen planen
" Copilot kann Code generieren, aber NICHT:
" - Microservice-Architektur designen
" - Entscheiden: Managed vs Unmanaged RAP
" - Performance-Bottlenecks analysieren (ohne Profiling-Daten)
" ❌ Security-Audits
" Copilot-Code kann enthalten:
" - SQL Injection (wenn nicht reviewed)
" - Hardcoded Credentials (aus Trainings-Daten)
" - Fehlende Authorization Checks
" → Code Review ist PFLICHT!
" ❌ 100% korrekt sein
" Copilot macht Fehler:
" - Syntax-Errors (selten, aber möglich)
" - Logik-Fehler (Business Rules falsch)
" - Deprecated APIs vorschlagen
" → Immer testen!

✅ Best Practices

" ✅ Copilot als Assistent, nicht Ersatz
" - Nutze Vorschläge als Startpunkt
" - Review JEDEN generierten Code
" - Teste ausgiebig
" ✅ Iterativ arbeiten
" - Prompt → Generate → Review → Verfeinern → Wiederholen
" ✅ Security bewusst
" - Entferne Copilot-generierte Secrets
" - Prüfe Authorization Checks
" - OWASP Top 10 beachten
" ✅ Code Review
" - Generierten Code wie fremden Code behandeln
" - Pair Programming mit Copilot
" ✅ Lernen
" - Copilot zeigt Best Practices
" - Verstehe den generierten Code (nicht blind kopieren!)

Kosten-Nutzen-Analyse

Investition

  • Lizenz: $10-19/Monat
  • Lernkurve: 1-2 Wochen für effektive Nutzung
  • Setup: 15 Minuten

ROI (Return on Investment)

Zeiteinsparung (konservativ):

TaskOhne CopilotMit CopilotErsparnis
Einfache Method schreiben15 Min5 Min67%
Unit Tests30 Min10 Min67%
Code-Refactoring60 Min20 Min67%
Debugging/Code-Erklärung45 Min15 Min67%
CDS View erstellen20 Min8 Min60%

Durchschnittliche Produktivitätssteigerung: 30-40%

Break-Even:

Stundenlohn: €60
Lizenz: €15/Monat
Ersparnis: 5 Stunden/Monat (bei 30% Produktivität)
→ €300/Monat gespart
→ ROI: 2000% (!)

Wichtige Hinweise / Best Practice

  • Review ist Pflicht: Jeder Copilot-Code muss reviewed werden
  • Prompts sind entscheidend: Gute Prompts = guter Code
  • Iterativ nutzen: Generate → Review → Refine → Repeat
  • Security beachten: Keine Secrets committen, Authorization prüfen
  • Lernen: Verstehe den Code, kopiere nicht blind
  • Testing: Copilot-Code genauso testen wie eigenen Code
  • Firmen-Kontext: Copilot kennt eure internen Standards nicht
  • Offline-Modus: Copilot braucht Internet-Verbindung
  • Datenschutz: Firmendaten werden an GitHub/Microsoft gesendet (Business-Lizenz für Enterprise)
  • Shortcuts lernen: Tab, Alt+], Ctrl+I für maximale Effizienz
  • Chat nutzen: Nicht nur Auto-Completion – Chat ist sehr mächtig
  • VS Code empfohlen: Bessere Copilot-Integration als Eclipse ADT (2025)

Weitere Ressourcen