Fork me on GitHub

Debugging

Αυτή η μετάφραση είναι πλήρως ενημερωμένη.

Τα σφάλματα είναι αναπόσπαστο μέρος κάθε project, γιαυτό και χρειαζόμστε απασφαλμάτωση. Σε αυτό το μάθημα θα μάθουμε για την απασφαλμάτωση κώδικα στην Elixir καθώς και για τα εργαλεία στατικής ανάλυσης που μας βοηθάνε να βρούμε πιθανά σφάλματα.

Πίνακας περιεχομένων

Dialyxir και Dialyzer

Το Dialyzer, ένας διαφορικός αναλυτής για προγράμματα Erlang είναι ένα εργαλείο για στατική ανάλυση κώδικα. Με άλλα λόγια διαβάζουν αλλά δεν τρέχουν κώδικα και τον αναλύουν π.χ. ψάχνοντας για κάποια σφάλματα, νεκρό, αχρείαστο ή απροσπέλαστο κώδικα.

Το Dialyxir είνα μια εργασία mix που απλοποιεί τη χρήση του Dialyzer στην Elixir.

Οι προδιαγραφές βοηθούν εργαλεία όπως το Dialyzer να καταλάβουν τον κώδικα καλύτερα. Αντίθετα με την τεκμηρίωση που είναι αναγνώσιμη και κατανοητή μόνο από άλλους ανθρώπους (αν υπάρχει και είναι καλογραμμένη), η spec χρησιμοποιεί πιο επίσημο συντακτικό και μπορεί να γίνει κατανοητή από μια μηχανή.

Ας προσθέσουμε το Dialyzer στο project μας. Ο πιο απλός τρόπος είναι να προσθέσουμε την εξάρτηση στο αρχείο mix.exs:

defp deps do
  [{:dialyxir, "~> 0.4", only: [:dev]}]
end

Τότε καλούμε:

$ mix deps.get
...
$ mix deps.compile

Η πρώτη εντολή θα κατεβάσει και εγκαταστήσει το Dialyxir. Μπορεί να σας ζητηθεί να εγκαταστήσετε το Hex μαζί του. Το δεύτερο συντάσσει την εφαρμογή Dialyxir. Αν θέλετε να εγκαταστήσετε το Dialyxir καθολικά, παρακαλώ διαβάστε την τεκμηρίωσή του.

Το τελευταίο βήμα είναι να τρέξετε το Dialyzer για να χτίσετε ξανά το PLT(Persistent Lookup Table - Πίνακας Μόνιμης Εύρεσης). Πρέπει να το κάνετε αυτό κάθε φορά που εγκαθιστάτε μια νέα έκδοση Erlang ή Elixir. Ευτυχώς, το Dialyzer δεν θα προσπαθήσει να αναλύσει τη βασική βιβλιοθήκη κάθε φορά που προσπαθείτε να το χρησιμοποιήσετε. Χρειάζονται μερικά λεπτά για να ολοκληρωθεί η λήψη.

$ mix dialyzer --plt
Starting PLT Core Build ... this will take awhile
dialyzer --build_plt --output_plt /.dialyxir_core_18_1.3.2.plt --apps erts kernel stdlib crypto public_key -r /Elixir/lib/elixir/../eex/ebin /Elixir/lib/elixir/../elixir/ebin /Elixir/lib/elixir/../ex_unit/ebin /Elixir/lib/elixir/../iex/ebin /Elixir/lib/elixir/../logger/ebin /Elixir/lib/elixir/../mix/ebin
  Creating PLT /.dialyxir_core_18_1.3.2.plt ...
...
 done in 5m14.67s
done (warnings were emitted)

Στατική ανάλυση κώδικα

Τώρα είμαστε έτοιμοι να χρησιμοποιήσουμε το Dialyxir:

$ mix dialyzer
...
examples.ex:3: Invalid type specification for function 'Elixir.Examples':sum_times/1. The success typing is (_) -> number()
...

Το μήνυμα από το Dialyzer είναι ξεκάθαρο: ο τύπος επιστροφής της συνάρτησής μας sum_times/1 είναι διαφορετικός από αυτόν που έχει οριστεί. Αυτό συμβαίνει γιατί η Enum.sum/1 επιστρέφει έναν αριθμό και όχι έναν ακέραιο αλλά ο τύπος επιστροφής της sum_times/1 είναι ακέραιος.

Από τη στιγμή που ο αριθμός δεν είναι το ίδιο πράγμα με τον ακέραιο δεχόμαστε ένα σφάλμα. Πως θα το διορθώσουμε; Πρέπει να χρησιμοποιήσουμε την συνάρτηση round/1 για να αλλάξουμε τον αριθμό σε έναν ακέραιο:

@spec sum_times(integer) :: integer
def sum_times(a) do
  [1, 2, 3]
  |> Enum.map(fn el -> el * a end)
  |> Enum.sum()
  |> round
end

Τελικά:

$ mix dialyzer
...
  Proceeding with analysis... done in 0m0.95s
done (passed successfully)

