Server API basis data deteksi penipuan

Aug 29 2020

Agak memalukan, saya telah membuat kode selama beberapa tahun sekarang, namun saya merasa bahwa saya masih menulis kode dengan cara yang sangat dasar. Sulit untuk memastikan, ketika banyak perusahaan sering memberikan wawancara pengkodean untuk tenaga kerja gratis, dan internet jarang melihat pengembangan perangkat lunak dari sisi bisnis tetapi memperlakukannya secara akademis terlalu meributkan detail yang tidak akan disia-siakan oleh perusahaan biasa untuk produktivitas.

Saya diberi tugas untuk menulis dengan Python oleh perusahaan pencegahan penipuan, yang saya selesaikan dan konfirmasi bekerja dengan benar, dalam tenggat waktu empat hingga lima jam. Mereka memberi saya daftar transaksi tiruan dalam file CSV, dan petunjuk berikut:

  1. Menggunakan Flask + pustaka python lainnya merancang layanan API sederhana yang dapat menyajikan informasi dalam file CSV ini.

  2. Asumsikan layanan ini akan menjadi bagian dari pipeline BI + ML tambahan, jadi usulkan sejumlah agregat yang dapat disediakan oleh setiap API saat ditanyai.

  3. Ini adalah tugas yang sangat terbuka, jadi silakan mengambil pendekatan yang menurut Anda tepat dan membuat beberapa asumsi jika itu menyederhanakan pekerjaan.

Pertanyaan: Bagaimana cara meningkatkan kode dan solusi saya?

Pertanyaan: Tanpa mengkhawatirkan perasaan saya, apakah ini bagus untuk 4 sampai 5 jam? Saya memiliki gelar sarjana di bidang Ilmu Komputer, tahun industri berbayar di mana saya melakukan pengembangan perangkat lunak (tetapi saya belajar sangat sedikit karena perusahaan menggunakan kerangka kerja yang sulit dipahami), dan telah berusaha keras untuk membuat kode sejak saya masih kecil.

Saya berasumsi: Jawabannya akan bervariasi dari menggunakan kerangka kerja untuk mengurangi kode boilerplate, injeksi ketergantungan, kasus uji, menggunakan beberapa file py, lebih banyak komentar, gunakan sakelar daripada banyak pernyataan elif, penanganan kesalahan, logging yang tepat daripada menggunakan print untuk status informasi, dan variabel bernama lebih baik. Saya kira bagian algoritma dari kode itu buruk, misalnya tidak akan mencari BIN dengan sangat efisien, dan database RAM mungkin merupakan implementasi yang lebih cepat mengingat lalu lintas tinggi yang berpotensi diterima ini.

Harap keras, karena setelah bertahun-tahun saya selalu melakukan hal-hal dasar yang sama, akhirnya saya ingin membuat kode seperti yang diharapkan oleh industri, atau perusahaan pemula.

Berikut kode sumbernya:

#################################################################################################
# Created by XXXXX YYYYY for ZZZZZ, use at your own risk
# Test the API with Post Man by sending JSON data:
# {
#   "auth": "amazingHorse",
#   "action": "suseptibleBINs"
#   "term": "additional information like search terms, else write 'empty'"
# }

# Setup instructions for first time users:
# Visual Studio Code
# pip3 install virtualenv
# .\env\Scripts\activate.bat
# pip3 flask flask-sqlalchemy
# pip3 install pandas
# python app.py
# !!! Warning: delete the xtransactions.sqlite file before each new deployment!!!!
#################################################################################################

from flask import Flask, request, jsonify
import sqlalchemy as db
import pandas as pd
from itertools import islice
import collections
import csv
import time
app = Flask(__name__)

adminPassword = "cyberExpert333" # Admin API password
userPassword = "amazingHorse" # User API password
suseptibleBINs = ["111","222","2a6f738d9ce1a8a9381aa775620fe5f0"] 
req_data = "" # Stores the JSON received from API

