Soll temporärer Code unter Versionskontrolle gestellt werden und wie?

29

Hier sind einige Beispiele für temporären / lokalen Code. Es wird benötigt, um mit der Codebasis zu arbeiten, aber es wäre schädlich, ein Teil davon zu sein:

  1. Projektdateien. Möglicherweise müssen Pfade bearbeitet werden, um das Layout auf dem aktuellen PC wiederzugeben.
  2. Makefiles. Beispielsweise muss die Optimierung möglicherweise während des Debuggens deaktiviert werden, nicht jedoch für den CI-Server.
  3. Schmutzige hässliche Hacks. Zum Beispiel return 7mitten in einer Funktion, um etwas zu testen, abhängig von der Funktion, und verdächtigt, bei einem Wert von 7 zu brechen. Oder 7 ist der Code der noch nicht implementierten Schaltfläche, die ich implementiere und durchgehend testen muss das Leben meines Zweiges.

Ich habe versucht, diese in einem git-Commit zu halten, bei dem ich immer nach oben zurückfalle, bevor ich zum Repo schiebe und dann schiebe HEAD~. Dies ist recht unpraktisch und funktioniert mit svn nicht. Das Verstauen macht mir noch mehr Angst - "Habe ich mich daran erinnert, nach dem Stoßen zu platzen?".

Wenn Sie den Code aus der Versionskontrolle heraushalten, wird jedes Mal, wenn ein Commit zusammengestellt wird, ein unangenehmes Rauschen erzeugt, und es kann vorkommen, dass er an einem Freitagabend versehentlich in ein Commit eingefügt wird.

Was wäre eine vernünftige Lösung für einen solchen Wegwerfcode?

Vorac
quelle
Muss dieser temporäre Code während seiner temporären Verwendung aus dem ursprünglichen Projekt aktualisiert werden?
JeffO
@ Jeffo, nicht sicher, ob ich dich verstehe. Die Dirty Snippets sind klein und kollidieren selten mit dem Code, der gerade entwickelt wird. @ Blrfl, es ist jedoch sehr gefährlich für sie, sich für den Mainstream zu engagieren. Stellen Sie sich eine return 7am trunkFreitagabend nach einer miesen Verschmelzung in der Sommerhitze vor.
Vorac
@Vorac - dafür sind Code-Reviews und -Tests da! Ich kann Ihnen viel Schlimmeres zeigen - Code, der nicht funktioniert, obwohl er auf den ersten Blick gut aussah. Return 7.. wenn sie nur alle so offensichtlich wären!
Gbjbaanb
@Vorac: Das war mehr ein philosophischer Kommentar als alles andere.
Blrfl
2
Gibt es eine Möglichkeit zu erkennen, in welcher Umgebung Sie sich befinden? Sie können es beispielsweise so einrichten, dass Code ausgeführt wird, wenn festgestellt wird, dass Sie sich in der Entwicklungsumgebung befinden, jedoch nicht in val / prod. Auf diese Weise müssen Sie beim Festschreiben nicht ständig Platzhaltercode hinzufügen / entfernen.
Saggio

Antworten:

46

Der gesamte Code ist temporär. Wenn ich Änderungen vornehme, füge ich gelegentlich Platzhalter ein - das Symbol, das ich gezeichnet habe, um auf den echten vom Designer zu warten. Die Funktion, die ich kenne, ruft die Bibliothek auf, die mein Kollege schreibt und die noch nicht fertig ist (oder begonnen hat). die zusätzliche Protokollierung, die entfernt oder auf andere Weise bedingt wird, die Fehler, die ich beheben werde, sobald sie vom Testteam bemerkt wurden, usw

Checken Sie also alles ein. Verwenden Sie einen Feature-Zweig für Ihre gesamte Entwicklung, dann können Sie die endgültige Version in trunk zusammenführen, und niemand muss wissen, welche Hacks und Bodges und Fixes Sie während Ihres Entwicklungszyklus vorgenommen haben. Sie müssen nur siehe die endgültige Version. Wenn Sie sich jedoch regelmäßig für Ihre Filiale entschieden haben, können Sie die Dinge sehen, die es wert sind, aufbewahrt zu werden, wenn ein Tag auf spektakuläre Weise schief gelaufen ist, oder Sie haben nach einer Mittagspause in der Kneipe weiter programmiert.

