جستجو در تالارهای گفتگو
در حال نمایش نتایج برای برچسب های 'چگونه'.
2 نتیجه پیدا شد
-
با سلام و درود، همهٔ ما میدانیم که امروزه کسبوکارهای اینترنتی و وابسته به فناوریهای مبتنی بر نرمافزار، یکی از حوزههایی به شمار میرود که در چهارچوب خود میتوانند پیشرفت بسیار چشمگیری داشته باشند. بنابراین، هر فردی که ایدهای در ذهن خود برای خلق یک کسبوکار دارد میتواند وارد این حوزهٔ «کسبوکارهای» اینترنتی شود. در این مقاله من به عناوین زیر اشاره خواهم کرد: گفتگوی صمیمانه و آزاد «مشاوره و ارزیابی مسائل» واقعیتهایی که مشتریان از آنها آگاه نیستند مشتری را برای مقایسه و دیدن نمونههای واقعی تشویق کنید معرفی و توصیف ابزارهایی که از آنها برای تولید و توسعه استفاده میکنید صداقت شما و تضمین وفاداری مشتری قرارداد، ارزیابی هزینهها و زمان توسعه مشاورهٔ رایگان یا پولی چگونه از دیگر برنامهنویسان و توسعهدهندگان متمایز و به یک برنامهنویس واقعی و حرفهای تبدیل شویم؟ بهروز باشید و از رفتارهای تعصبی بپرهیزید محصولات با کیفیت در سطح جهانی تولید کنید خدمات پشتیبانی، تضمین پاسخگو بودن طبیعی است که راهاندازی چنین مواردی نیاز به دانش و مهارتهای تخصصی در حوزهٔ مهندسی کامپیوتر، نرمافزار و شاخههای دیگر آن خواهد داشت. برای مثال: راهاندازی یک وبسایت برای معرفی کسبوکار مشتری نیازمند یک فرآیند ارزیابی، استعلام، ثبت، تخصیص فضای میزبانی، طراحی، برنامهنویسی، توسعه و پشتیبانی است. در این حالت مشتری میبایست با مراجعه به یکی از شرکتها و یا متخصصهای این حوزه خواستهٔ خود را به آن ارائه کند تا مطابق با آن کسبوکار ارزیابی و توسعه یابد. اگر شما به دنبال این هستید که سریعاً مشتری خود را قانع و پروژهای را برای انجام بپذیرید، شک نکنید که احتمال شکست و نارضایتی در هر دو طرف بسیار بالا خواهد بود. ممکن است شما رزومهٔ بسیار قوی با نمونهکارهای بسیار جذاب در اختیار داشته باشید که مشتری در لحظهٔ اول به تواناییهای شما مطمئن شود. اما این به تنهایی کافی نیست! گفتگوی صمیمانه و آزاد «مشاوره و ارزیابی مسائل» در این مقاله من به برخی از مشکلات مهمی که مشتریان در ابتدای کار با آن مواجه هستند میپردازم که عبارتند از: عدم شناخت کافی به ابزارها، روشها، الگوها و حتی افراد و شرکتهای انجام دهندهٔ این خدمات. جالب است بدانید که مشتری بر اساس دانستهها، شنیدهها و همچنین دیدههای خود از الگوهای نه چندان ارزیابی شده تصویری را از کسبوکار خود ترسیم میکند که کاملاً خام است که اگر توسط متخصصین مورد بررسی قرار نگیرد ممکن است به مسیر نادرست و نا آگاهانهای هدایت شوند که نتیجهٔ آن به جز ناامیدی و نا رضایت مشتری نخواهد بود. بنابراین اگرچه دنیای طراحی و توسعهٔ نرمافزار میتواند همهگیر باشد، اما واقعیت آن است که «باید کار را به کاردان سپرد» کاردانهایی که میتوانند با مورد ارزیابی قرار دادن ایدههای ذهنی مشتری آن را درک، هدایت و بهبود بخشد. من در بسیاری از جلسات کاری خودم برای شنیدن خواستههای مشتری نسبت به طرحی که در ذهن خود داشته این مشکلات را به خوبی دیده و درک میکنم. به عنوان مثال: مشتری در ابتدای کار مایل به بیان سریع تصویری از ایده یا راهکار خود برای توسعهٔ کسبوکاری است که شامل استراتژی کامل و نهایی شدهای نیست. البته من اطمینان میدهم این اشتباهات طبیعی بوده و یکی از وظایف برنامهنویسان حرفهای این است که با متکی بودن به علم روانشناسی و همدلی در شنیدن خواستههای مشتری سعی در تأیید همراه با اصلاح و هدایت آن به بهترین سمت ممکن باشد. در نظر داشته باشید که احتمال بسیار زیادی وجود دارد که ابتدای کار در همان دقایق اولیه جلسه مطالبی را از مشتری خود بشنوید که واقعاً در کسبوکار او نیاز نیست و یا حتی فراتر و متفاوتتر از آن چیزی است که در عمل باید به آن متکی بود. حتی در همان دقایق اول احتمال بسیار زیادی دارد که از مشتری چنین سوألاتی را بشنوید «شما بابت این کار چقدر هزینه میگیرید؟» البته این نوع سوألات حتی در پشت تلفن نیز پرسیده میشود، اما برای اینکه ارزش کار خودتان را حفظ کنید توصیه میشود هیچگاه بدون ارزیابی و اصول حرفهای در شنیدن خواستهٔ مشتری خود نه قیمت و نه زمانی برای انجام درخواست ارائه ندهید. این روشی ناشیانه است که معمولاً افراد غیر متخصص به کار میگیرند. بنابراین توصیه میشود صحبتها و ایدههای مشتری خود را با دقت گوش کنید. تأکید میکنم به هیچ عنوان ایدهٔ مشتری خود را سریعاً نکوبید و آن را رد نکنید «این امر موجب میشود مشتری نظرش در مورد شما تغییر کند» این روش در شأن متخصص حرفهای نیست. چرا که یکی از وظایف مهم شما ارائهٔ یک راهکار و مشاورهٔ مفید قبل از اخذ قرارداد و انجام آن است. سعی کنید سوألهایی را بپرسید که مشتری خود به آنها فکر نکرده است و با شنیدن آن حتماً نظرش جلب و از بُعد دیگری به کسبوکار خود و توسعهٔ آن نگاه خواهد کرد. شما به عنوان مشاور فنی باید بتوانید مشتری را قانع کنید که چه موردی ارزشمند و کدام بخش از خواستههای آن ارزش آنچنانی ندارد! چرا که مشتری نیاز دارد به مشکلات و ارزشهایی که در طرح ذهنی خود وجود دارد آگاه باشد تا به راحتی بتواند یک تصمیم صحیح بگیرد. واقعیتهایی که مشتریان از آنها آگاه نیستند قطعاً واقعیتهایی وجود دارد که مشتریان از آنها آگاه نیستند، چرا که آنها متخصص و افراد فنی نیستند. بنابراین احتمال بسیار زیاد دارد که مشتری ابتدا نمونهای از خواستههای خود را برای شما معرفی کند. به عنوان مثال: معرفی یک نمونه وبسایت یا نرمافزار (اپلیکیشن) که در نظر او بسیار جذاب و قابل قبول است. تمامی این مسائل وجود خواهد داشت، شما باید در نظر داشته باشید که تفاوت یک نمونه با خواستهٔ مشتری را شفاف سازی کنید. اگر قرار است بر اساس سلیقهٔ مشتری با او همکاری کنید بهتر است بدانید شما متخصص نیستید و نتیجهٔ پروژهای که بر روی آن کار خواهید کرد مطابق میل شما در بُعد تخصصی نخواهد بود. نمونه وبسایت مثال زده شده توسط مشتری را در مقابل خود مشتری ارزیابی کنید، اگر شما یک حرفهای باشید قطعاً میتوانید الگوهای پیاده سازی شده، روشهای برنامهنویسی، سیستم نرمافزاری، بسترها، تجربهکاربری و رابطکاربری آن را بررسی و نظر خود را برای مشتری ارائه دهید. در نظر داشته باشید زمانی که مشتری برای شما نمونه مثالی را ارائه میکند که شاید تا حدی با ایدهٔ ذهنی آن یکسان است، شما باید در نظر داشته باشید که اصول اساسی تولید محصولی که در نظر دارد را به او توضیح دهید. مشتری باید بداند که رفتار کاربرها، تجربهکاربری، برندینگ و اصول چیدهمان و همهٔ موارد دیگر در عین حال سادگی در کاربرد آن چقدر مهم است. تجربهکاربری هرچند برای خود یک تخصص کامل است، اما مشتری نیاز دارد تا شما در مورد این نکتهها به او یادآوری کنید. اگر شما فقط یک برنامهنویس هستید بهتر است مراجعی را برای مشتری و حتی خودتان در نظر بگیرید تا در بهتر شدن محصول مشارکت کند. مشتری را برای مقایسه و دیدن نمونههای واقعی تشویق کنید همهٔ مشتریان شما مانند هم رفتار نمیکنند، بعضی از آنها قبل از شما با افراد دیگری صحبت کردهاند و بعضی از آنها با شما به عنوان اولین نفر در رابطه با کسبوکارشان و خواستهٔ خود در ایجاد آن صحبت میکنند. بنابراین سعی کنید مشتری را به دیدن رقبا و نمونههایی که مشابه کسبوکار آن است تشویق کنید تا بتواند آنها را در واقعیت نیز ببیند. پیشنهاد میکنم دو نمونهٔ مشابه را در مقابل هم مقایسه کنید و برای مشتری توضیح دهید که چه تفاوتی بین ضعفها و قدرتها وجود دارد. معرفی و توصیف ابزارها و فناوریهایی که از آنها برای تولید و توسعه استفاده میکنید طبیعتاً همهٔ مشتریان شما با ابزارها، زبانهای برنامهنویسی و دیگر موارد آشنایی ندارند. اما برای جذب اعتماد و افزایش آگاهی مشتری لازم است به توصیف ابزارهایی که از آنها استفاده میکنید بپردازید. قرار نیست همهٔ موارد را به صورت فنی توضیح دهید، اما تا جایی که ممکن است به نکته مزیتها و مقایسهٔ تکنیکها و ابزارهایی که قرار است محصول مشتری را با آن توسعه دهید بپردازید تا اون نیز در جریان ذاتِ اصلی محصول خود قرار بگیرد. صداقت شما و تضمین وفاداری مشتری اگر به دنبال جذب مشتری با وفا و مشارکت طولانی مدت هستید، سعی کنید از همان دقایق ابتدائی نظرات خود را بیطرف و با صداقت کامل در قالب مشاورهی قانع کننده ارائه کنید. قرار نیست در همان جلسهٔ اول قرارداد اخذ کنید و یا هزینهای بابت کارتان دریافت کنید! اگر احساس میکنید مشتری شما به مهارتها و حضور شما ارزش قائل نشده است و به نظرات شما توجهی نمیکند خیلی محترمانه سعی کنید وارد این همکاری نشوید. چرا که حرف شنوی از یک متخصص یک ارزش اولیه برای ادامهٔ همکاری است. ناگفته نماند در مقابل ارزشهایی که مشتری به شما میدهد، مانند: شنیدن مشتاقانهٔ نظرات شما، به معنای آن است که این رابطهٔ کلامی در حل بسیاری از مسائل برای مشتری بسیار مهم بوده و شما از نتیجهٔ وقتی که بابتِ این مشاوره صرف میکنید مطمئن شوید. قرارداد، ارزیابی هزینهها و زمان توسعه قبل از اینکه مشتری به شما بگوید شرایط قرادادی چگونه است، شما نمونه قراردادی را با توجه به نتایج ارزیابی شده از نیاز مشتری آماده کنید. بندها و مادههای قرارداد را عادلانه مشخص کنید. تعهدات شما باید به گونهای باشد که مشتری شما از کار مطمئن شود. این قرارداد است که مشخص میکند شما چقدر به تواناییهای خودتان مطمئن هستید. متأسفانه بعضی از توسعهدهندگان به گونهای تعهدات را یکطرفه و به نفع خود تنظیم میکنند که گویی مشتری هیچ حقی در پروژه ندارد! حتی بندهایی دیده میشود که گاهاً توسعهدهنده اعلام کرده است منبعکد - سورسکد برنامه را با هزینهٔ بسیار زیاد و جدا از پروژه به مشتری تحویل خواهد داد! به نظر من این یک بی انصافی به تمام معناست! چرا که مشتری پول میدهد تا محصول خریداری کند! منطقیترین پیشنهاد از نظر من این است که بر اساس زمان و زحماتی که در ساخت و توسعهٔ پروژه صرف خواهد شد یک هزینه و زمانِ شفاف برای مشتری ارائه دهید. برای مثال: فازبندیهای ساخت پروژه در یک جدول استاندارد مانند WBS یا همان «ساختار شکست کار» استفاده کنید. مشاورهٔ رایگان یا پولی ممکن است با خود فکر کنید که من چرا باید دقیقهها و یا ساعتها وقت صرف مشاورهٔ کسانی صرف کنم که مشخص نیست مشتری من هستند یا خیر! برای تشخیص این موضوع که آیا مشاورههای شما در نهایت منجر به همکاری دو طرفه میشود یا خیر، کافی است به چند نکته توجه کنید. اول اینکه مشتری یا نمایندهای از مشتری به دفتر کسبوکار شما آمده است یا برعکس شما به دفتر کاری یا یک دیدار دوستانه رفتهاید! قطعاً زمانی که شما یک دفتر یا شرکت منظمی دارید طبیعی است که زمان خود را باید ارزشمند نگهدارید. بنابراین قبل از ورود به مشاورهٔ اصلی، اشکالی ندارد که بگویید برای ورود به آن هزینهای را دریافت خواهید کرد. به این نکته توجه داشته باشید که، پیشمشاوره با مشاورهٔ اصلی بسیار متفاوت است. در پیشمشاوره شما اولین دیدار را با مشتری خود خواهید داشت که در آن قرار است صحبتهای طرف مقابل را شنیده و از آن برای تجزیه تحلیل آن برای پاسخ در یک زمان مناسب نکتهبرداری کنید. در این نوع صحبت که معمولاً در دیدار اول و مقدماتی شکل میگیرد بهتر است هیچ صحبتی از هزینههایی که در ذهن دارید به مشتری انتقال ندهید چرا که در این مرحله «واقعاً نیاز نیست» و شما صرفاً باید یک شنوندهٔ خوب باشید. در نهایت بعد از شنیدن صحبتهای مشتری، لازم است از او بخواهید تا یک فرصت برای تجزیه تحلیل شنیدههای او بدهید. همانطور که در ابتدای مقاله توضیح دادم، احتمال اینکه مشتری در همان ابتدای صحبتهای خود درخواست میزانه هزینه و زمان برای انجام پروژه کند بسیار زیاد است. بنابراین اگر قبل از تجزیه تحلیل مسئله زمان و هزینهای برای آن مشخص کنید، دیگر نخواهید توانست در صحبتها و جلسات بعدی هزینهها و زمانبندی مشخصی که بعد از تجزیه تحلیل واقعیت به دست آوردهاید را به مشتری پیشنهاد و او را قانع کنید و هر چیزی که در سر داشتهاید را از دست خواهید داد. نکتهٔ کلیدی در این مرحله برای حرفهای برخورد کردن، این است که مشتری را متوجه این کنید که قرار است به او مشاوره و آموزشهای قبل از ورود به مرحلهٔ ساخت و توسعهٔ ایدهٔ ذهنی او را بدهید. در واقع قرار است یک ارزشآفرینی از این صحبتها برای مشتری ایجاد کنید تا به دانستههای خود اضافه کند «این کار برای مشتری شما ارزشمند و قابل قبول است» در این زمان است که شما میتوانید وارد مذاکرهٔ جدی و حرفهای شوید که شامل آموزشها و توضیحات کامل برای قانعسازی مشتری است که قطعاً دارای هزینه و ارزش به خصوصی خواهد بود. بنابراین یک جلسهٔ دیگر برای مشاورهٔ جدی با مشتری خود هماهنگ کنید تا نکات کلیدی و اساسی را برای هدایت هر چه بهتر او به مسیر درست و موفقیت را ترسیم کنید. چگونه از دیگر برنامهنویسان و توسعهدهندگان متمایز و به یک برنامهنویس واقعی و حرفهای تبدیل شویم؟ به احتمال بسیار زیاد هر یک از برنامهنویسان و طراحان در حوزهٔ کسبوکارهای اینترنتی که در زمینههای طراحی، توسعه و تولید محصولات نرمافزاری فعالیت میکنند، نظر بر این دارند که چون مهارت کار با زبانهای برنامهنویسی را در اختیار دارند و یا رزومه یا نمونهکارهای خوبی را دارند، پس بهترین هستند! متأسفانه من بارها شاهد غرور نابهجای بسیاری از برنامهنویسان بودهام که به شدت این رفتار را در شأن حرفهای ها نمیدانم. توصیه میکنم به دانستههای خود مغرور نباشید و از آنچه که در اختیار دارید به نحو عالی استفاده کنید تا از شما یک حرفهای واقعی بسازد. شرایطی که یک برنامهنویس حرفهای میتواند داشته باشد به صورت زیر است: تجربهٔ کافی و پُخته در زمینههای تخصصی تحصیلات مرتبط و مطالعات بسیار در حوزهٔ تخصصی و مرتبط با آن آشنا به اصول مشتری مداری برندینگ، معرفی فردی و تخصصی آشنا به اصول تجربهکاربری و سیستم روانشناسی مناسب با آن رزومهٔ خوب و واقعی نمونه کارهای واقعی و اصولی عدم وابستگی به ابزارهای محدود در توسعه مدارک و مجوزهای لازم در حوزهٔ فعالیتی چهارچوب مشخص و کاتالوگ معرفی خدمات و ارزشها توجه کنید که داشتن مجوز و گواهیهای فعالیتی در این حوزه بسیار مهم است. اگر شما به عنوان یک متخصص در این رشته فعالیت میکنید باید بدانید داشتن مدارک و گواهیهایی ملی و بینالمللی در این حوزه اعتبار خوبی در اختیار شما قرار میدهد که مشتری را بیشتر قانع خواهد کرد. پیشنهاد میکنم بهتر است خودتان را با یک رزومهٔ خوب و مجوزهای لازم از سمت «سازمان نظام صنفی رایانهای کشور» و «مرکز فناوری اطلاعات و رسانههای دیجیتال» معرفی کنید. اخذ این گواهیها در صورتی که شما واقعاً یک متخصص هستید در قالب شرکتی یا خصوصی، میتواند یک اعتبار لازم در قبال دانستههای شما و شرکت شما را در اختیار سازمانها و ارگانهای دولتی، خصوصی و نیمهخصوصی بدهد که اولویت انتخاب در زمان مزایدهها نیز با کسانی است که اعتبار لازم را دارند. واقعیت آن است، دریافت پروژههای بزرگ نه تنها نیاز به دانش و رزومهٔ بسیار خوب دارد، بلکه گواهیهایی که ثابت میکند شما یک متخصص هستید مهم است. این تنها گزینهای است که شما را با افرادی که غیر متخصص هستند متمایز میکند. بهروز باشید و از رفتارهای تعصبی پرهیز کنید همهٔ ما این واقعیت را میدانیم که در حوزهٔ صنعت علوم کامپیوتری، فناوری با سرعت بسیار چشمگیری در حال تغییر و تحولات بسیار زیادی است. این دلیل موجب میشود که در صورت عدم بهروزرسانی اطلاعات و دانش تکنیکی شرکت یا شخص برنامهنویس، از دیگر رقبا فاصله بگیرد. متأسفانه در کشور ما شرکتها و برنامهنویسان بسیاری هستند که به سبکها و اصولی که در نمونههای جهانی از آنها به خوبی یاد نمیشوند وابستگی نشان میدهند و بر بهترین بودن آن تأکید متعصبانهای دارند. شاید این تأکیدها در دید اولیه از جانب مشتری قابل درک باشد، اما واقعیت آن است که نباید خود را محدود به ابزارها و فناوریهایی کنید که از آیندهٔ آن بی خیر هستید! به عنوان مثال بررسی آیندهای از یک فناوری مانند IoT میتواند بسیاری از مسائل را برای شما یادآوری کند که چه ابزار و چهارچوبی میتواند برای پیشرفت روز افزون با حداقل محدودیتها مناسب است. در بسیاری از جوامع، وبسایتها، گروهها وکانالهای اینترنتی دیده میشود که افراد به ابزار و دانشی که فقط به آن محدود و مسلط هستند شدیداً تعصبی برخورد کرده و آن را بهترین انتخاب میدانند. لازم است یادآوری کنیم تعصب بر دانستهها تنها تأیید بر کم دانستن دارد و نه بیشتر! اگر منطقی باشیم یادگیری استانداردهای تضمین شده و پایدار، فناوریها، ابزارها و زبانهای برنامهنویسی قدرتمند و آیندهدار همیشه در پایداری و توسعهٔ سریع کسبوکارها موثر هستند. چرا که فناوری در زمان تغییر محیط را نیز تغییر میدهد. بنابراین توصیه من در این بخش آن است که در یادگیری ابزارها و زبانهای برنامهنویسی، تکنیکها و آشنایی با استانداردهای روز جهانی مصمم باشید و به هیچ عنوان به ابزارهای محدود به دانستههای خود تأکید شدید نکنید مگر با دلیل منطقی و علمی که تضمین کند انتخاب شما دقیقاً هم سو با پیشرفت است. محصولات با کیفیت در سطح جهانی تولید کنید با توجه به توضیحاتی که داده شد، شرکتها و توسعهدهندگانی که در حوزهٔ تولید نرمافزار فعالیت میکنند، معمولاً محصولاتی را توسعه میدهند که در مدیریت کسبوکارهای خود و دیگران موثر است. محصولات نرمافزاری هرچقدر هم قدرتمند باشند و هرچقدر شما کدهای منظم و قدرتمندی در تولید آنها نوشته باشید، کدهای شما از نظر مشتری یا کاربرانی که از آنها استفاده میکنند مخفی است. لازم به ذکر است که، یکی از رایجترین اشتباهاتی که نا خواسته در اکثر محصولات ایرانی دیده میشود عدم به کار گیری مباحث تجربهکاربری و رابطکاربری و استانداردهای توسعهٔ مناسب است. حقیقت این است که نمونه محصولات خارجیِ موفق فاقد این ایرادات هستند و در این صورت است که در نظر کاربر بسیار محبوب میشوند. هرچند بحث تجاری و تبلیغات رسانهای و جهانی در محبوبیت آنها بسیار مهم است، اما در نهایت این کاربر است که تصمیم میگیرد آن را بپذیرد یا خیر. منظور از کاربری صرفاً در زیبایی محیط نرمافزاری نیست، بلکه در دسترس بودن امکانات و ویژگیهایی که میتواند در برقراری ارتباط و وفاداری مشتری شما مفید باشد هم اشاره دارد. بنابراین، اگر شما دید کاربری نداشته باشید و صرفاً با توجه به سلیقههای خودتان محصولی را تولید کنید که فاقد اصول کاربری باشد در این صورت است که محصول شما تنها برای خودتان مهم و با ارزش خواهد بود. نکته: اصول استاندارد نسخهنگاری نرمافزار (محصول) را رعایت کنید و سعی کنید مشتری را در جریان تغییر تحولات و ویژگیهای اعمال شده در محصول قرار دهید. برای این کار میتوانید از استانداردهایی مانند نسخهنگاری معنایی استفاده کنید. خدمات پشتیبانی، تضمین پاسخگو بودن با توجه به نکاتی که اشاره شد، پشتیبانی و پاسخگو بودن در مراحل بعد از عقد قرارداد، طراحی و تولید محصول، یکی از مهمترین مواردی که در طولانی مدت وفاداری کاربران (مشتریان) شما را تضمین میکند، پاسخگو بودن و پشتیبانی است. حتی این موضوع میتواند به صورت یک قرارداد جداگانه با شرایط مخصوص خودش برای مشتری بیان شود تا در جریان شرایط و نحوهٔ پشتیبانی قرار بگیرد. علاوه بر قواعد و قوانین مشتری مداری و توسعهٔ کسبوکار، در چرخهٔ تولید نرمافزار نیز مهم است که بازخوردهای کاربری دریافت و مشکلات احتمالی محصول (نرمافزار) را بررسی و حل نمایید. این خود نوعی پشتیبانی و پاسخگویی و ارزش قائل شدن به مشتریان است که در عمل حتی به روشهای بسیار هوشمندانه میتوان آن را انجام داد. مشتریان شما در هر زمان که با مشکلی مواجه شوند حق دارند مشکلی که با آن مواجه شدهاند را به توسعهدهندهٔ محصول انتقال دهند. توسعهدهنده با بررسی بازخورد ارائه شده موظف است مشکل مربوطه را بررسی و آن را حل کند. این نکته در جملههای مشابه میتواند در بخشی از بندهای قراردادِ بین مشتری و توسعهدهنده یادآوری شود. شاید با خود فکر کنید که با چه روشهایی میتوان ارتباط بین مشتری و توسعهدهنده را برای حل مشکلی در محصول بررسی و مدیریت کرد، حتی بدون آنکه نیاز باشد به صورت حضوری وقت صرف آن کرد. در این باره پیشنهاد میکنم به توضیحات قبلی من در رابطه با ساختن محصول با کیفیت عمیقاً توجه کنید. منظور از توسعهٔ محصولات با کیفیت آن است که مشتری باید بتواند حتی در بازهٔ ۲۴ ساعته نظر خود را نسبت به مشکل، انتقاد یا پیشنهادی در رابطه با محصول ارائه کند تا در فرصت مناسب توسعهدهنده آن را بررسی کند. معمولاً این فرآیند به صورت سنتی با تلفن و مراجعهٔ حضوری صورت میگیرد، اما توصیهٔ من برای حفظ زمان و کارآیی بهتر این است که نرمافزار (محصول) خود را مجهز به خدمات پشتیبانی آنلاین در قالب سیستم هوشمند مجهز کنید. علاوه بر آن، استانداردهای سیاههٔ تغییرات (change log) و مشکلات گزارش شده را در محیط نرمافزار شفاف سازی کنید تا مشتری هم متوجه اعمال نظرات و انجام آن شود.
-
- توسعهدهنده
- برنامهنویس
-
(و 6 مورد دیگر)
برچسب زده شده با :
-
آغازی طوفانی برای پیاده سازی یک پیام رسان ساده بر پایه ++C
Max Base نوشته وبلاگ را ارسال کرد در برنامه نویسی
با سلام وقت بخیر, در این مطلب میخواهیم در مورد روش کارکرد پیام رسان ها بیشتر بدانیم و با یکدیگر کد یک پیام رسان ساده را پیاده و بررسی کنیم. طرز کار کرد پیام رسان در نظر داشته باشید که هر پیام رسانی که بر ساختار ها پیاده شده باشد از دو قسمت تشکیل شده است. نرم افزار اصلی برای مدیریت درخواست ها (سرور) نرم افزار برای کاربران (کاربر) به نرم افزار اولی سمت SERVER خواهیم گفت و به بعدی سمت CLIENT خواهیم گفت. روم یا تالار گفتگو ما تنها یک اتاق برای گفتگو در نظر میگیریم و هر کاربری که به سرور متصل شود را در همان تالار اضافه خواهیم کرد. تالار های گفتگو صرفا برای تقکیک سازی ارسال و دریافت ها و محدود کردن بازه ی کاربران مورد نظر... (ممکن است یک کاربر در چند اتاق بطور همزمان باشد.) سیستم های پیام رسان پیشرفته تر مانند تلگرام و ... تالار های زیادی را شامل می شوند. (هر کاربر خودش در کانال و گروه های مختلفی عضو است که هر کدام از آنها یک کانال متفاوت محسوب می شوند.) * دقت شود که منظور از کانال صرفا یک اتاق یا تالار گفتگو است و منظور کانال ارتباطی و پروتکل نیست. نرم افزار اصلی نرم افزار اصلی وظیفه دارد تا تمام کاربرانی که وارد تالار شده اند را به یاد داشته باشد و هر لحظه اماده دریافت درخواست هایی از طرف کاربرانش باشد. و پیام هایی را که از کاربران دریافت می کند برای تمامی کاربران دیگر هم ارسال کند که بسته به خلاقیت و نیاز می تواند هر یک از این بخش ها متفاوت طراحی شود. نرم افزار اصلی باید از قبل اجرا شده باشد. تا کاربران دیگر با استفاده از نرم افزار مخصوص به خودشان بتوانند به سرور متصل شوند و ارسال و دریافت داشته باشند. در نظر داشته باشید که اگر در نرم افزار اصلی اختلالی پیش بیایید و متوقف بشوند. قطا برای تمام کاربران مشکل پیش می آید. مگر اینکه از پایگاه های داده ی داخلی استفاده کرده باشند. (با خلاقیت می توان به گونه های متفاوتی چنین ساختاری را پیاده کرد) نرم افزار کاربران این نرم افزار جذاب ترین بخش است چرا تمام قابلیت هایی را که در اختیار کاربر قرار می دهیم را مستقیما طراحی می کنیم. در نظر داشته باشید که هر چیزی که در این نرم افزار طراحی می شود باید در نرم افزار اصلی پشتیبانی شوند... بنابراین اگر این دو بخش توسط دو فرد یا دو گروه مجزا طراحی می شوند آنها باید توسط داکیومنت ها و جلساتی به نظرات مشابه ای رسیده باشند. (اگرچه اینها تخصص و وظیفه ی تحلیلگر سیستم است! نه بطور همزمان وظیفه توسعه دهنده و برنامه نویس نرم افزار) پیاده سازی یک نمونه اکنون در نظر داریم تا با استفاده از ساختار کتابخانه BoostAsio پروژه ای را با نام BoostAsioChat ایجاد کنیم که در آن می خواهیم یک پیام رسان با حداقل ترین امکانات پایه طراحی کنیم که بیشتر جنبه شخصی و تفریحی دارد. زیرا از ساختار های استاندارد و ایمن و کاربری کاملا بدور است! (می توانید خودتان توسعه دهید و آنرا جالب تر بسازید) ساختار نرم افزار اصلی و سرور را به این صورت تعریف می کنیم : typedef deque<message> messageQueue; class participant { public: virtual ~participant() {} virtual void deliver(const message& messageItem) = 0; }; typedef shared_ptr<participant> participantPointer; class room { public: void join(participantPointer participant); void deliver(const message& messageItem); void leave(participantPointer participant); private: messageQueue messageRecents; enum { max = 200 }; set<participantPointer> participants; }; class session : public participant, public enable_shared_from_this<session> { public: session(tcp::socket socket, room& room) : socket(move(socket)), room_(room); void start(); void deliver(const message& messageItem); private: void readHeader(); void readBody(); void write(); tcp::socket socket; room& room_; message messageItem; messageQueue Messages; }; class server { public: server(boost::asio::io_context& io_context, const tcp::endpoint& endpoint) : acceptor(io_context, endpoint); private: void do_accept(); tcp::acceptor acceptor; room room_; }; int main(int argc, char* argv[]); ساختار نرم افزار کاربر را هم به این صورت تعریف می کنیم : typedef deque<message> messageQueue; class client { public: client(boost::asio::io_context& context, const tcp::resolver::results_type& endpoints) : context(context), socket(context); void write(const message& messageItem); void close(); private: void connect(const tcp::resolver::results_type& endpoints); void readHeader(); void readBody(); void write(); boost::asio::io_context& context; tcp::socket socket; message readMessage; messageQueue writeMessage; }; int main(int argc, char* argv[]); در نظر داریم تا در این پروژه از thread ها نیز استفاده کنیم... در مورد این مفهوم ها می توانید بصورت مجزا تحقیق کنید. بنابراین روش کامپایل این پروژه به این صورت خواهد بود : $ g++ client.cpp -lpthread -o client $ g++ Server.cpp -lpthread -o server آزمایش همانطور که گفته شد در ابتدا نرم افزار اصلی و سرور باید اجرا شود. در اینجا ما تمام ارتباطات شبکه را بر روی یک سیستم در شبکه داخلی برقرار خواهیم کرد... پس نگرانی در مورد ساختار های درونی شبکه و آی پی / دی ان اس / دامین نخواهیم داشت. بنابراین ای پی را می توانید ای پی داخلی یا localhost در نظر بگیرید. برای آزمایش پورت فرضی 4000 را در نظر میگیریم و نرم افزار اصلی را روی این پورت اجرا میکنیم : $ ./server 4000 در این مرحله متوجه می شوید که نرم افزار اصلی با موفقیت اجرا شده است و همچنان اجرا مانده است. بله درست است... نرم افزار اصلی هر لحظه باید منتظر دستور کاربران باشد. اگر لحظه ای برای نرم افزار اصلی اختلالی پیش آید نخواهد توانست دستورات کاربران را انجام یا پاسخ دهد. بنابراین این پردازش را قطع نکنید و اجازه دهید تا نرم افزار اصلی اجرا بماند. در محیط دیگری نرم افزار سمت کاربر را نیز اجرا کنید. این نرم افزار را می توانید به تعداد دلخواه وارد کنید. (همانطور که ممکن است 6 نفر همزمان به سرور متصل باشند / یا ممکن است هیچ فردی به سرور متصل نشوند) ابتدا یک کاربری را به سرور با پورت 4000 و شبکه داخلی وصل می کنیم : $ ./client localhost 4000 first user: you can type message here... حال در محیط دیگری با کاربر جدیدی نیز وارد می شویم : $ ./client localhost 4000 second user: you can type message here... در این پروژه نمونه از کاربران نام کاربری یا نام نمی پرسیم.. و صرفا وقتی وارد محیط گفتگو می شوند... یا زمانی که به سرور متصل می شوند منتظر هستیم تا انها پیامی را بنویسند... هر پیامی را که بنویسند به سرور ارسال می شود و سرور وظیفه دارد تا آنرا برای تمام کاربران بفرستد. و این روند درون یک حلقه بی نهایت تکرار می شوند. پس این ارتباط دو طرفه خواهد بود و هم کاربران برای سرور اطلاعات ارسال می کنند و هم سرور برای کاربران اطلاعات ارسال خواهد کرد. در نظر داشته باشید که کاربر اول می تواند پیامی را بنویسد و به کاربران دیگر ارسال شود. ممکن است کاربر سومی اصلا تصمیمی به نوشتن پیام نداشته باشد و صرفا تمایل به خواندن پیام دیگران داشته باشند. و این کاملا اختیاری است. و ما کاربران را اجباری نمیکنیم. اگرچه شما می توانید با خلاقیت خودتان اینها را با متغییر های کمکی و دستورات شرطی پیاده کنید. کد ها برای پیام ها یک ساختار در نظر میگیریم و بصورت مشترک در هر دو نرم افزار استفاده خواهیم کرد... بنابراین اینرا در هدر پیاده خواهیم کرد. هدر پیام : (message.hpp) #ifndef message_HPP #define message_HPP #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; class message { public: enum { headerLength = 4 }; enum { maxBodyLength = 512 }; message() : bodyLength_(0) { } const char* data() const { return data_; } char* data() { return data_; } size_t length() const { return headerLength + bodyLength_; } const char* body() const { return data_ + headerLength; } char* body() { return data_ + headerLength; } size_t bodyLength() const { return bodyLength_; } void bodyLength(size_t new_length) { bodyLength_ = new_length; if(bodyLength_ > maxBodyLength) bodyLength_ = maxBodyLength; } bool decodeHeader() { char header[headerLength + 1] = ""; strncat(header, data_, headerLength); bodyLength_ = atoi(header); if(bodyLength_ > maxBodyLength) { bodyLength_ = 0; return false; } return true; } void encodeHeader() { char header[headerLength + 1] = ""; sprintf(header, "%4d", static_cast<int>(bodyLength_)); memcpy(data_, header, headerLength); } private: char data_[headerLength + maxBodyLength]; size_t bodyLength_; }; #endif نرم افزار اصلی و سرور : (server.cpp) #include <iostream> #include <cstdlib> #include <deque> #include <memory> #include <list> #include <set> #include <utility> #include <boost/asio.hpp> #include "message.hpp" using boost::asio::ip::tcp; using namespace std; typedef deque<message> messageQueue; class participant { public: virtual ~participant() {} virtual void deliver(const message& messageItem) = 0; }; typedef shared_ptr<participant> participantPointer; class room { public: void join(participantPointer participant) { participants.insert(participant); for(auto messageItem: messageRecents) participant->deliver(messageItem); } void deliver(const message& messageItem) { messageRecents.push_back(messageItem); while(messageRecents.size() > max) messageRecents.pop_front(); for(auto participant: participants) participant->deliver(messageItem); } void leave(participantPointer participant) { participants.erase(participant); } private: messageQueue messageRecents; enum { max = 200 }; set<participantPointer> participants; }; class session : public participant, public enable_shared_from_this<session> { public: session(tcp::socket socket, room& room) : socket(move(socket)), room_(room) { } void start() { room_.join(shared_from_this()); readHeader(); } void deliver(const message& messageItem) { bool write_in_progress = !Messages.empty(); Messages.push_back(messageItem); if(!write_in_progress) { write(); } } private: void readHeader() { auto self(shared_from_this()); boost::asio::async_read(socket, boost::asio::buffer(messageItem.data(), message::headerLength), [this, self](boost::system::error_code ec, size_t) { if(!ec && messageItem.decodeHeader()) { readBody(); } else { room_.leave(shared_from_this()); } }); } void readBody() { auto self(shared_from_this()); boost::asio::async_read(socket, boost::asio::buffer(messageItem.body(), messageItem.bodyLength()), [this, self](boost::system::error_code ec, size_t) { if(!ec) { room_.deliver(messageItem); readHeader(); } else { room_.leave(shared_from_this()); } }); } void write() { auto self(shared_from_this()); boost::asio::async_write(socket, boost::asio::buffer(Messages.front().data(), Messages.front().length()), [this, self](boost::system::error_code ec, size_t) { if(!ec) { Messages.pop_front(); if(!Messages.empty()) { write(); } } else { room_.leave(shared_from_this()); } }); } tcp::socket socket; room& room_; message messageItem; messageQueue Messages; }; class server { public: server(boost::asio::io_context& io_context, const tcp::endpoint& endpoint) : acceptor(io_context, endpoint) { do_accept(); } private: void do_accept() { acceptor.async_accept([this](boost::system::error_code ec, tcp::socket socket) { if(!ec) { make_shared<session>(move(socket), room_)->start(); } do_accept(); }); } tcp::acceptor acceptor; room room_; }; int main(int argc, char* argv[]) { try { if(argc < 2) { cerr << "Usage: server <port> [<port> ...]\n"; return 1; } boost::asio::io_context io_context; list<server> servers; for(int i = 1; i < argc; ++i) { tcp::endpoint endpoint(tcp::v4(), atoi(argv[i])); servers.emplace_back(io_context, endpoint); } io_context.run(); } catch (exception& e) { cerr << "Exception: " << e.what() << "\n"; } return 0; } نرم افزار دوم و سمت کاربر : (client.cpp) #include <iostream> #include <thread> #include <cstdlib> #include <deque> #include <boost/asio.hpp> #include "message.hpp" using boost::asio::ip::tcp; using namespace std; typedef deque<message> messageQueue; class client { public: client(boost::asio::io_context& context, const tcp::resolver::results_type& endpoints) : context(context), socket(context) { connect(endpoints); } void write(const message& messageItem) { boost::asio::post(context, [this, messageItem]() { bool write_in_progress = !writeMessage.empty(); writeMessage.push_back(messageItem); if(!write_in_progress) { write(); } }); } void close() { boost::asio::post(context, [this]() { socket.close(); }); } private: void connect(const tcp::resolver::results_type& endpoints) { boost::asio::async_connect(socket, endpoints, [this](boost::system::error_code ec, tcp::endpoint) { if(!ec) { readHeader(); } }); } void readHeader() { boost::asio::async_read(socket, boost::asio::buffer(readMessage.data(), message::headerLength), [this](boost::system::error_code ec, size_t) { if(!ec && readMessage.decodeHeader()) { readBody(); } else { socket.close(); } }); } void readBody() { boost::asio::async_read(socket, boost::asio::buffer(readMessage.body(), readMessage.bodyLength()), [this](boost::system::error_code ec, size_t) { if(!ec) { cout.write(readMessage.body(), readMessage.bodyLength()); cout << "\n"; readHeader(); } else { socket.close(); } }); } void write() { boost::asio::async_write(socket, boost::asio::buffer(writeMessage.front().data(), writeMessage.front().length()), [this](boost::system::error_code ec, size_t) { if(!ec) { writeMessage.pop_front(); if(!writeMessage.empty()) { write(); } } else { socket.close(); } }); } boost::asio::io_context& context; tcp::socket socket; message readMessage; messageQueue writeMessage; }; int main(int argc, char* argv[]) { try { if(argc != 3) { cerr << "Usage: client <host> <port>\n"; return 1; } boost::asio::io_context context; tcp::resolver resolver(context); auto endpoints = resolver.resolve(argv[1], argv[2]); client c(context, endpoints); thread t([&context](){ context.run(); }); char line[message::maxBodyLength + 1]; while(cin.getline(line, message::maxBodyLength + 1)) { message messageItem; messageItem.bodyLength(strlen(line)); memcpy(messageItem.body(), line, messageItem.bodyLength()); messageItem.encodeHeader(); c.write(messageItem); } c.close(); t.join(); } catch (exception& e) { cerr << "Exception: " << e.what() << "\n"; } return 0; } این پروژه آزمایشی بصورت رایگان و اوپن سورس در اینترنت بخصوص اینجا وجود دارد و می توانید آنرا مستقیما بصورت کامل دانلود کنید. با تشکر, Max Base / مکس بیس