# For ordinary visitors
@app.route('/')
def hello_world():
    return 'Welcome, this is a private nonproduction system and provides API access to authorised users only'

# TODO admin access with special privs to drop tables etc...
@app.route('/api/admin', methods=['POST'])
def adminAccess():
    req_data = request.get_json()
    password = req_data['password']
    if(password != adminPassword):
        return "Authentication failure"
    else:
        return "Welcome administrator, please finish coding this..."

# Normal API access
@app.route('/api/user', methods=['POST'])
def userAccess():
    req_data = request.get_json()
    password = req_data['password'] # This function only checks for user password, admins have a seperate path at /api/admin
    if(password != userPassword):
        return "Authentication failure"
    else:
        action = req_data['action'] # What user would like to do
        term = req_data['term'] # Optional information, such as text to search for
        if(action == "BIN"):
            return binsFraudRisk()
        elif (action == "search"):
            return searchDatabase(term)
        elif (action == "mean"):
            return meanMaths(term)
        elif (action == "mode"):
            return modeMaths(term)
        elif (action == "median"):
            return medianMaths(term)
        elif (action == "max"):
            return maxMaths(term)
        elif (action == "min"):
            return minMaths(term)
        else:
            return "Error in your JSON data, please resend request"

# Boiler plate database code
def boilerPlateDatabase():
    engine = db.create_engine('sqlite:///xtransactions.sqlite')
    connection = engine.connect()
    metadata = db.MetaData()
    census = db.Table('trans', metadata, autoload=True, autoload_with=engine)
    query = db.select([census])
    ResultProxy = connection.execute(query)
    ResultSet = ResultProxy.fetchall()
    return ResultSet

# BINs suseptible to fraud
def binsFraudRisk():
    ResultSet = boilerPlateDatabase()
    foundRow = list()
    for row in ResultSet:
        for badBIN in suseptibleBINs:
            if badBIN == row[4]: 
                foundRow.append(row) # Add into foundRow array
    return str(foundRow) # All discovered rows which have suseptible BINs

# Search string - case sensitive!
def searchDatabase(searchTerm):
    ResultSet = boilerPlateDatabase()
    foundRow = list()
    for row in ResultSet:
        if (searchTerm == row[1] or searchTerm == row[2] or searchTerm == row[3] or searchTerm == row[4] or searchTerm == row[5] or searchTerm == row[6] or searchTerm == row[7] or searchTerm == row[8] or searchTerm == row[9]): 
            foundRow.append(row)
    return str(foundRow) # All rows which match the query

# Mean is the average
def meanMaths(searchTerm):
    ResultSet = boilerPlateDatabase()
    searchNumber = 0
    # 7
    if(searchTerm == "amount"):
        searchNumber = 7
    # 8
    elif(searchTerm == "currency"):
        searchNumber = 8
    else:
        return "Error in your JSON"

    # New array with just with numbers from amount or currency
    num = []
    for number in ResultSet:
        num.append(number[searchNumber])

    # Calculate the mean
    sum_num = 0
    for t in num:
        sum_num = sum_num + t           
    avg = sum_num / len(num)
    return str(avg)

# Mode is number that appears the most
def modeMaths(searchTerm):
    ResultSet = boilerPlateDatabase()
    searchNumber = 0
    # 7
    if(searchTerm == "amount"):
        searchNumber = 7
    # 8
    elif(searchTerm == "currency"):
        searchNumber = 8
    else:
        return "Error in your JSON"

    # New array with just with numbers from amount or currency
    num_list = []
    for number in ResultSet:
        num_list.append(number[searchNumber])

    # calculate the frequency of each item
    data = collections.Counter(num_list)
    data_list = dict(data)

    max_value = max(list(data.values()))
    mode_val = [num for num, freq in data_list.items() if freq == max_value]
    if len(mode_val) == len(num_list):
        return "Mode not found!"
    else:
        return("The Mode of the list is : " + ', '.join(map(str, mode_val)))