Die Versionskontrolle ist kein Artefakt-Repository oder Dokumentenspeichersystem. Es geht darum, die Geschichte der Veränderungen festzuhalten. Stecke alles hinein, was du magst, denn eines Tages möchtest du vielleicht sehen, was es war, und an diesen Tagen merkst du, worum es in deinem SCM wirklich geht.

PS. Wirklich temporäre Dateien (zB .obj oder Build-Artefakte) haben keinen Platz in Ihrem SCM. Dies sind Dinge, die für niemanden von Wert sind. Sie können erkennen, was sie sind - wenn Sie sie löschen, macht es Ihnen nichts aus, oder Sie bemerken sogar, dass sie verschwunden sind.

gbjbaanb
quelle
5
Einverstanden. Verzweigung ist der richtige Weg. Erstellen Sie eine Verzweigung, machen Sie dort, was Sie wollen, und führen Sie den fertigen Code zusammen, wenn er fertig ist. Der Kopf sollte als Release-Version behandelt werden, die der Client jederzeit herunterladen und verwenden kann.
Cameron McKay
Tolle Antwort, nach allem, was ich gesehen habe, hat GIT die lokale Versionierung eingeführt, um Menschen zu helfen, die ein Protokoll ihrer lokalen Arbeit haben möchten. Temporärer Code sollte in den Maschinen des Entwicklers bleiben, bis er bereit ist, sie in das Repo zu übertragen
InformedA
2
Ich werde ein großes Poster mit der Aufschrift "ALL CODE IS TEMPORARY" ausdrucken und es an die Wand kleben. Wahrscheinlich in Comic Sans.
Bob Tway
2
@MattThrower in einem Blasenzitat, das von den Lippen von Clippy kommt?
Gbjbaanb
1
Nicht ausgeführter Code oder Code, der nicht kompiliert werden kann, sollte jedoch nicht zur Versionskontrolle verpflichtet werden.
Tulains Córdova
17

Projektdateien. Möglicherweise müssen Pfade bearbeitet werden, um das Layout auf dem aktuellen PC wiederzugeben.

Bei Projektdateien ist die beste Strategie, wenn Sie die Projektdatei über ein Skript generieren können. Fügen Sie die eigentliche Projektdatei zu Ihren Ignorierungen hinzu und generieren Sie die Projektdatei bei Bedarf neu. In Java-Projekten verwende ich beispielsweise gradle, mit dem ein Eclipse-Projekt generiert werden kann.

Makefiles. Beispielsweise muss die Optimierung möglicherweise während des Debuggens deaktiviert werden, nicht jedoch für den CI-Server.

Sie sollten in der Lage sein, zwischen Optimierungs- und Debug-Modus zu wechseln, ohne Ihr Makefile zu ändern. Verwenden Sie stattdessen ein Befehlszeilenflag, eine Umgebungsvariable oder eine separate Datei, die sich nicht in Ihrem Repository befindet, um dies zu steuern.

Schmutzige hässliche Hacks. Zum Beispiel 7 in der Mitte einer Funktion zurückgeben, um etwas zu testen, abhängig von der Funktion, und vermutet, dass es bei einem Wert von 7 abbricht. Oder 7 ist der Code der noch nicht implementierten Schaltfläche, die ich implementiere und die ich implementieren muss Test während des gesamten Lebens meiner Branche.

Können Sie keinen Test schreiben, der den vermuteten Fehlerfall auslöst?

In den meisten Fällen sollten Sie in der Lage sein, Ihren Workflow anzupassen, damit Sie diese Änderungen nicht an Dateien in Ihrem Repository vornehmen. Die Dateien, die lokal geändert werden, sollten zum Ignoriermechanismus Ihres Projekts hinzugefügt werden und nicht im Repository enthalten sein. In einigen Fällen werden Sie dennoch temporäre Änderungen vornehmen, die Sie nicht in das Repository übernehmen möchten. Fügen Sie für diese eine spezielle Sequenz hinzu, z. B .: XXX, und fügen Sie einen Pre-Commit-Hook hinzu, der Commits ablehnt, in denen sie noch vorhanden sind.