Η χρήση των προδιαγραφών μαζί με εργαλεία ανάλυσης στατικού κώδικα μας βοηθάει να γράφουμε κώδικα που είναι αυτό-ελεγμένος και περιέχει λιγότερα σφάλματα.

Απασφαλμάτωση

Μερικές φορές η στατική ανάλυση του κώδικα δεν είναι αρκετή. Μπορεί να είναι αναγκαίο να καταλάβουμε τη ροή εκτέλεσης ώστε να βρούμε σφάλματα. Ο απλούστερος τρόπος είναι να βάλουμε εκφράσεις εξόδου στον κώδικά μας όπως η IO.puts/2 για να παρακολουθήσουμε τιμές και ροή κώδικα, αλλά αυτή η τεχνική είναι απαρχαιωμένη και έχει όρια. Ευτυχώς για εμάς, μπορούμε να χρησιμοποιήσουμε τον εντοπιστή σφαλμάτων της Erlang για να απασφαλματώσουμε τον κώδικά μας στην Elixir.

Ας δούμε μια βασική ενότητα:

defmodule Example do
  def cpu_burns(a, b, c) do
    x = a * 2
    y = b * 3
    z = c * 5

    x + y + z
  end
end

Και τώρα τρέξτε το iex:

$ iex -S mix

Και τώρα τρέξτε τον εντοπιστή σφαλμάτων:

iex > :debugger.start()
{:ok, #PID<0.307.0>}

Η ενότητα :debugger της Erlang παρέχει πρόσβαση στον εντοπιστή σφαλμάτων. Μπορούμε να χρησιμοποιήσουμε την start/1 για να τον παραμετροποιήσουμε:

Το επόμενο βήμα είναι να συνδέσουμε την ενότητά μας στον εντοπιστή σφαλμάτων:

iex > :int.ni(Example)
{:module, Example}

Η ενότητα :int είναι ένας ερμηνευτής που μας δίνει τη δυνατότητα να δημιουργούμε σημεία διακοπής και να μπούμε μέσα στην εκτέλεση του κώδικα.

Όταν ξεκινάτε τον εντοπιστή σφαλμάτων θα δείτε ένα νέο παράθυρο σαν αυτό:

Στιγμιότυπο οθόνης Εντοπιστή Σφαλμάτων 1

Αφού συνδέσουμε την ενότητά μας στον εντοπιστή σφαλμάτων θα είναι διαθέσιμη στο μενού στα αριστερά μας:

Στιγμιότυπο οθόνης Εντοπιστή Σφαλμάτων 2

Δημιουργία σημείων διακοπής

Ένα σημείο διακοπής είναι ένα σημείο στον κώδικα όπου η εκτέλεση μπορεί να διακοπεί. Έχουμε δύο τρόπους δημιουργίας σημείων διακοπής:

Ας προσπαθήσουμε να δημιουργήσουμε ένα σημείο διακοπής στο IEx:

iex > :int.break(Example, 8)
:ok

Αυτό ορίζει ένα σημείο διακοπής στη γραμμή 8 της ενότητας Example. Τώρα όταν καλέσουμε τη συνάρτησή μας:

iex > Example.cpu_burns(1, 1, 1)

Η εκτέλεση θα διακοπεί στο IEx και το παράθυρο εντοπισμού σφαλμάτων θα πρέπει να δείχνει κάπως έτσι:

Στιγμιότυπο οθόνης Εντοπιστή Σφαλμάτων 3

Ένα επιπρόσθετο παράθυρο με τον πηγαίο κώδικά μας θα εμφανιστεί:

Στιγμιότυπο οθόνης Εντοπιστή Σφαλμάτων 4

Σε αυτό το παράθυρο μπορούμε να δούμε την τιμή των μεταβλητών, να προχωρήσουμε στην επόμενη γραμμή ή να αξιολογήσουμε τις εκφράσεις. Η :int.disable_break/2 μπορεί να κληθεί ώστε να απενεργοποιήσουμε ένα σημείο διακοπής:

iex > :int.disable_break(Example, 8)
:ok

Για να ενεργοποιήσουμε ξανά ένα σημείο διακοπής μπορούμε να καλέσουμε την :int.enable_break/2 ή μπορούμε να διαγράψουμε ένα σημείο διακοπής με αυτό τον τρόπο:

iex > :int.delete_break(Example, 8)
:ok

Οι ίδιες λειτουργίες είναι διαθέσιμες στο παράθυρο του εντοπιστή σφαλμάτων. Στο κεντρικό μενού, Break, μπορούμε να επιλέξουμε Line Break και να ορίσουμε σημεία διακοπής. Αν επιλέξουμε μια γραμμή που δεν έχει κώδικα τότε το σημείο διακοπής θα αγνοηθεί, αλλά θα εμφανιστεί στο παράθυρο του εντοπιστή σφαλμάτων. Υπάρχουν τρείς τύποι σημείων διακοπής:

Αυτό ήταν όλο! Καλή απασφαλμάτωση!


Contributors

loading...



Share This Page