# Median is middle value
def medianMaths(searchTerm):
    ResultSet = boilerPlateDatabase()
    searchNumber = 0
    # 7
    if(searchTerm == "amount"):
        searchNumber = 7
    # 8
    elif(searchTerm == "currency"):
        searchNumber = 8
    else:
        return "Error in your JSON"

    # New array with just with numbers from amount or currency
    num_list = []
    for number in ResultSet:
        num_list.append(number[searchNumber])

    # Sort the list
    num_list.sort()
    # Finding the position of the median
    if len(num_list) % 2 == 0:
        first_median = num_list[len(num_list) // 2]
        second_median = num_list[len(num_list) // 2 - 1]
        median = (first_median + second_median) / 2
    else:
        median = num_list[len(num_list) // 2]
    return("The median is: " + str(median))

# Max is highest number
def maxMaths(searchTerm):
    ResultSet = boilerPlateDatabase()
    searchNumber = 0
    # 7
    if(searchTerm == "amount"):
        searchNumber = 7
    # 8
    elif(searchTerm == "currency"):
        searchNumber = 8
    else:
        return "Error in your JSON"

    # New array with just with numbers from amount or currency
    num_list = []
    for number in ResultSet:
        num_list.append(number[searchNumber])
    
    return 'Maximum: '+str(max(num_list))

# Min is smallest number
def minMaths(searchTerm):
    ResultSet = boilerPlateDatabase()
    searchNumber = 0
    # 7
    if(searchTerm == "amount"):
        searchNumber = 7
    # 8
    elif(searchTerm == "currency"):
        searchNumber = 8
    else:
        return "Error in your JSON"

    # New array with just with numbers from amount or currency
    num_list = []
    for number in ResultSet:
        num_list.append(number[searchNumber])

    return 'Minimum: '+str(min(num_list))

def databaseManagement():
    print("Creating new database")
    engine = db.create_engine('sqlite:///xtransactions.sqlite') # Create test.sqlite automatically
    connection = engine.connect()
    metadata = db.MetaData()
    trans = db.Table('trans', metadata,
        db.Column('Id', db.Integer(), unique=True), # Not in CSV file but makes life easier
        db.Column('t', db.String(), nullable=False),
        db.Column('tx_id', db.String(), nullable=False),
        db.Column('src_card', db.String(), nullable=False),
        db.Column('src_BIN', db.String(), nullable=False),
        db.Column('dst_card', db.String(), nullable=False),
        db.Column('dst_BIN', db.String(), nullable=False),
        db.Column('amount', db.Integer(), nullable=False),
        db.Column('currency', db.Integer(), nullable=False),
        db.Column('status', db.String(), nullable=False),
        )
    metadata.create_all(engine) # Creates the table

    # Inserting record one by one with a FOR loop
    print("Loading CSV into database")
    theIDCounter = 0 # Counter variable to assign a unique ID for DB
    with open('trx_sample.csv') as fd:
        for row in islice(csv.reader(fd), 2, None): # Skip line 0 (the disclaimer) and 1 (which is stuff like t, tx_id)
            query = db.insert(trans).values(Id=theIDCounter, t=row[0], tx_id=row[1], src_card=row[2], src_BIN=row[3], dst_card=row[4], dst_BIN=row[5], amount=row[6], currency=row[7], status=row[8])
            ResultProxy = connection.execute(query)
            theIDCounter = theIDCounter + 1
    results = connection.execute(db.select([trans])).fetchall()

if __name__ == '__main__':
    databaseManagement() # Loads CSV and puts everything into the DB
    app.run(debug=False) # If true then it causes server to restart which upsets DB

Jawaban

34 Peilonrayz Aug 29 2020 at 09:44

Kode Anda tidak terlihat Pythonic karena kode Anda tidak mengikuti PEP 8 .

  • Banyak PEP 8 yang harus dilakukan dengan spasi; dua baris baru di atas dan di bawah kelas tingkat atas dan definisi fungsi, dua spasi di depan komentar sebaris, spasi selalu setelah koma, spasi tunggal di kedua sisi operator.
  • Anda menggunakan camelCasebukan snake_caseuntuk fungsi dan nama variabel.
  • Anda memiliki banyak tanda kurung yang tidak diperlukan yang membuat kode Anda lebih padat.
  • Anda tidak konsisten dalam pembatas string Anda.

Beberapa masalah ini dan mengingat Anda memiliki fungsi bernama hello_worldmembuat saya berpikir Anda telah mengambil kode Flask dari web.

Anda juga telah menggunakan komentar daripada docstrings, PEP 257 , untuk mendokumentasikan kode Anda.


API server Anda sepertinya tidak terlalu bagus:

  • Semua tanggapan 200 OK bahkan dalam kegagalan di mana sekitar 400 kode akan masuk akal.

  • API Anda tidak memiliki format umum untuk dengan mudah mengidentifikasi apakah tanggapan berhasil, baik Anda tidak menggunakan kode HTTP atau tidak.

    Pesan kesalahan Anda bahkan tidak memiliki format atau kata yang sama.


Di semua kode Anda, sekilas memiliki beberapa tanda bahaya.

17 yedpodtrzitko Aug 29 2020 at 10:11

blok panjang elif-s dapat disederhanakan dengan menggunakan pencarian kamus. Jadi, alih-alih ini:

if(action == "BIN"):
    return binsFraudRisk()
elif (action == "search"):
    return searchDatabase(term)
elif (action == "mean"):
    return meanMaths(term)
elif (action == "mode"):
    return modeMaths(term)
elif (action == "median"):
    return medianMaths(term)
elif (action == "max"):
    return maxMaths(term)
elif (action == "min"):
    return minMaths(term)
else:
    return "Error in your JSON data, please resend request"

Anda dapat mendefinisikan kamus dengan kondisi sebagai kunci + hasil sebagai nilai, dengan asumsi semua fungsi mengharapkan parameter yang sama (mis. tambahkan termparameter ke binsFraudRisk()meskipun tidak akan digunakan di sana)

action_resolver = {
    "BIN": binsFraudRisk,
    "search": searchDatabase,
    # ...keep adding other functions
}

# all if-elifs will shrink into this:
if action in action_resolver:
    return action_resolver[action](term)
else:
    return "Error in your JSON data, please resend request"
    
17 FinnPoppinga Aug 30 2020 at 01:09

Jawaban lain sudah membahas topik seperti pemformatan kode atau hal lain yang mungkin tidak idiomatis. Dalam ulasan ini, saya ingin fokus pada apa yang saya harapkan jika saya adalah pewawancara dan akan meninjau solusi Anda.

1. Rancang API sederhana

Tugas pertama meminta Anda mendesain API sederhana yang menyajikan beberapa data dari file CSV. Sebagai pewawancara, saya ingin melihat hal-hal berikut:

  • API menggunakan format data umum untuk memberikan data kepada pengguna akhir, kemungkinan besar JSON.
  • API berperilaku baik, misalnya menyetel Content-Typeheader yang benar , dan kode status yang bermakna.
  • yang antarmuka API masuk akal dalam konteks aplikasi dan konsisten.
  • API didokumentasikan dengan baik.

Jadi pendekatan pertama yang baik adalah melihat data yang Anda miliki. Dari skema database Anda dalam databaseManagementfungsi tersebut, saya berasumsi Anda memiliki daftar transaksi di file CSV. Jadi API minimum yang ingin saya lihat adalah:

GET /transactions- mengembalikan semua transaksi dalam file CSV dalam format JSON.
GET /transactions/:id- mengembalikan transaksi dengan yang diberikan tx_id.

Poin bonus, jika Anda menggunakan sesuatu seperti openapi untuk menentukan tipe data dan operasi API Anda dengan standar ini. Standar ini juga memungkinkan Anda untuk menyediakan dokumentasi API dengan cara yang mudah.

Fungsi lain yang dapat diterapkan di atas misalnya memfilter daftar transaksi menggunakan parameter kueri:

GET /transactions?currency=EUR - mengembalikan semua transaksi dengan mata uang yang setara dengan EUR.

Atau Anda dapat menambahkan sumber daya lain untuk diindeks, yang akan berguna untuk tugas kedua:

GET /accounts- dengan asumsi BIN adalah semacam ID akun, kembalikan semua src_BIN yang ada.
GET /accounts/:src_bin- mengembalikan beberapa info tentang akun yang diberikan (misalnya saldo).

Mengapa?

Dalam lingkungan profesional, sangat penting untuk merancang API Anda dengan hati-hati, karena begitu API berada di alam liar, Anda (hampir) tidak pernah bisa mengubahnya. Alat lain akan bergantung pada titik akhir untuk berperilaku dengan cara yang terdokumentasi. Saya ingin melihat bahwa kandidat mempertimbangkan hal ini.

2. Usulkan sejumlah agregat yang dapat disediakan setiap API saat ditanyai

Saya pikir untuk tugas ini sebagian besar tentang konteks wawancara Anda. Ini adalah perusahaan pendeteksi penipuan, dan saya pikir ini harus tercermin dalam jawaban Anda untuk tugas ini.

Saya bukan dari bisnis ini, jadi tidak tahu apa yang masuk akal, tetapi jika saya melakukan sesuatu, saya akan melakukan sesuatu seperti:

GET /accounts/:src_bin/statistics- kembali min, max, meantransaksi outgoing dari yang diberikan :src_bin.

atau bahkan sesuatu dengan level yang lebih tinggi seperti:

GET /accounts/:src_bin/outliers- kembali keluar dari transaksi biasa untuk diberikan :src_bin

Di mana Anda menerapkan algoritme pendeteksian pencilan yang Anda temukan di internet, untuk memungkinkan pengguna API menemukan transaksi "mencurigakan".

Mengapa?

Ini menunjukkan bahwa Anda bukan sekadar monyet pengkodean, tetapi Anda juga dapat berpikir dalam domain bisnis perusahaan tempat Anda akan bekerja, yang merupakan keterampilan yang sangat penting bagi setiap insinyur perangkat lunak.

Topik untuk dipelajari

Anda secara eksplisit bertanya tentang nasihat tentang caranya

[...] akhirnya memberi kode seperti yang diharapkan oleh industri, atau perusahaan pemula.

Dan menurut saya ada beberapa keterampilan yang harus Anda peroleh yang akan membantu Anda menangani tugas-tugas seperti ini dengan lebih mudah:

  • mengetahui standar yang mapan. Jawaban lain menyebutkan pep8konvensi pemformatan kode, tetapi Anda juga harus tahu tentang openapi dan REST saat Anda bekerja di posisi teknik terkait web.
  • jika Anda memperkenalkan dependensi tambahan, seharusnya ada alasan bagus untuk itu. Saya berpikir untuk menggunakan SQLite sebagai database. Saya pikir ini secara teknis adalah pilihan yang baik, tetapi Anda tidak benar-benar menggunakan salah satu fiturnya dalam kode Anda. Semua agregat yang Anda berikan tidak menggunakan fungsionalitas agregasi SQL apa pun .
  • tahu bagaimana melakukan otentikasi API . Tugas tidak meminta otentikasi, jadi saya pikir pilihannya adalah tidak melakukannya sama sekali, atau melakukannya dengan benar. Melakukan hardcode kata sandi dan mengirimkannya ke badan permintaan bukanlah cara yang tepat untuk melakukannya.
9 Ry- Aug 29 2020 at 09:41

Kode bisa lebih sederhana. Sepertinya Anda sudah memiliki banyak ide tentang peningkatan potensial, jadi saya akan merekomendasikan untuk mencobanya lebih sering dan membandingkan hasil masing-masing dengan bagaimana kode sebelumnya untuk belajar darinya.

  • Satu-satunya kueri database Anda adalah kueri untuk mengambil semua baris. Jika Anda akan memuat CSV ke dalam database SQLite, itu harus menjalankan kueri.

  • Python memiliki perhitungan median bawaan .

  • if(searchTerm == "amount"): searchNumber = 7 elif(searchTerm == "currency"): searchNumber = 8 dan ekstraksi kolom berikut ini adalah beberapa logika umum yang sangat tidak dapat difaktorkan.

  • Mungkin lebih baik desain API memberikan setiap operasi rutenya sendiri. Melakukan ini juga akan memaksa Anda untuk memfaktorkan otentikasi, yang juga meningkatkan kode.

  • Jika statistik tidak berubah pada waktu proses, Anda dapat menghitung sebelumnya.

  • Membandingkan kata sandi dengan ==tidak aman karena serangan waktu, tetapi ini adalah contoh mainan, dan pewawancara Anda mungkin tidak akan peduli / tahu tentang itu.

  • Panda tidak digunakan.

  • Ada banyak pustaka standar Python, fitur bahasa, dan ekspektasi pemformatan yang harus Anda pelajari jika Anda akan menggunakan Python. (Tentu saja, beberapa di antaranya bisa dilakukan. Tetapi hal lain, seperti memeriksa apakah suatu elemen ada dalam daftar, Anda harus tahu bisa dilakukan lebih baik tidak peduli bahasa apa yang Anda kenal.)

Saya berharap untuk memperbarui jawaban ini dengan lebih detail besok. Bagaimanapun, berikut adalah gambaran tentang tampilan kode untuk sementara:

import statistics
from dataclasses import dataclass


@dataclass
class Transaction:
    t: str
    tx_id: str
    src_card: str
    src_bin: str
    dst_card: str
    dst_bin: str
    amount: int
    currency: int   # you sure?
    status: str     # enum?


@app.route("/amounts/median")
def median():
    return {"median": statistics.median(t.amount for t in transactions)}


# ... (every route is that short) ...


# libraries can do this
def transaction_from_row(row):
    return Transaction(
        t=row[0],
        tx_id=row[1],
        src_card=row[2],
        src_bin=row[3],
        dst_card=row[4],
        dst_bin=row[5],
        amount=int(row[6]),
        currency=int(row[7]),
        status=row[8],
    )


if __name__ == "__main__":
    with open("trx_sample.csv") as f:
        # Skip line 0 (the disclaimer) and 1 (which is stuff like t, tx_id)
        transactions = [transaction_from_row(row) for row in islice(csv.reader(fd), 2)]
7 IainShelvington Aug 29 2020 at 09:36

Pengamatan ini hanya tentang kode itu sendiri dan bukan tentang penerapan Anda

Sebagian besar basis kode Python mematuhi panduan gaya PEP8 , ini membantu pengembang Python mengurai dan memahami kode satu sama lain. Kode Anda tidak mengikuti pedoman PEP8 untuk nama fungsi dan variabel. Nama fungsi dan variabel harus lowercase_with_underscores:

def bins_fraud_risk():
    result_set = boiler_plate_database()

Anda membungkus ekspresi dalam pernyataan "jika" Anda dengan tanda kurung yang tidak perlu, hapuslah:

if search_term == "amount":

Menggabungkan string dengan operator "+" tidak disukai karena membuat string baru setiap saat yang dapat menyebabkan kinerja yang buruk. Pemformatan string biasanya lebih disukai

# Using an f-string
return f'The median is: {median}'

# Using .format()
return 'The median is: {}'.format(median)
5 Anonymous Aug 30 2020 at 06:16

Secara pribadi ada satu hal yang membuat saya kesal: penggunaan nilai indeks, bukan nama bidang. Pertimbangkan contoh ini:

# BINs suseptible to fraud
def binsFraudRisk():
    ResultSet = boilerPlateDatabase()
    foundRow = list()
    for row in ResultSet:
        for badBIN in suseptibleBINs:
            if badBIN == row[4]: 
                foundRow.append(row) # Add into foundRow array
    return str(foundRow) # All discovered rows which have suseptible BINs

Jika Anda memiliki database SQL maka saya tidak mengerti mengapa Anda melakukan hal ini (baris demi baris iterasi untuk menemukan BIN yang buruk) ketika kueri SQL sederhana akan melakukan pekerjaan itu. Ini tidak efisien.

Tapi masalah lainnya adalah referensi ke kolom # 4. Bagaimana jika struktur tabel Anda berubah? Sangat dapat dibayangkan bahwa beberapa bidang lagi dapat ditambahkan / disisipkan di masa mendatang, dan sebagai akibatnya posisi bidang lainnya akan bergeser. Jadi, Anda harus membuat banyak penyesuaian dalam kode Anda dan selalu ada risiko Anda lupa satu baris (atau lebih). Kemudian kode Anda mungkin akan terus berfungsi tetapi beberapa kondisi tidak lagi mengevaluasi seperti yang Anda inginkan. Ini adalah cara yang bagus untuk memperkenalkan bug.

Dan menggunakan nomor kolom sama sekali tidak intuitif .

Kode Anda juga penuh dengan angka ajaib hardcode. Jika Anda tidak dapat menghindarinya, gunakan konstanta .

Anda melakukan panggilan berulang kali boilerPlateDatabase()yang secara bergantian melakukan ini ResultSet = ResultProxy.fetchall():, yang sangat tidak efisien dan tidak perlu. Lakukan saja kueri SQL biasa. Saya pikir Anda belum meluangkan waktu untuk membaca tentang SQLAlchemy (karena ini adalah platform yang Anda pilih). Python juga mendukung SQLite di luar kotak sehingga Anda dapat membuat kueri dengan mudah, bahkan tanpa SQLAlchemy.

Atau jika Anda akan memuat semua record ke memori, lakukan sekali saja, saat startup. Karena Anda sedang mengerjakan sampel data statis yang bagaimanapun juga tidak akan berubah. Tidak perlu memuat ulang semuanya setiap saat.

Saran saya adalah:

  • jika Anda berurusan dengan database SQL, pelajari cara menggunakan SQL yang benar
  • biasakan untuk mengukur waktu eksekusi kode Anda, berikut adalah penunjuk yang berguna:https://realpython.com/python-timer/Anda dapat memperoleh keuntungan besar dengan meningkatkan kode Anda. Dampaknya mungkin tidak terlalu terlihat saat ini, tetapi ketika Anda menjalankan kode mahal dalam satu putaran, pengguna Anda akan menjadi tidak sabar di belakang layar mereka.

Panda bisa menjadi pilihan tetapi dalam kasus ini SQL biasa seharusnya lebih dari cukup.

Tapi pikirkan apa yang akan terjadi dengan kumpulan data yang sangat besar. Aplikasi Anda tidak akan diskalakan dan menjadi lebih lambat (atau crash) dan memuat semuanya ke memori dapat menyebabkan masalah kinerja. Hanya untuk iseng saya akan melihat penggunaan memori dan level CPU saat aplikasi sedang berjalan. Saya menemukan kekurangan dalam aplikasi saya sendiri hanya dengan melakukan itu. Seperti, aplikasi baris perintah yang menggunakan 25% CPU atau 50 Mb RAM => tidak terlihat.

Dalam satu kata Anda perlu belajar bagaimana menulis kode yang efisien dan bukan hanya kode yang berfungsi.

Last but not least: menurut saya API harus diimplementasikan sebagai kelas mandiri, jadi dalam file terpisah. Ini berbeda dari antarmuka.

Komentar dalam kode Anda tidak terlalu membantu: Saya tidak belajar apa-apa tentang fungsi dengan melihatnya. Apa yang akan membantu adalah dua atau tiga baris yang menjelaskan logika dan mungkin menunjukkan sampel data.