Winston Ewert
quelle
Manchmal muss ich kleine Hacks an einer Datei ausführen und gleichzeitig Produktionscode in dieselbe Datei schreiben. svnunterstützt keine partiellen Datei-Commits, daher ist dies in solchen Situationen ein Problem. Die meisten meiner Kollegen übertragen die Hacks einfach auf die Zweigstelle und bereinigen sie beim Zusammenführen zu trunk. Ich lenke mich jedoch ab (und mache Fehler bei Zusammenführungen, und Zusammenführungen in svn sind heilig und unveränderlich), was diese Frage erleichtert.
Vorac
@Vorac, ich würde nach Subversion-Hooks suchen, mit denen Sie beim Festschreiben Skripte ausführen können. Es sollte möglich sein, ein Skript zu schreiben, das eine Zusammenführung ablehnt, wenn es XXX oder ähnliches enthält.
Winston Ewert
1
@Vorac: Wenn Sie TortoiseSVN verwenden, können Sie Restore After Commit für eine Datei verwenden, um einen Teil des Commits auszuführen. Verwenden Sie ein Diff-Tool oder Ihren Editor, um die Blöcke, die Sie nicht festschreiben möchten, vorübergehend zu entfernen. Tortoise stellt die vollständige Datei direkt danach wieder her und Sie können die verbleibenden Blöcke festschreiben, wenn Sie bereit sind. Dies kann erreicht werden, indem eine schnelle Sicherung der Datei erstellt und diese nach dem ersten Festschreiben wiederhergestellt wird.
Leokhorn
5

Die Versionskontrolle sollte Code und Konfiguration enthalten, die zum Erstellen der Anwendung erforderlich sind.

Das bedeutet, dass:

  • Temporäres Material, das für kurze Zeit eingeführt wurde (die Zeit, die erforderlich ist, um den Ort eines Fehlers zu lokalisieren oder mit einer Funktion einer Sprache zu experimentieren), sollte sich nicht in einer Versionskontrolle befinden: Behalten Sie es bei, bis Sie es benötigen es, dann entfernen Sie es einfach, wenn Sie das Commit ausführen .

  • Lokale Dateien, die für einen bestimmten Computer geeignet sind, können in einem Zweig aufbewahrt werden.

    Ich würde es vermeiden, sie nur lokal aufzubewahren, da es zu schmerzhaft ist, all diese Dinge zu wiederholen, wenn Ihr Laptop gestohlen wird oder ein Virus Sie zwingt, das Betriebssystem neu zu installieren (und Sie stellen übrigens fest, dass Ihre letzte Sicherung vor zwei Jahren durchgeführt wurde). .

    Auf der anderen Seite sollten Sie mit der Dateistruktur vorsichtig sein: Die lokale Konfiguration ist in Ordnung, bis sie überwältigend wird, und zwingt Sie dazu, in jeder Datei von 42 am Projekt beteiligten Entwicklern eine einzige Änderung vorzunehmen.

    Achten Sie auf die Möglichkeit, die Besonderheiten zwischen den Maschinen zu beseitigen. Es kann bedeuten:

    • Zugriff auf einen Entwickler-SQL-Server gewähren, um lokale Instanzen auf Entwicklermaschinen zu ersetzen,

    • Paketverteilungsdienste wie Pypi oder npm für öffentliche Pakete und deren private Gegenstücke für interne Pakete verwenden,

    • Bitten Sie die Mitglieder des Teams, die gleichen Softwareversionen zu installieren.

    • Machen Sie Software-Updates so transparent wie möglich.

    • Oder ermöglichen Sie die Bereitstellung des Betriebssystems und der erforderlichen Software auf einem Computer mit einem Klick (plus der Zeit, die jeder Entwickler benötigt, um sein bevorzugtes Vim vs. Emacs, Chrome vs. Firefox usw. zu installieren).

So:

Projektdateien. Möglicherweise müssen Pfade bearbeitet werden, um das Layout auf dem aktuellen PC wiederzugeben.

Warum nicht auf jedem PC das gleiche Layout verwenden? Pfade innerhalb des Projekts sollten relativ zur Projektdatei sein, was bedeutet, dass es egal ist, wo sich das Projekt befindet. Software- und Bibliotheksversionen sind besser gleich, um kryptische Fehler zu vermeiden, die nur auf einigen Computern auftreten und für andere Mitglieder des Teams nicht reproduzierbar sind.

Beispiel:

In einem mit Visual Studio erstellten Projekt finden Sie möglicherweise:

  • Die Dateien selbst. Da die Pfade relativ sind, spielt es keine Rolle, ob sich das Projekt auf meinem Computer befindet, H:\Development\Hello World Project\während andere Teammitglieder das Projekt ausgecheckt haben C:\Work\HelloWorld\.

  • Die Abhängigkeiten, dh Fremd- und Hausbibliotheken. Beide Arten sollten von NuGet behandelt werden, was alle konfliktbezogenen Diskussionen überflüssig macht. Wenn Sie nicht die gleiche Version der Bibliothek haben, die ich habe, bitten Sie NuGet, die Abhängigkeiten zu aktualisieren. So einfach ist das (wenn es gut funktioniert, was nicht immer der Fall ist).

    Beachten Sie, dass es wichtig ist, die internen Bibliotheken auch in einem privaten NuGet zu behalten. Wenn eine Reihe von Bibliotheken in einem freigegebenen Ordner gespeichert oder über ein Team per E-Mail gesendet werden, kommt es zu anarchischen und depressiven CI-Servern.

  • Einstellungen. Es ist entscheidend, dass das Team die gleichen Einstellungen hat. Wenn die Hälfte des Teams beschließt, Warnungen als Fehler zu behandeln, und die Hälfte des Teams die Warnungen unverändert beibehält, werden die Mitglieder des ersten Teils des Teams die von den Entwicklern generierten Warnungen aus dem zweiten Teil des Teams entfernen.

  • Die Einstellungen für Dienstprogramme. Diese sind schwierig, da einige Mitglieder des Teams möglicherweise einige Dienstprogramme installiert haben, andere jedoch nicht.

    Es wird dringend empfohlen, dasselbe Toolset zu installieren. Wenn einige Programmierer StyleCop verwenden möchten, andere jedoch nicht, wird das Team den Job nicht erledigen. Wenn einige Codeverträge verwenden, andere jedoch nicht, treten dieselben Probleme auf.

Makefiles. Beispielsweise muss die Optimierung möglicherweise während des Debuggens deaktiviert werden, nicht jedoch für den CI-Server.

Behalten Sie mehrere Makefiles in der Versionskontrolle. Es ist nicht ungewöhnlich, eine Debug-Version auch auf dem CI-Server zu erstellen und an einen Client zu senden, bei dem ein heikler Fehler auftritt.

Schmutzige hässliche Hacks. Zum Beispiel 7 in der Mitte einer Funktion zurückgeben, um je nach Funktion etwas zu testen, und den Verdacht haben, bei einem Wert von 7 zu brechen.

Ich würde einen solchen Code an erster Stelle vermeiden. Verwenden Sie Unit-Tests, um etwas zu testen. Wenn es wirklich ein paar Sekunden dauert, um einen Code zum Debuggen auszutauschen , dann tun Sie es, aber Sie werden diesen Code sowieso in ein paar Minuten entfernen, sodass Sie ihn nicht festschreiben müssen.

Wie Sie es beschreiben, sollten Sie einen Test schreiben. Zum Beispiel, wenn Sie sicher sein möchten, dass:

class TemperatureConverter
{
    public int CelsiusToFahrenheit(int temperature)
    {
        ...
    }
}

Löst eine Ausnahme aus, wenn temperaturesie der AbsoluteZeroKonstanten unterlegen ist, sollten Sie nicht mit Code selbst spielen. Erstellen Sie stattdessen einen Komponententest, der Folgendes bewirkt:

  • Dokumentieren Sie Ihren Code selbst,
  • Erhöhen Sie die Zuverlässigkeit Ihres Codes,
  • sicherstellen, dass sich die Betreuer bei der Änderung der obigen Methode auf Regressionstests verlassen können,
  • Wenden Sie sich an andere Entwickler Ihres Teams, die möglicherweise denselben Test durchführen müssen.
