کدام گزینه درست است!
وقتی می گوییم در یک ساختمان داده عملیات(مانند get و set) با پیچیدگی زمانی O(1) انجام می شود:
وقتی می گوییم در یک ساختمان داده عملیات(مانند get و set) با پیچیدگی زمانی O(1) انجام می شود:
Anonymous Quiz
45%
زمانی که پیچیدگی زمانیO(1) باشد، یعنی تعداد عملیاتی که داشتیم، هرچقدرهم طول زیادباشد برابر با یک است
55%
ممکن است یک میلیون عمل انجام شده باشداما طول آن چه یک باشد یاچند میلیارد، پیچیدگی زمانی اش برابر است
😱9
هزینهی Raise کردن Exception و رویکرد متفاوت گولنگ
در اکثر زبان ها، استثناها (Exceptions) ابزار اصلی برای مدیریت خطاها هستند. برای مثال وقتی یک استثنا در Python رخ میدهد، سیستم اجرا (Runtime) باید کارهای زیر را انجام دهد:
1. ایجاد یک شیء استثنا: این شامل تخصیص حافظه و مقداردهی اولیه برای شیء استثنا است.
2. جمعآوری اطلاعات پشته: Python باید مسیر اجرای فعلی را بررسی کند و یک traceback ایجاد کند.
3. مدیریت جریان کنترل: سیستم اجرا باید به دنبال بلوکهای
این عملیاتها، بهویژه جمعآوری اطلاعات پشته و مدیریت جریان کنترل، هزینهبر هستند. در نتیجه، raise کردن یک استثنا در Python میتواند تاثیر منفی قابل توجهی بر عملکرد برنامه داشته باشد، به خصوص اگر استثناها به صورت مکرر رخ دهند.
رویکرد GoLang برای مدیریت خطاها
در زبان برنامهنویسی Go، مدیریت خطاها به گونهای متفاوت انجام میشود. به جای استفاده از استثناها، خطاها به عنوان مقادیر معمولی برگردانده میشوند. این رویکرد به دلایل زیر باعث افزایش عملکرد میشود:
1. عدم نیاز به مدیریت جریان کنترل پیچیده:
- در Go، خطاها به صورت مقادیر بازگشتی از توابع برگردانده میشوند. این رویکرد از مدیریت پیچیده جریان کنترل که در استثناها نیاز است، جلوگیری میکند. بنابراین، زمان و منابعی که برای جستجو و انتقال جریان کنترل در بلوکهای
2. عدم نیاز به جمعآوری اطلاعات پشته:
- وقتی یک خطا به عنوان مقدار بازگشتی مدیریت میشود، نیازی به جمعآوری اطلاعات پشته و ایجاد traceback نیست. این باعث کاهش هزینههای محاسباتی و بهبود عملکرد میشود.
3. کاهش سربار حافظه:
- ایجاد استثناها معمولاً شامل تخصیص حافظه برای شیء استثنا و اطلاعات پشته است. در مقابل، بازگرداندن یک خطا به عنوان مقدار بازگشتی نیاز به تخصیص حافظه اضافی ندارد و سربار حافظه را کاهش میدهد.
مثال از مدیریت خطا در Go
در این مثال، تابع
#exception
@Syntax_fa
در اکثر زبان ها، استثناها (Exceptions) ابزار اصلی برای مدیریت خطاها هستند. برای مثال وقتی یک استثنا در Python رخ میدهد، سیستم اجرا (Runtime) باید کارهای زیر را انجام دهد:
1. ایجاد یک شیء استثنا: این شامل تخصیص حافظه و مقداردهی اولیه برای شیء استثنا است.
2. جمعآوری اطلاعات پشته: Python باید مسیر اجرای فعلی را بررسی کند و یک traceback ایجاد کند.
3. مدیریت جریان کنترل: سیستم اجرا باید به دنبال بلوکهای
try و except بگردد و جریان اجرای برنامه را به بلوک مناسب منتقل کند.این عملیاتها، بهویژه جمعآوری اطلاعات پشته و مدیریت جریان کنترل، هزینهبر هستند. در نتیجه، raise کردن یک استثنا در Python میتواند تاثیر منفی قابل توجهی بر عملکرد برنامه داشته باشد، به خصوص اگر استثناها به صورت مکرر رخ دهند.
رویکرد GoLang برای مدیریت خطاها
در زبان برنامهنویسی Go، مدیریت خطاها به گونهای متفاوت انجام میشود. به جای استفاده از استثناها، خطاها به عنوان مقادیر معمولی برگردانده میشوند. این رویکرد به دلایل زیر باعث افزایش عملکرد میشود:
1. عدم نیاز به مدیریت جریان کنترل پیچیده:
- در Go، خطاها به صورت مقادیر بازگشتی از توابع برگردانده میشوند. این رویکرد از مدیریت پیچیده جریان کنترل که در استثناها نیاز است، جلوگیری میکند. بنابراین، زمان و منابعی که برای جستجو و انتقال جریان کنترل در بلوکهای
try و catch صرف میشود، در Go وجود ندراد.2. عدم نیاز به جمعآوری اطلاعات پشته:
- وقتی یک خطا به عنوان مقدار بازگشتی مدیریت میشود، نیازی به جمعآوری اطلاعات پشته و ایجاد traceback نیست. این باعث کاهش هزینههای محاسباتی و بهبود عملکرد میشود.
3. کاهش سربار حافظه:
- ایجاد استثناها معمولاً شامل تخصیص حافظه برای شیء استثنا و اطلاعات پشته است. در مقابل، بازگرداندن یک خطا به عنوان مقدار بازگشتی نیاز به تخصیص حافظه اضافی ندارد و سربار حافظه را کاهش میدهد.
مثال از مدیریت خطا در Go
package main
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", result)
}
در این مثال، تابع
divide یک خطا به عنوان مقدار بازگشتی برمیگرداند. در صورت بروز خطا، نیازی به مدیریت پیچیده جریان کنترل نیست و خطا به صورت معمولی پردازش میشود.#exception
@Syntax_fa
👍6👎1👏1
جلوگیری از کد تکراری (Duplicate Code)
کد تکراری یا Duplicate Code به بخشی از کد گفته میشود که بهطور مشابه یا یکسان در چندین نقطه از برنامه تکرار شده است. وجود کد تکراری نه تنها خوانایی کد را کاهش میدهد، بلکه باعث میشود مدیریت و نگهداری کد نیز پیچیدهتر شود.
آقا / خانم این کارارو نکن:
1. کپی و پیست کردن کد: یکی از رایجترین دلایل وجود کد تکراری، کپی و پیست کردن کد به جای استفاده از رویکردهای ماژولار و تابعی است.
2. عدم وجود طراحی مناسب: طراحی نادرست و عدم استفاده از اصول برنامهنویسی شیءگرا و الگوهای طراحی میتواند منجر به تکرار کد شود.
3. توسعه توسط تیمهای مختلف: توسعه موازی توسط تیمهای مختلف بدون هماهنگی مناسب نیز میتواند باعث ایجاد کد تکراری شود.
کد تکراری چه مشکلاتی بوجود میاره؟
1. افزایش پیچیدگی و کاهش خوانایی: کد تکراری باعث افزایش حجم کد و کاهش خوانایی آن میشود، که میتواند درک و نگهداری کد را دشوارتر کند.
2. افزایش احتمال خطا: در صورت نیاز به تغییر در بخشی از کد، باید همه نمونههای تکراری آن تغییر یابند که احتمال بروز خطا را افزایش میدهد.
3. کاهش کارایی توسعه: مدیریت کد تکراری زمانبر است و باعث کاهش کارایی فرآیند توسعه و نگهداری نرمافزار میشود.
روشهای جلوگیری از کد تکراری:
1. استفاده از توابع و روشهای ماژولار:
- با تبدیل کد تکراری به توابع یا متدهای مستقل، میتوان از تکرار کد جلوگیری کرد و از مزایای کد قابل استفاده مجدد بهرهمند شد.
2. استفاده از اصول برنامهنویسی شیءگرا:
- با استفاده از وراثت، ترکیب (composition) و سایر اصول برنامهنویسی شیءگرا میتوان کد تکراری را کاهش داد.
3. استفاده از الگوهای طراحی (Design Patterns):
- الگوهای طراحی مانند Adapter، Factory، Strategy و دیگر الگوها میتوانند به کاهش کد تکراری کمک کنند.
4. استفاده از ابزارهای تشخیص کد تکراری:
- ابزارهایی مانند SonarQube میتوانند به شناسایی و حذف کد تکراری کمک کنند.
مثال:
حرفای ما ثابت شدست مثال نمیخواد که 😁
پ.ن:
تو آخرین شرکتی که کار می کردم، بزرگوار یکی از طرفداران duplicate code بود.
حتی اون تابعی که قبلا نوشته بودو دوباره استفاده نمیکرد. کپی پیست میکرد تا بغل دست کدی که ازش استفاده کرده باشه😐
#duplicate_code
@Syntax_fa
کد تکراری یا Duplicate Code به بخشی از کد گفته میشود که بهطور مشابه یا یکسان در چندین نقطه از برنامه تکرار شده است. وجود کد تکراری نه تنها خوانایی کد را کاهش میدهد، بلکه باعث میشود مدیریت و نگهداری کد نیز پیچیدهتر شود.
آقا / خانم این کارارو نکن:
1. کپی و پیست کردن کد: یکی از رایجترین دلایل وجود کد تکراری، کپی و پیست کردن کد به جای استفاده از رویکردهای ماژولار و تابعی است.
2. عدم وجود طراحی مناسب: طراحی نادرست و عدم استفاده از اصول برنامهنویسی شیءگرا و الگوهای طراحی میتواند منجر به تکرار کد شود.
3. توسعه توسط تیمهای مختلف: توسعه موازی توسط تیمهای مختلف بدون هماهنگی مناسب نیز میتواند باعث ایجاد کد تکراری شود.
کد تکراری چه مشکلاتی بوجود میاره؟
1. افزایش پیچیدگی و کاهش خوانایی: کد تکراری باعث افزایش حجم کد و کاهش خوانایی آن میشود، که میتواند درک و نگهداری کد را دشوارتر کند.
2. افزایش احتمال خطا: در صورت نیاز به تغییر در بخشی از کد، باید همه نمونههای تکراری آن تغییر یابند که احتمال بروز خطا را افزایش میدهد.
3. کاهش کارایی توسعه: مدیریت کد تکراری زمانبر است و باعث کاهش کارایی فرآیند توسعه و نگهداری نرمافزار میشود.
روشهای جلوگیری از کد تکراری:
1. استفاده از توابع و روشهای ماژولار:
- با تبدیل کد تکراری به توابع یا متدهای مستقل، میتوان از تکرار کد جلوگیری کرد و از مزایای کد قابل استفاده مجدد بهرهمند شد.
2. استفاده از اصول برنامهنویسی شیءگرا:
- با استفاده از وراثت، ترکیب (composition) و سایر اصول برنامهنویسی شیءگرا میتوان کد تکراری را کاهش داد.
3. استفاده از الگوهای طراحی (Design Patterns):
- الگوهای طراحی مانند Adapter، Factory، Strategy و دیگر الگوها میتوانند به کاهش کد تکراری کمک کنند.
4. استفاده از ابزارهای تشخیص کد تکراری:
- ابزارهایی مانند SonarQube میتوانند به شناسایی و حذف کد تکراری کمک کنند.
مثال:
حرفای ما ثابت شدست مثال نمیخواد که 😁
پ.ن:
تو آخرین شرکتی که کار می کردم، بزرگوار یکی از طرفداران duplicate code بود.
حتی اون تابعی که قبلا نوشته بودو دوباره استفاده نمیکرد. کپی پیست میکرد تا بغل دست کدی که ازش استفاده کرده باشه😐
#duplicate_code
@Syntax_fa
👍8😁1
ساختمان داده Deque (Double-Ended Queue)
Deque،
مخفف "Double-Ended Queue"، یک نوع ساختمان داده است که بهصورت همزمان امکان اضافه و حذف عناصر را از هر دو انتها (ابتدا و انتها) فراهم میکند. این ویژگی Deque را به یک ابزار قدرتمند در بسیاری از الگوریتمها و برنامههای کاربردی تبدیل کرده است.
ویژگیهای Deque
1. دسترسی دو طرفه: امکان اضافه و حذف عناصر از (ابتدا و انتها) را فراهم میکند.
2. انعطافپذیری: ترکیبی از ویژگیهای پشته (stack) و صف (queue) را داراست.
3. پیچیدگی زمانی بهینه: عملیات افزودن و حذف در هر دو انتها دارای زمان اجرای O(1) است(اگر به لیست های پیوندی پیاده شود)
عملیاتهای اصلی در Deque:
1. افزودن به ابتدا (Add to Front):
- عملیات:
- توضیح: این عملیات یک عنصر را به ابتدای Deque اضافه میکند.
2. افزودن به انتها (Add to Rear):
- عملیات:
- توضیح: این عملیات یک عنصر را به انتهای Deque اضافه میکند.
3. حذف از ابتدا (Remove from Front):
- عملیات:
- توضیح: این عملیات اولین عنصر را از Deque حذف میکند.
4. حذف از انتها (Remove from Rear):
- عملیات:
- توضیح: این عملیات آخرین عنصر را از Deque حذف میکند.
5. دسترسی به اولین عنصر (Peek at Front):
- عملیات:
- توضیح: این عملیات اولین عنصر را بدون حذف از Deque برمیگرداند.
6. دسترسی به آخرین عنصر (Peek at Rear):
- عملیات:
- توضیح: این عملیات آخرین عنصر را بدون حذف از Deque برمیگرداند.
7. بررسی خالی بودن (Check if Empty):
- عملیات:
- توضیح: این عملیات بررسی میکند که آیا Deque خالی است یا خیر.
8. بررسی اندازه (Check Size):
- عملیات:
- توضیح: این عملیات تعداد عناصر موجود در Deque را برمیگرداند.
پیادهسازی Deque
برای پیادهسازی Deque، چندین ساختار داده وجود دارند که میتوانند به کار گرفته شوند، اما دو ساختار دادهای که معمولاً برای پیادهسازی Deque مناسب هستند عبارتند از:
1. لیست پیوندی دوطرفه (Doubly Linked List):
- توضیح: لیست پیوندی دوطرفه دارای گرههایی است که هر گره شامل دو اشارهگر است: یکی به گره قبلی و دیگری به گره بعدی.
این ساختار داده امکان افزودن و حذف عناصر از هر دو انتها را با پیچیدگی زمانی O(1) فراهم میکند.
- مزایا:
- زمان اجرای بهینه برای عملیات افزودن و حذف.
- انعطافپذیری بالا.
- معایب:
- سربار حافظه به دلیل استفاده از اشارهگرها.
2. آرایه دایرهای (Circular Array):
- توضیح: آرایه دایرهای یک آرایه ثابت است که انتهای آن به ابتدای آرایه پیوند داده شده است. این ساختار داده نیز امکان افزودن و حذف عناصر از هر دو انتها را با پیچیدگی زمانی O(1) فراهم میکند.
- مزایا:
- استفاده کارآمد از حافظه.
- دسترسی سریع به عناصر.
- معایب:
- اندازه ثابت آرایه میتواند منجر به مشکلاتی در صورت نیاز به فضای بیشتر یا کمتر شود.
- نیاز به مدیریت دقیق اندیسها برای جلوگیری از سرریز (overflow) یا سربار (underflow).
تمرین:
مثال Deque رو تو زبانی که کار میکنید پیاده سازیش کنید و توی کامنت ارسال کنید.
#deque #data_structures
@Syntax_fa
Deque،
مخفف "Double-Ended Queue"، یک نوع ساختمان داده است که بهصورت همزمان امکان اضافه و حذف عناصر را از هر دو انتها (ابتدا و انتها) فراهم میکند. این ویژگی Deque را به یک ابزار قدرتمند در بسیاری از الگوریتمها و برنامههای کاربردی تبدیل کرده است.
ویژگیهای Deque
1. دسترسی دو طرفه: امکان اضافه و حذف عناصر از (ابتدا و انتها) را فراهم میکند.
2. انعطافپذیری: ترکیبی از ویژگیهای پشته (stack) و صف (queue) را داراست.
3. پیچیدگی زمانی بهینه: عملیات افزودن و حذف در هر دو انتها دارای زمان اجرای O(1) است(اگر به لیست های پیوندی پیاده شود)
عملیاتهای اصلی در Deque:
1. افزودن به ابتدا (Add to Front):
- عملیات:
addFirst(element)- توضیح: این عملیات یک عنصر را به ابتدای Deque اضافه میکند.
2. افزودن به انتها (Add to Rear):
- عملیات:
addLast(element)- توضیح: این عملیات یک عنصر را به انتهای Deque اضافه میکند.
3. حذف از ابتدا (Remove from Front):
- عملیات:
removeFirst()- توضیح: این عملیات اولین عنصر را از Deque حذف میکند.
4. حذف از انتها (Remove from Rear):
- عملیات:
removeLast()- توضیح: این عملیات آخرین عنصر را از Deque حذف میکند.
5. دسترسی به اولین عنصر (Peek at Front):
- عملیات:
peekFirst()- توضیح: این عملیات اولین عنصر را بدون حذف از Deque برمیگرداند.
6. دسترسی به آخرین عنصر (Peek at Rear):
- عملیات:
peekLast()- توضیح: این عملیات آخرین عنصر را بدون حذف از Deque برمیگرداند.
7. بررسی خالی بودن (Check if Empty):
- عملیات:
isEmpty()- توضیح: این عملیات بررسی میکند که آیا Deque خالی است یا خیر.
8. بررسی اندازه (Check Size):
- عملیات:
size()- توضیح: این عملیات تعداد عناصر موجود در Deque را برمیگرداند.
پیادهسازی Deque
برای پیادهسازی Deque، چندین ساختار داده وجود دارند که میتوانند به کار گرفته شوند، اما دو ساختار دادهای که معمولاً برای پیادهسازی Deque مناسب هستند عبارتند از:
1. لیست پیوندی دوطرفه (Doubly Linked List):
- توضیح: لیست پیوندی دوطرفه دارای گرههایی است که هر گره شامل دو اشارهگر است: یکی به گره قبلی و دیگری به گره بعدی.
این ساختار داده امکان افزودن و حذف عناصر از هر دو انتها را با پیچیدگی زمانی O(1) فراهم میکند.
- مزایا:
- زمان اجرای بهینه برای عملیات افزودن و حذف.
- انعطافپذیری بالا.
- معایب:
- سربار حافظه به دلیل استفاده از اشارهگرها.
2. آرایه دایرهای (Circular Array):
- توضیح: آرایه دایرهای یک آرایه ثابت است که انتهای آن به ابتدای آرایه پیوند داده شده است. این ساختار داده نیز امکان افزودن و حذف عناصر از هر دو انتها را با پیچیدگی زمانی O(1) فراهم میکند.
- مزایا:
- استفاده کارآمد از حافظه.
- دسترسی سریع به عناصر.
- معایب:
- اندازه ثابت آرایه میتواند منجر به مشکلاتی در صورت نیاز به فضای بیشتر یا کمتر شود.
- نیاز به مدیریت دقیق اندیسها برای جلوگیری از سرریز (overflow) یا سربار (underflow).
تمرین:
مثال Deque رو تو زبانی که کار میکنید پیاده سازیش کنید و توی کامنت ارسال کنید.
#deque #data_structures
@Syntax_fa
👍7
چند نکته در خصوص الگوریتم های بازگشتی
الگوریتمهای Tail Recursion:
مفهوم Tail Recursion
الگوریتمهای بازگشتی، تکنیکی برای حل مسائل پیچیده از طریق تجزیه آنها به زیرمسائل کوچکتر و حل آنها با استفاده از خود تابع بازگشتی هستند. یکی از انواع خاص این الگوریتمها، Tail Recursion است. در tail recursion، فراخوانی بازگشتی به عنوان آخرین عملیات در تابع انجام میشود. به عبارت دیگر، هیچ عملیات دیگری بعد از فراخوانی بازگشتی انجام نمیشود. این ویژگی اجازه میدهد که حالت فعلی تابع دیگر نیازی به نگهداری در حافظه نداشته باشد.
به عنوان مثال، تابع بازگشتی برای پیدا کردن یک عدد در آرایه مرتب شده:
نکته:
الگوریتم های بازگشت دمی رو ، میشه بصورت خطی نوشت.
بهینهسازی Tail Recursion توسط کامپایلرها
یکی از ویژگیهای مهم بازگشت دم این است که بسیاری از کامپایلرها و مفسرهای زبانهای برنامهنویسی میتوانند این نوع بازگشت را بهینهسازی کنند. این بهینهسازی که به نام Tail Call Optimization (TCO) یا بهینهسازی فراخوانی دم شناخته میشود، به کامپایلر اجازه میدهد که فراخوانیهای بازگشتی دم را به یک حلقه ساده تبدیل کند، در نتیجه نیاز به استفاده از پشته بازگشتی را حذف میکند.
در زبانهای برنامهنویسی که از این بهینهسازی پشتیبانی میکنند، مانند Haskell، Scheme و برخی پیادهسازیهای Python (مثل PyPy)، کامپایلر میتواند بازگشت دم را به یک حلقه
این تبدیل باعث میشود که عملکرد و بهرهوری برنامه بهبود یابد، زیرا دیگر نیازی به افزایش عمق پشته بازگشتی برای هر فراخوانی وجود ندارد.
محدودیتهای Recursion Stack
در اکثر زبانهای برنامهنویسی، هر بار که یک تابع بازگشتی فراخوانی میشود، یک فریم جدید به پشته بازگشتی اضافه میشود. پشته بازگشتی یا recursion stack مکانی است که اطلاعات مربوط به هر فراخوانی، شامل پارامترها، متغیرهای محلی و آدرس بازگشت، ذخیره میشود.
این پشته محدودیتهای خاص خود را دارد:
1. محدودیت حافظه: هر پشته بازگشتی مقدار مشخصی از حافظه را مصرف میکند. در صورتی که عمق بازگشتی زیاد باشد، ممکن است برنامه با خطای Stack Overflow مواجه شود.
2. کاهش کارایی: هر فراخوانی بازگشتی نیاز به زمان اضافی برای مدیریت فریمهای پشته دارد که میتواند منجر به کاهش کارایی شود.
3. پیچیدگی کد: مدیریت دستی بازگشتها و پارامترها میتواند کد را پیچیدهتر و مشکلتر برای فهم کند.
نکته:
اکثرا الگوریتمی که بصورت خطی بتونیم بنویسیم، نسبت به الگوریتم بازگشتی پرفورمنس بهتری داره.
#recursion
@Syntax_fa
الگوریتمهای Tail Recursion:
مفهوم Tail Recursion
الگوریتمهای بازگشتی، تکنیکی برای حل مسائل پیچیده از طریق تجزیه آنها به زیرمسائل کوچکتر و حل آنها با استفاده از خود تابع بازگشتی هستند. یکی از انواع خاص این الگوریتمها، Tail Recursion است. در tail recursion، فراخوانی بازگشتی به عنوان آخرین عملیات در تابع انجام میشود. به عبارت دیگر، هیچ عملیات دیگری بعد از فراخوانی بازگشتی انجام نمیشود. این ویژگی اجازه میدهد که حالت فعلی تابع دیگر نیازی به نگهداری در حافظه نداشته باشد.
به عنوان مثال، تابع بازگشتی برای پیدا کردن یک عدد در آرایه مرتب شده:
func SearchRecursive(array []int, x int) bool {
if len(array) == 1 {
return array[0] == x
}
middle := len(array) / 2
if array[middle] == x {
return true
}
if array[middle] < x && len(array) >= middle+1 {
return SearchRecursive(array[middle:], x)
} else {
return SearchRecursive(array[:middle], x)
}
}
نکته:
بهینهسازی Tail Recursion توسط کامپایلرها
یکی از ویژگیهای مهم بازگشت دم این است که بسیاری از کامپایلرها و مفسرهای زبانهای برنامهنویسی میتوانند این نوع بازگشت را بهینهسازی کنند. این بهینهسازی که به نام Tail Call Optimization (TCO) یا بهینهسازی فراخوانی دم شناخته میشود، به کامپایلر اجازه میدهد که فراخوانیهای بازگشتی دم را به یک حلقه ساده تبدیل کند، در نتیجه نیاز به استفاده از پشته بازگشتی را حذف میکند.
در زبانهای برنامهنویسی که از این بهینهسازی پشتیبانی میکنند، مانند Haskell، Scheme و برخی پیادهسازیهای Python (مثل PyPy)، کامپایلر میتواند بازگشت دم را به یک حلقه
for یا while تبدیل کند:def factorial(n):
acc = 1
while n > 0:
acc *= n
n -= 1
return acc
این تبدیل باعث میشود که عملکرد و بهرهوری برنامه بهبود یابد، زیرا دیگر نیازی به افزایش عمق پشته بازگشتی برای هر فراخوانی وجود ندارد.
محدودیتهای Recursion Stack
در اکثر زبانهای برنامهنویسی، هر بار که یک تابع بازگشتی فراخوانی میشود، یک فریم جدید به پشته بازگشتی اضافه میشود. پشته بازگشتی یا recursion stack مکانی است که اطلاعات مربوط به هر فراخوانی، شامل پارامترها، متغیرهای محلی و آدرس بازگشت، ذخیره میشود.
این پشته محدودیتهای خاص خود را دارد:
1. محدودیت حافظه: هر پشته بازگشتی مقدار مشخصی از حافظه را مصرف میکند. در صورتی که عمق بازگشتی زیاد باشد، ممکن است برنامه با خطای Stack Overflow مواجه شود.
2. کاهش کارایی: هر فراخوانی بازگشتی نیاز به زمان اضافی برای مدیریت فریمهای پشته دارد که میتواند منجر به کاهش کارایی شود.
3. پیچیدگی کد: مدیریت دستی بازگشتها و پارامترها میتواند کد را پیچیدهتر و مشکلتر برای فهم کند.
نکته:
اکثرا الگوریتمی که بصورت خطی بتونیم بنویسیم، نسبت به الگوریتم بازگشتی پرفورمنس بهتری داره.
#recursion
@Syntax_fa
🔥3👍2
فامیل و آشنا:
شنیدم برنامه نویسی و طراحی وب سایت بلدی
_ آره بلدم
یه ایده دارم بیا بزنش سودش نصف نصف میلیاردر میشیم
_ فرار
#fun
@Syntax_fa
شنیدم برنامه نویسی و طراحی وب سایت بلدی
_ آره بلدم
یه ایده دارم بیا بزنش سودش نصف نصف میلیاردر میشیم
_ فرار
#fun
@Syntax_fa
🤣18
Massimo Dev
📗 اصول مهم کد ریویو یا بررسی کد: YAGNI، KISS و DRY
من خودم موقع کد ریویوها این سه اصل رو خیلی با دقت رعایت میکنم.
🔶 1. YAGNI (You aren't gonna need it):
- این اصل داره میگه از اضافه کردن ویژگیها یا کدی که الان لازم نیست خودداری کن. این کار باعث میشه کدت تمیز و ساده بمونه.
🔹 - مثال: اگه تو داری یه فرم ساده برای ورود اطلاعات مینویسی، لازم نیست از الان برای فیلتر کردن دادهها یا اضافه کردن قابلیتهای پیچیده فکر کنی. اونها رو بعداً وقتی واقعاً نیاز بود اضافه کن.
🔶 2. KISS (Keep it simple & stupid):
- میگه سعی کن کدت ساده باشه. راهحلهای پیچیده معمولاً میشه سادهترشون کرد و این باعث میشه کد راحتتر خوانده و نگهداری بشه.
🔹 - مثال: به جای نوشتن یه تابع پیچیده برای محاسبه تخفیف، یه تابع ساده بنویس که فقط تخفیف رو بر اساس درصد حساب کنه. اگه بعداً نیاز به محاسبات پیچیدهتر بود، اون موقع بهش اضافه کن.
🔶 3. DRY (Don't repeat yourself):
- میگه جایی که میشه، از کدهای موجود استفاده کن و از تکرار کد خودداری کن. این کار باعث میشه نگهداری کد راحتتر باشه و احتمال خطاها کمتر بشه.
🔹- مثال: اگه داری چند بار یه عملیات مشابه مثل محاسبه مالیات رو انجام میدی، اون رو تو یه تابع مجزا بنویس و هر بار از اون تابع استفاده کن.
با رعایت این اصول در کد ریویوها، میتونی کدی بنویسی که هم خواناتر، هم قابل نگهداریتر و هم بهینهتر باشه. همه چیز در مورد نوشتن کد کمتر ولی بهتره.
Source:
@gopher_academy
@Syntax_fa
📗 اصول مهم کد ریویو یا بررسی کد: YAGNI، KISS و DRY
من خودم موقع کد ریویوها این سه اصل رو خیلی با دقت رعایت میکنم.
🔶 1. YAGNI (You aren't gonna need it):
- این اصل داره میگه از اضافه کردن ویژگیها یا کدی که الان لازم نیست خودداری کن. این کار باعث میشه کدت تمیز و ساده بمونه.
🔹 - مثال: اگه تو داری یه فرم ساده برای ورود اطلاعات مینویسی، لازم نیست از الان برای فیلتر کردن دادهها یا اضافه کردن قابلیتهای پیچیده فکر کنی. اونها رو بعداً وقتی واقعاً نیاز بود اضافه کن.
🔶 2. KISS (Keep it simple & stupid):
- میگه سعی کن کدت ساده باشه. راهحلهای پیچیده معمولاً میشه سادهترشون کرد و این باعث میشه کد راحتتر خوانده و نگهداری بشه.
🔹 - مثال: به جای نوشتن یه تابع پیچیده برای محاسبه تخفیف، یه تابع ساده بنویس که فقط تخفیف رو بر اساس درصد حساب کنه. اگه بعداً نیاز به محاسبات پیچیدهتر بود، اون موقع بهش اضافه کن.
🔶 3. DRY (Don't repeat yourself):
- میگه جایی که میشه، از کدهای موجود استفاده کن و از تکرار کد خودداری کن. این کار باعث میشه نگهداری کد راحتتر باشه و احتمال خطاها کمتر بشه.
🔹- مثال: اگه داری چند بار یه عملیات مشابه مثل محاسبه مالیات رو انجام میدی، اون رو تو یه تابع مجزا بنویس و هر بار از اون تابع استفاده کن.
با رعایت این اصول در کد ریویوها، میتونی کدی بنویسی که هم خواناتر، هم قابل نگهداریتر و هم بهینهتر باشه. همه چیز در مورد نوشتن کد کمتر ولی بهتره.
Source:
@gopher_academy
@Syntax_fa
👍12
This media is not supported in your browser
VIEW IN TELEGRAM
وقتی بعد از یه عمر
نصب ویندوز روی کلی سیستم،
کرک برنامه های کاربردی مختلف،
کرک بازی ها از کودکی تا به امروز،
تماشای غیر قانونی فیلم و سریال ها،
استفاده از اکانت های دزدی،
دانلود رایگان کتاب ها از کانال های تلگرامی،
دیدن دوره های پابلیک شده چند میلیونی،
صد ها فقره کپی رایت،
میری اون دنیا.
#fun
@Syntax_fa
نصب ویندوز روی کلی سیستم،
کرک برنامه های کاربردی مختلف،
کرک بازی ها از کودکی تا به امروز،
تماشای غیر قانونی فیلم و سریال ها،
استفاده از اکانت های دزدی،
دانلود رایگان کتاب ها از کانال های تلگرامی،
دیدن دوره های پابلیک شده چند میلیونی،
صد ها فقره کپی رایت،
میری اون دنیا.
#fun
@Syntax_fa
🤣24💔3👍1😁1
Lambda Expression
توضیح: Lambda expressions، که به عنوان anonymous functions (توابع بینام) نیز شناخته میشوند، توابعی هستند که بدون نام تعریف میشوند و برای عملیاتهای کوچک و ساده مورد استفاده قرار میگیرند. در پایتون، این توابع با استفاده از کلمه کلیدی
کار با Lambda Expression در پایتون
-
-
مثال ساده
در این مثال، یک تابع لامبدا تعریف میکنیم که دو عدد را با هم جمع میکند:
در اینجا، تابع لامبدا دو آرگومان
استفاده از Lambda Expressions در توابع higher-order
توابع higher-order توابعی هستند که یک یا چند تابع را به عنوان آرگومان میپذیرند و یا تابعی را برمیگردانند. Lambda expressions معمولاً در توابع higher-order مانند
مثال با
تابع
مثال با
تابع
مثال با
تابع
#lambda_expression #python #filter #map #reduce
@Syntax_fa
توضیح: Lambda expressions، که به عنوان anonymous functions (توابع بینام) نیز شناخته میشوند، توابعی هستند که بدون نام تعریف میشوند و برای عملیاتهای کوچک و ساده مورد استفاده قرار میگیرند. در پایتون، این توابع با استفاده از کلمه کلیدی
lambda تعریف میشوند. کار با Lambda Expression در پایتون
lambda arguments: expression
-
arguments: آرگومانهایی که تابع میپذیرد.-
expression: عبارتی که ارزیابی میشود و نتیجه آن برگردانده میشود.مثال ساده
در این مثال، یک تابع لامبدا تعریف میکنیم که دو عدد را با هم جمع میکند:
add = lambda x, y: x + y
result = add(3, 4)
print(result) # Output: 7
در اینجا، تابع لامبدا دو آرگومان
x و y میپذیرد و مقدار x + y را برمیگرداند.استفاده از Lambda Expressions در توابع higher-order
توابع higher-order توابعی هستند که یک یا چند تابع را به عنوان آرگومان میپذیرند و یا تابعی را برمیگردانند. Lambda expressions معمولاً در توابع higher-order مانند
map(), filter(), و reduce() استفاده میشوند.مثال با
map()تابع
map() یک تابع را روی هر آیتم از یک iterable اعمال میکند:numbers = [1, 2, 3, 4, 5]
doubled = map(lambda x: x * 2, numbers)
print(list(doubled)) # Output: [2, 4, 6, 8, 10]
مثال با
filter()تابع
filter() آیتمهایی را که تابع به عنوان True ارزیابی میکند، فیلتر میکند:numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = filter(lambda x: x % 2 == 0, numbers)
print(list(evens)) # Output: [2, 4, 6, 8, 10]
مثال با
reduce()تابع
reduce() از ماژول functools (توضیح اینکه دقیقا چطور عمل میکنه رو خواستید بگید تو یه پست دیگه بگم):from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print(product) # Output: 120
#lambda_expression #python #filter #map #reduce
@Syntax_fa
👍6
Syntax | سینتکس
iterable
چند تا نکته کوتاه درباره پیمایش
iterator:
یک Iterator چیزی هستش که به ما این امکان رو میده عناصر یک ساختمان داده رو یکی پس از دیگری و به ترتیب دسترسی پیدا کنیم.
iterable:
ساختمان داده ای که به ما اجازه iterator رو بده، بهش iterable و یا قابل پیمایش میگیم.
iteration:
فرآیند پیمایش کردن روی عناصر یک iterable هستش.
تو پیاده سازی ساختمان داده یه نکته ای که باید بهش دقت کنید این هستش که اگه نیازه، براش قابلیت پیمایش شدن رو پیاده سازی کنید.
یک iterator معمولا متد های زیر رو داره:
next()
این متد یه خونه میره جلو تر و مقدارش رو برمیگردونه
hasNext()
این متد که یک boolean برمیگردونه، بهمون میگه مقدار بعدی وجود داره یا نه.
remove()
با این متد، عنصری که الان اونجا هستیم رو پاک میکنیم.
مثال ساده استفاده از iterator:
نکته:
معمولا iterator ها دربرابر concurrent modification ایمن هستن. یعنی وقتی روی یک ساختمان داده دارید پیمایش می کنید، نمیتونید بصورت همزمان مقداری رو بهش اضافه و یا حذف کنید.
@Syntax_fa
iterator:
یک Iterator چیزی هستش که به ما این امکان رو میده عناصر یک ساختمان داده رو یکی پس از دیگری و به ترتیب دسترسی پیدا کنیم.
iterable:
ساختمان داده ای که به ما اجازه iterator رو بده، بهش iterable و یا قابل پیمایش میگیم.
iteration:
فرآیند پیمایش کردن روی عناصر یک iterable هستش.
تو پیاده سازی ساختمان داده یه نکته ای که باید بهش دقت کنید این هستش که اگه نیازه، براش قابلیت پیمایش شدن رو پیاده سازی کنید.
یک iterator معمولا متد های زیر رو داره:
next()
این متد یه خونه میره جلو تر و مقدارش رو برمیگردونه
hasNext()
این متد که یک boolean برمیگردونه، بهمون میگه مقدار بعدی وجود داره یا نه.
remove()
با این متد، عنصری که الان اونجا هستیم رو پاک میکنیم.
مثال ساده استفاده از iterator:
while it.hasnext():
print(it.next())
نکته:
معمولا iterator ها دربرابر concurrent modification ایمن هستن. یعنی وقتی روی یک ساختمان داده دارید پیمایش می کنید، نمیتونید بصورت همزمان مقداری رو بهش اضافه و یا حذف کنید.
@Syntax_fa
👍8
پنج تا از مخفف های معروف دنیای برنامه نویسی و معنی اونا:
TDD(tea drinking developers):
به معنی برنامه نویسان چای خور
REST(really exhausted software team):
تیم نرم افزاری پنچر
HTML(how to meet ladies):
چگونه با خانم ها آشنا شویم
CSS(cant style stuff):
وقتی بعد کلی ور رفتن، نتونستید استایل فرانت رو درست کنید میگید سی اس اس یعنی نمیتونم چیز هارو استایل کنم.
SQL(singles have a quite life):
سینگل ها زندگیه آرومی دارن
#fun
@Syntax_fa
TDD(tea drinking developers):
به معنی برنامه نویسان چای خور
REST(really exhausted software team):
تیم نرم افزاری پنچر
HTML(how to meet ladies):
چگونه با خانم ها آشنا شویم
CSS(cant style stuff):
وقتی بعد کلی ور رفتن، نتونستید استایل فرانت رو درست کنید میگید سی اس اس یعنی نمیتونم چیز هارو استایل کنم.
SQL(singles have a quite life):
سینگل ها زندگیه آرومی دارن
#fun
@Syntax_fa
😁20🤣7
✍️ Massimo Dev
🔵⚪️ نسخهبندی API یا API Versioning میدونی چیه؟
🚨 نسخهبندی API یه راهحلیه برای مدیریت تغییرات API در طول زمان بدون اینکه کاربرهای قدیمی دچار مشکل بشن. وقتی که API تغییر میکنه و ویژگیهای جدیدی بهش اضافه میشه یا مشکلاتی برطرف میشن، نسخهبندی کمک میکنه تا کاربرهایی که از نسخههای قدیمی استفاده میکنن همچنان بدون مشکل به کارشون ادامه بدن و در عین حال نسخههای جدیدتر هم در دسترس باشن.
✳️ بذار یه مثال ساده بزنم:
فرض کن یه API داری که اطلاعات آب و هوا رو میده. اولین نسخهی API (v1) یه اندپوینت داره به اسم
که اطلاعات سادهای مثل دما و رطوبت رو برمیگردونه.
نسخه 1 (v1):
بعداً تصمیم میگیری اطلاعات بیشتری مثل سرعت باد و پیشبینی هوا رو اضافه کنی. برای اینکه کاربرهای قدیمی دچار مشکل نشن، یه نسخه جدید از API (v2) معرفی میکنی:
نسخه 2 (v2):
به این ترتیب، کاربرهایی که از نسخه قدیمی (v1) استفاده میکنن همچنان بدون تغییر به کارشون ادامه میدن و کاربرهای جدید میتونن از ویژگیهای جدید نسخه 2 (v2) استفاده کنن.
✳️ بهترین روشها برای نسخهبندی API
🔹نسخهبندی URL:
- شماره نسخه رو توی مسیر URL قرار بده، مثل
و
- مثال:
🔹نسخهبندی با هدرها:
- از هدرهای سفارشی برای مشخص کردن نسخه استفاده کن.
- مثال:
با
🔹نسخهبندی با پارامترهای کوئری:
- شماره نسخه رو به عنوان پارامتر کوئری قرار بده.
- مثال:
🔹استراتژی پایاندهی به نسخههای قدیمی:
- به کاربرها بگو که نسخه قدیمی چه زمانی غیرفعال میشه و راهنمایی برای مهاجرت به نسخههای جدید بده.
- یه بازه زمانی مشخص و راهنمای مهاجرت ارائه کن.
🔹مستندسازی:
- برای هر نسخه از API مستندات واضح و دقیقی فراهم کن.
- مثالها، موارد استفاده و راهنماهای مهاجرت رو توضیح بده.
🔹سازگاری با نسخههای قبلی:
- تا حد ممکن نسخههای جدید رو سازگار با نسخههای قبلی نگه دار تا کاربرها دچار مشکل نشن.
- از نسخهبندی معنایی (مثل major.minor.patch) استفاده کن تا سطح تغییرات رو نشون بدی مثلا نسخه ،29.5.0 شده 29.5.1
🔹سیاست نسخهبندی:
- یه سیاست نسخهبندی تعریف کن که مشخص کنه کی و چطور نسخههای جدید منتشر میشن.
- واضح بگو که چه زمانی تغییرات بزرگ نیاز به یه نسخه جدید دارن.
Source:
@gopher_academy
#api_versioning
@Syntax_fa
🔵⚪️ نسخهبندی API یا API Versioning میدونی چیه؟
🚨 نسخهبندی API یه راهحلیه برای مدیریت تغییرات API در طول زمان بدون اینکه کاربرهای قدیمی دچار مشکل بشن. وقتی که API تغییر میکنه و ویژگیهای جدیدی بهش اضافه میشه یا مشکلاتی برطرف میشن، نسخهبندی کمک میکنه تا کاربرهایی که از نسخههای قدیمی استفاده میکنن همچنان بدون مشکل به کارشون ادامه بدن و در عین حال نسخههای جدیدتر هم در دسترس باشن.
✳️ بذار یه مثال ساده بزنم:
فرض کن یه API داری که اطلاعات آب و هوا رو میده. اولین نسخهی API (v1) یه اندپوینت داره به اسم
/weatherکه اطلاعات سادهای مثل دما و رطوبت رو برمیگردونه.
نسخه 1 (v1):
GET /v1/weather?city=London
Result:
{
"temperature": "15°C",
"humidity": "75%"
}
بعداً تصمیم میگیری اطلاعات بیشتری مثل سرعت باد و پیشبینی هوا رو اضافه کنی. برای اینکه کاربرهای قدیمی دچار مشکل نشن، یه نسخه جدید از API (v2) معرفی میکنی:
نسخه 2 (v2):
GET /v2/weather?city=London
Result:
{
"temperature": "15°C",
"humidity": "75%",
"wind_speed": "10 km/h",
"forecast": [
{"day": "Monday", "temperature": "16°C"},
{"day": "Tuesday", "temperature": "17°C"}
]
}
به این ترتیب، کاربرهایی که از نسخه قدیمی (v1) استفاده میکنن همچنان بدون تغییر به کارشون ادامه میدن و کاربرهای جدید میتونن از ویژگیهای جدید نسخه 2 (v2) استفاده کنن.
✳️ بهترین روشها برای نسخهبندی API
🔹نسخهبندی URL:
- شماره نسخه رو توی مسیر URL قرار بده، مثل
/v1/resourceو
/v2/resource- مثال:
GET /api/v1/weather،GET /api/v2/weather.🔹نسخهبندی با هدرها:
- از هدرهای سفارشی برای مشخص کردن نسخه استفاده کن.
- مثال:
GET /api/weatherبا
headers: {"API-Version": "v2"}🔹نسخهبندی با پارامترهای کوئری:
- شماره نسخه رو به عنوان پارامتر کوئری قرار بده.
- مثال:
GET /api/weather?version=2🔹استراتژی پایاندهی به نسخههای قدیمی:
- به کاربرها بگو که نسخه قدیمی چه زمانی غیرفعال میشه و راهنمایی برای مهاجرت به نسخههای جدید بده.
- یه بازه زمانی مشخص و راهنمای مهاجرت ارائه کن.
🔹مستندسازی:
- برای هر نسخه از API مستندات واضح و دقیقی فراهم کن.
- مثالها، موارد استفاده و راهنماهای مهاجرت رو توضیح بده.
🔹سازگاری با نسخههای قبلی:
- تا حد ممکن نسخههای جدید رو سازگار با نسخههای قبلی نگه دار تا کاربرها دچار مشکل نشن.
- از نسخهبندی معنایی (مثل major.minor.patch) استفاده کن تا سطح تغییرات رو نشون بدی مثلا نسخه ،29.5.0 شده 29.5.1
🔹سیاست نسخهبندی:
- یه سیاست نسخهبندی تعریف کن که مشخص کنه کی و چطور نسخههای جدید منتشر میشن.
- واضح بگو که چه زمانی تغییرات بزرگ نیاز به یه نسخه جدید دارن.
Source:
@gopher_academy
#api_versioning
@Syntax_fa
👍7
برای اولین بار در لینکدین یکی اخراج شده و بدلایل:
- شروع فصل جدیدی از زندگیه حرفه ای
- کسب تجربیات جدید
- روبرو شدن با چالش های نو
- تصمیم به جدا شدن از شرکت قبلی
و ... دنبال کار نمیگرده.
#fun
@Syntax_fa
- شروع فصل جدیدی از زندگیه حرفه ای
- کسب تجربیات جدید
- روبرو شدن با چالش های نو
- تصمیم به جدا شدن از شرکت قبلی
و ... دنبال کار نمیگرده.
#fun
@Syntax_fa
😁5🤣3👍1
Syntax | سینتکس
برای اولین بار در لینکدین یکی اخراج شده و بدلایل: - شروع فصل جدیدی از زندگیه حرفه ای - کسب تجربیات جدید - روبرو شدن با چالش های نو - تصمیم به جدا شدن از شرکت قبلی و ... دنبال کار نمیگرده. #fun @Syntax_fa
چجوری تو لینکدین پستامون ویو خوبی بگیره؟
بعضیا میگن پستای لینکدینم اصلا ویو نمیگیره. حتی هیچکس منو تو لینکدین به انگشتشم نمیگیره یه لحظه رو ری اکشن بزنه.
خب تو این پست چند تا نکته رو با هم بررسی میکنیم تا تو لینکدین پیشرفت کنید:
عنوان شغلی:
نگو کارمند فروش😐 بگو استراتژیست تحول فروش جهانی😍
نگو برنامه نویس 😐 بگو مهندس معماری دیجیتال 😎
نگو گرافیست بگو نقاش رویا های شما
داستان های الهام بخش
یادت نره درباره چیزهایی که الهام بخش هستن بنویسی
مثلا:
روزی که یه خودکار رو پیدا کردم و زندگیم متحول شد!!
این موضوع چرتو هر کی ببینه میگه ببینم چی میگه
گزارش پیشرفت ها و مسیری که رفتید:
این مورد خیلی خوب ویو میخوره
مثلا:
از Hello worl تا روزی که در شرکت دارغوزآباد استخدام شدم
عکس حرفه ای و پرانرژی
نیشتو قشنگ باز کن بعد با یدونه دوربین حرفه ای عکس بگیر بذار پروفایل
تشکر از دیگران
تا جایی که میتونی برای بقیه بم.. یعنی ازشون تشکر کن
حتی یکی بهت فحش داد بگو تشکر میکنم بابت اظهار نظرتون
نقل قول های الهام بخش
برو تو گوگل سرچ کن«سخن بزرگان» بعد تو لینکدین پست کن.
ایراد گرفتن از بقیه
تا میتونی پست بذار بگو لینکدین اینستا نیست و لینکدین خیلی برنامه خاصیه فقط آدمای خاص میتونن توش فعالیت کنن
نکته خیلی مهم:
اگه پسرید تمامی این نکاتو بیخیال شید چون جواب نمیده
#fun
@Syntax_fa
بعضیا میگن پستای لینکدینم اصلا ویو نمیگیره. حتی هیچکس منو تو لینکدین به انگشتشم نمیگیره یه لحظه رو ری اکشن بزنه.
خب تو این پست چند تا نکته رو با هم بررسی میکنیم تا تو لینکدین پیشرفت کنید:
عنوان شغلی:
نگو کارمند فروش😐 بگو استراتژیست تحول فروش جهانی😍
نگو برنامه نویس 😐 بگو مهندس معماری دیجیتال 😎
نگو گرافیست بگو نقاش رویا های شما
داستان های الهام بخش
یادت نره درباره چیزهایی که الهام بخش هستن بنویسی
مثلا:
روزی که یه خودکار رو پیدا کردم و زندگیم متحول شد!!
این موضوع چرتو هر کی ببینه میگه ببینم چی میگه
گزارش پیشرفت ها و مسیری که رفتید:
این مورد خیلی خوب ویو میخوره
مثلا:
از Hello worl تا روزی که در شرکت دارغوزآباد استخدام شدم
عکس حرفه ای و پرانرژی
نیشتو قشنگ باز کن بعد با یدونه دوربین حرفه ای عکس بگیر بذار پروفایل
تشکر از دیگران
تا جایی که میتونی برای بقیه بم.. یعنی ازشون تشکر کن
حتی یکی بهت فحش داد بگو تشکر میکنم بابت اظهار نظرتون
نقل قول های الهام بخش
برو تو گوگل سرچ کن«سخن بزرگان» بعد تو لینکدین پست کن.
ایراد گرفتن از بقیه
تا میتونی پست بذار بگو لینکدین اینستا نیست و لینکدین خیلی برنامه خاصیه فقط آدمای خاص میتونن توش فعالیت کنن
نکته خیلی مهم:
اگه پسرید تمامی این نکاتو بیخیال شید چون جواب نمیده
#fun
@Syntax_fa
😁18👍2👎1👏1
🤣13👍1