Arseni Mourzenko
quelle
2
Leider habe ich keine Erfahrung mit dem Schreiben von Tests. Bei der aktuellen Plattform handelt es sich um eine ARM-CPU, die einige Hardware als Reaktion auf USB-Befehle konfiguriert. Es erfolgt keine Rückmeldung von der Hardware an die CPU.
Vorac
2
Wenn temporärer Code dauerhafte Auswirkungen haben kann, selbst wenn der Code nach dem Erreichen dieser Auswirkungen möglicherweise nie benötigt wird, wäre es meines Erachtens sinnvoll, den Code an einem anderen Ort zu belassen, falls Fragen dahingehend bestehen, ob die Auswirkungen korrekt erzielt wurden. Wenn zum Beispiel das Datenbankformat für ein Produkt während der Entwicklung geändert wird, kann man ein einmaliges Hilfsprogramm schreiben, um das Format zu ändern. Das Dienstprogramm wird möglicherweise nie benötigt, nachdem die einzige vorhandene Datenbank im alten Format konvertiert wurde, es muss jedoch möglicherweise überprüft werden, wie die Konvertierung durchgeführt wurde.
Supercat
Ich habe gute Erfahrungen mit der Generierung von Visual Studio-Projektdateien mit CMake gemacht, was eine gewisse Flexibilität hinsichtlich der genauen Position des Quellcodes und des kompilierten Codes im Dateisystem ermöglicht. Dann versionskontrolliere ich die CMake-Eingabedateien anstelle der VS-Projektdateien. Dies entspricht jedoch immer noch Ihrem Grundsatz: "Die Versionskontrolle sollte Code und Konfiguration enthalten, die zum Erstellen der Anwendung erforderlich sind." Dem stimme ich voll und ganz zu!
David K
Bei VS müssen Sie manchmal darauf achten, dass sich keine absoluten Pfade einschleichen. Beim Upgrade auf win64 und beim Wechsel von Bibliotheken für Plattformen von Drittanbietern C:\Program Files\...aufC:\Program Files (x86)\...
Dan Neely
@DanNeely: Aus diesem Grund sollten Bibliotheken von Drittanbietern von NuGet verwaltet werden.
Arseni Mourzenko
2

Wir verwenden @@Kommentare im Code, um anzuzeigen, dass etwas nicht ganz fertig ist, zu Testzwecken usw.

Auf diese Weise können wir festlegen, dass Kollegen nicht zu lange auf die Synchronisierung warten müssen und sehen können, wo noch gearbeitet wird (z. B. zu verstehen, warum ein Teil noch nicht vollständig funktioniert).

Wir führen eine globale Suche durch @@, um Überreste zu vermeiden, bevor die letzten Phasen des Betatests usw. erreicht werden.

Mit dieser Disziplin sehe ich keinen Grund, mich nicht nur zu engagieren. Auf diese Weise haben wir keine separaten Zweige und nur ein zusätzliches 'Protokoll', dem wir folgen müssen.


Als zusätzlichen Vorteil sind diese Aufgaben (normalerweise kleine Dinge) immer im Code enthalten. Der Entwickler, der daran arbeitet, kann sie schnell durchgehen, und es ist nicht erforderlich, separate Listen zu führen.
Sie wissen, wie die Entwicklung abläuft: Sie arbeiten an einem Ort, aber Sie verwenden Ihren Verstand ständig als Stapel (" Ich sollte das dort ändern, wenn ich hier fertig bin "). Nur kurz notieren@@ Bemerkung wird ein Stapelüberlauf verhindert.

Ich zeige sogar @@nameProbleme an, die ich mit 'name' besprechen muss.

Jan Doggen
quelle
1

2 HAMSTER-Lösungen:

  • Sie können einen Pre-Commit-Hook verwenden, um Ihren Code auf ungewöhnliche Schlüsselwörter wie HAMSTER zu überprüfen. Lassen Sie nur nicht zu, dass Leute Code schreiben, der mit HAMSTER versehen wurde, und verwenden Sie ihn, wenn Sie schmutzige Hacks ausführen.

  • Eine andere Option, zum Beispiel in C, ist die Verwendung von #ifdef HAMSTER. Der Code wird dann nur auf Ihrem Computer ausgeführt, auf dem Sie ein Compiler-Flag HAMSTER haben.

user143985
quelle
0

Wir unterziehen alles der Quellcodeverwaltung, um die aktuellen Binärdateien zu erstellen und zu testen, und verstehen, warum die Dinge so entworfen / implementiert / getestet wurden, wie sie sind.

Das gilt sogar für Spitzen http://www.extremeprogramming.org/rules/spike.html , wie die, die Sie beschrieben haben. Wir hosten sie einfach in einem anderen Teilbaum.

Solkar
quelle
0

Im Folgenden finden Sie eine Reihe von Lösungen, die ich gelegentlich unter verschiedenen Umständen selbst verwende und die Sie bei der Anwendung auf Ihre eigenen Workflows als hilfreich erachten können:

  1. Leichte Äste, die zerquetscht werden können.

    Git ist großartig darin. Hacke in einen Zweig, mache viele Commits und baue deinen Verlauf neu auf oder zerquetsche ihn, um das Rauschen zu beseitigen.

  2. Verwenden Sie eine Patch-Warteschlange über Ihrem SCM.

    Ich benutze häufig StGit , um Patches an die Spitze meines aktuellen Zweigs zu verschieben. Wenn ich mit der Verzweigung fertig bin, kann ich sie vor dem Zusammenführen, Zusammenpressen oder erneuten Basieren wieder aus dem Stapel entfernen oder sie in der Hauptcodebasis zusammenführen, wenn ich sie behalten möchte.

  3. Verwenden Sie RCS als "Out-of-Band" SCM für kleine Experimente.

    Manchmal möchten Sie eine gerade laufende Datei nur auf einmal überprüfen, ohne den Verlauf danach bereinigen zu müssen. Normalerweise benutze ich RCS für diesen Zweck innerhalb von Git oder SVN. Ich fordere Git auf, RCS-Artefakte zu ignorieren, meine laufenden Arbeiten in RCS zu überprüfen und, wenn mir die Ergebnisse gefallen, einfach die *,vDateien oder das gesamte RCS-Verzeichnis zu werfen . Laufen git clean -fdxSie einfach nicht oder ähnlich, bis Sie Ihre Arbeit Ihrem "echten" SCM gewidmet haben, oder Sie werden es bereuen.

  4. Benannte Verstecke.

    Ein weiterer Git-Ismus, aber praktisch: git stash save --include-untracked <some-cool-title>kann zur Not nützlich sein. Auf diese Weise können Sie laufende Arbeiten speichern, einfügen und anwenden sowie Ihre verschiedenen Prüfpunkte über git stash listoder anzeigen git reflog --all. Andere SCMs verfügen möglicherweise über ähnliche Funktionen, Ihre Laufleistung kann jedoch bei diesen stark variieren.

CodeGnome
quelle
0

Ein Teil dieses temporären Codes ist eigentlich nur eine Manifestation einer unsachgemäßen Build- / Test- / Entwicklungsmethode, und hoffentlich wird ihre Existenz die zukünftige Verbesserung motivieren.

Zumindest auf Git sollte es Ihnen freigestellt sein, mit einer beliebigen Anzahl von Feature-Zweigen herumzuspielen, bis sie zum Zusammenführen mit Master / Trunk bereit sind.

Die Versionskontrolle soll Ihnen helfen , und ich schätze die Erkenntnisse darüber, wie in der Vergangenheit Fehler (oder vielleicht auch weniger intuitive Entscheidungen) gemacht wurden, und treffe fundiertere Entscheidungen für die Gegenwart.

prusswan
quelle
0

Ich glaube, dass einige Systeme Warnungen auslösen, wenn TODO in einem Kommentar angezeigt wird

// TODO: remove this hack.

Dies kann alles sein, was Sie brauchen, wenn Sie eine relevante Option in einem Teil Ihrer Entwicklungsumgebung finden oder einfach einen grep-Befehl in Ihre Build-Datei einfügen. Es kann auch möglich sein, dass // HACKeine beliebige Zeichenfolge aufgenommen wird.

Dies ist einfacher, als Ihren Code auf eine bestimmte Weise zu organisieren und zu hoffen, dass die Leute daran denken, ihn nicht zu verwenden. Es macht es auch sicherer, @gbjbaanbs Rat zu befolgen (wenn Sie sicherstellen können, dass alle die Warnungen sehen!).

Stecke alles hinein, was du magst, denn eines Tages möchtest du vielleicht sehen, was es war, und an diesen Tagen merkst du, worum es in deinem SCM wirklich geht.

GKFX
quelle
0

Das Versetzen von Code in die Quellcodeverwaltung ist niemals schädlich.

Jedes einzelne der von Ihnen erwähnten Elemente sollte sich in der Quellcodeverwaltung befinden.

Toby Allen
quelle