Building a new social (or a "chain" of them): your suggestions

Discussion in 'Chit Chat' started by fullautotrading, Jun 23, 2023.

  1. Today was a long day of coding to create the unified feed, Twitter-X style :) LOL

    The feature requires a ton of changes and refactoring, on top of the current "forum-like" architecture.

    This is due to the fact that when I am showing the posts within their forum and their threads, all the shown posts share the same forum and thread.

    upload_2023-8-10_20-30-42.png


    So, for each post, they are the same.

    Instead of a unified feed where each post must maintain the pointers to the respective threads, forums, and authors (author of the post and thread OP), I need to maintain that information for each and every post.

    So for instance, to extract the posts, I was using something like the following. The extra needed information (use an avatar and nickname of the poster) was simply obtained by joining, and the main information about the thread and forum was simply the current thread and forum.

    Code:
    public System.Collections.Generic.List<ThreadPost> SelectAllThreadPosts_PAGED(int ThreadID, int PageNumber, bool AllPostsVirtualThread)
    {
        string WhereThreadClause;
        int PageSizeUsed;
    
        string Order_SelectUpToPage;
        string Order_SelectBringPageOnTop;
        string Order_SelectPageOrdered;
    
        string SortingField;
    
        if (AllPostsVirtualThread)
        {
            WhereThreadClause = "";
            PageSizeUsed = _PAGE_SIZE_ALL_POSTS;
            Order_SelectUpToPage = "DESC";
            Order_SelectBringPageOnTop = "ASC";
            Order_SelectPageOrdered = "DESC";
            SortingField = "DateOfLastUpload";  // may be DbNull
        }
        else
        {
            WhereThreadClause = "ThreadPosts.ThreadID=@ThreadID AND";
            PageSizeUsed = _PAGE_SIZE_POSTS;
            Order_SelectUpToPage = "ASC";
            Order_SelectBringPageOnTop = "DESC";
            Order_SelectPageOrdered = "ASC";
            SortingField = "PostID";   // in place of SortingField = "DateOfPostCreation"
        }
    
    
        string SelectPageOrdered;
    
        if (!this._USE_SQL_SERVER)
        {
    
            // record fino alla pagina corrent ordinati
            int EstremoSuperiore = PageNumber * PageSizeUsed;
            if (EstremoSuperiore <= 0)
                EstremoSuperiore = 1;          
    
            string SelectUpToPage = "Select TOP " + EstremoSuperiore + " ThreadPosts.*, Users.NicknameUser, Users.AvatarFileUser FROM ThreadPosts LEFT JOIN Users On ThreadPosts.UserAuthorID=Users.UserID" + " WHERE " + WhereThreadClause + " ThreadPosts.StatusPost=0 And (Users.StatusUser=0 Or Users.StatusUser Is NULL) ORDER BY " + SortingField + " " + Order_SelectUpToPage;
    
            string SelectBringPageOnTop = "SELECT TOP " + PageSizeUsed + " sub.* FROM (" + SelectUpToPage + ") sub ORDER BY sub." + SortingField + " " + Order_SelectBringPageOnTop;
    
            SelectPageOrdered = "SELECT * FROM (" + SelectBringPageOnTop + ") subOrdered ORDER BY subOrdered." + SortingField + " " + Order_SelectPageOrdered + ";";
        }
        else
        {
    
            int EstremoSuperiore = PageNumber * PageSizeUsed;  // same as: StartingPoint + PageSizeUsed - 1
            int StartingPoint = EstremoSuperiore - PageSizeUsed + 1;
    
            string MySQL_Internal = "SELECT TOP " + EstremoSuperiore + "ROW_NUMBER() OVER (ORDER BY " + SortingField + " " + Order_SelectPageOrdered + ") AS RowNum," + " ThreadPosts.*, Users.NicknameUser, Users.AvatarFileUser FROM ThreadPosts LEFT JOIN Users ON ThreadPosts.UserAuthorID=Users.UserID" + " WHERE " + WhereThreadClause + " ThreadPosts.StatusPost=0";
    
            SelectPageOrdered = "SELECT * FROM (" + MySQL_Internal + ") AS RowConstrainedResult WHERE RowNum >= " + StartingPoint + " AND RowNum <= " + EstremoSuperiore + " ORDER BY RowNum ;";
        }
    
    
        using (var MyConn = MakeConnection())
        {
            MyConn.Open();
    
            using (var MyCmd = this.MakeCommand(SelectPageOrdered, MyConn))
            {
                MyCmd.Parameters.Add("@ThreadID", System.Data.OleDb.OleDbType.Integer).Value = ThreadID;
    
                using (var r = MyCmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
                {
                    if (r.HasRows)
                    {
                        var Posts = new System.Collections.Generic.List<ThreadPost>();
    
                        while (r.Read())
                        {
                            ThreadPost ThreadPost;
                            if (this._USE_SQL_SERVER)
                                ThreadPost = this.Fill_ThreadPost_FromDBFields(r, 1);
                            else
                                ThreadPost = this.Fill_ThreadPost_FromDBFields(r, 0);
                            Posts.Add(ThreadPost);         // key string, richiesto dal serializzatore
                        }
    
                        return Posts;
                    }
                }
            }
        }
    
        return null;
    }
    
    Never mind the 3 nested selects that are needed for result pagination (in case ROW_NUMBER() method is not available, like in SQLSERVER. Remember that I am making this compatible with most relational DBMSes, with multiple connectivity).

    The problem is that in a "unified feed", the concept of the current thread or forum is meaningless, as each post can belong everywhere.

    This forces a bit of rethinking of the extraction and join process.

    What I have done is to simplify the paginated SELECT of the post, by extracting only the post and then rejoining the corresponding objects programmatically.

    A draft of the new procedure would look like this:

    Code:
    public void SelectAllThreadPosts_PAGED(int ThreadID, int PageNumber, ref System.Collections.Generic.List<ThreadPost> ListOfSortedPosts, ref Dictionary<string, UserInfo> DictOfDifferentUsers, ref Dictionary<string, ForumThread> DictOfDifferentThreads, ref Dictionary<string, Forum> DictOfDifferentForums)
    {
        int PageSizeUsed;
    
        string Order_SelectUpToPage;
        string Order_SelectBringPageOnTop;
        string Order_SelectShownPage;
    
        string SortingField;
    
        if (ThreadID == _KEY_GLOBAL_VIRTUAL_THREAD_ALL_POST)
        {
            // WhereThreadClause = ""
            PageSizeUsed = _PAGE_SIZE_ALL_POSTS;
            Order_SelectUpToPage = "DESC";
            Order_SelectBringPageOnTop = "ASC";
            Order_SelectShownPage = "DESC";
            SortingField = "DateOfLastUpload";  // may be DbNull
        }
        else
        {
            PageSizeUsed = _PAGE_SIZE_POSTS;
            Order_SelectUpToPage = "ASC";
            Order_SelectBringPageOnTop = "DESC";
            Order_SelectShownPage = "ASC";
            SortingField = "PostID";   // in place of "DateOfPostCreation"
        }
    
        int EstremoSuperiore = Math.Max(1, PageNumber * PageSizeUsed);
    
        string SelectUpToPage = "Select TOP " + EstremoSuperiore + " ThreadPosts.*" + FROM_forPosts() + WHERE_forPosts(ThreadID == _KEY_GLOBAL_VIRTUAL_THREAD_ALL_POST) + " ORDER BY " + SortingField + " " + Order_SelectUpToPage;
    
        string SelectReverseChunk = "SELECT TOP " + PageSizeUsed + " UpToPage.* FROM (" + SelectUpToPage + ") UpToPage ORDER BY UpToPage." + SortingField + " " + Order_SelectBringPageOnTop;
        string SelectPageOrdered = "SELECT * FROM (" + SelectReverseChunk + ") ReversedChunk ORDER BY ReversedChunk." + SortingField + " " + Order_SelectShownPage + ";";
    
        using (var MyConn = MakeConnection())
        {
            MyConn.Open();
    
            using (var MyCmd = this.MakeCommand(SelectPageOrdered, MyConn))
            {
                if (ThreadID != _KEY_GLOBAL_VIRTUAL_THREAD_ALL_POST)
                    MyCmd.Parameters.Add("@ThreadID", System.Data.OleDb.OleDbType.Integer).Value = ThreadID;
    
                using (var r = MyCmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
                {
                    if (r.HasRows)
                    {
                        while (r.Read())
                        {
                            ThreadPost ThreadPost = this.Fill_ThreadPost_FromDBFields(r, 0, forJoin: false);
                            this.Crea_Stringa_PostFileAndFolderSuServer(ThreadPost.FileNamePost, ThreadPost.FileNamePostWithFolder, ThreadPost.FileNamePostPhysicalPathOnServer);
    
                            if (!DictOfDifferentUsers.ContainsKey(ThreadPost.UserAuthorID))
                            {
                                UserInfo UserInfo_PostOP = this.getUserInfoFrom_UserID(ThreadPost.UserAuthorID);
                                if (UserInfo_PostOP != null)
                                {
                                    {
                                        var withBlock = UserInfo_PostOP;
                                        DictOfDifferentUsers.Add(UserInfo_PostOP.UserID, UserInfo_PostOP);
                                        this.Crea_Stringa_UserAvatarFileAndFolderSuServer(withBlock.AvatarFileUser, withBlock.AvatarFileUserWithFolder, withBlock.AvatarFileUserPathPhysicalOnServer);
                                    }
                                }
                            }
    
                            // thread
                            if (!DictOfDifferentThreads.ContainsKey(ThreadPost.ThreadID))
                            {
                                ForumThread ForumThread = this.getForumThreadFrom_ThreadID(ThreadPost.ThreadID);
                                DictOfDifferentThreads.Add(ForumThread.ThreadID, ForumThread);
    
                                // autore thread
                                if (!DictOfDifferentUsers.ContainsKey(ForumThread.OpUserID))
                                {
                                    UserInfo UserInfo_ThreadOP = this.getUserInfoFrom_UserID(ForumThread.OpUserID);
                                    if (UserInfo_ThreadOP != null)
                                    {
                                        {
                                            var withBlock = UserInfo_ThreadOP;
                                            DictOfDifferentUsers.Add(withBlock.UserID, UserInfo_ThreadOP);
                                            this.Crea_Stringa_UserAvatarFileAndFolderSuServer(withBlock.AvatarFileUser, withBlock.AvatarFileUserWithFolder, withBlock.AvatarFileUserPathPhysicalOnServer);
                                        }
                                    }
                                }
    
                                // forum
                                if (!DictOfDifferentForums.ContainsKey(ForumThread.ForumID))
                                {
                                    Forum Forum = this.getForumFrom_ForumID(ForumThread.ForumID);
                                    DictOfDifferentForums.Add(Forum.ForumID, Forum);
                                }
                            }
    
                            ListOfSortedPosts.Add(ThreadPost);
                        }
                    }
                }
            }
        }
    }
    

    Then I would create dictionaries of all the threads and forums and send those to the client through serialization, where the objects are recreated and "rejoined" to the respective posts.

    This way I can avoid replicating all the information about threads and forums for each post, and maintain a list of unique objects which are recreated and relinked on the client.

    So in the end, it required a full day, and I am not yet finished as there are still many bugs running everywhere to be patiently killed one by one :) but I am pretty happy with the journey :) A good way to celebrate my birthday after all :)

    In practice, this new feature has forced the code to become conceptually more abstract but also more maintainable.


    upload_2023-8-10_20-38-44.png


    It's pretty much like that when you work on a project. The more sides you start "hitting" it, the more powerful and abstract become every object you use, often with a gain in maintainability... :)
     
    Last edited: Aug 10, 2023
    #51     Aug 10, 2023
  2. Yesterday, August 15 was a full coding day (and trading account "supervision"), with massive refactoring, and today I hope to be able to do also some physical exercise :)

    I have seen some new posts from Dr. Dawkins on X. He seems to be getting old: I hope he takes care adequately of himself :)

    The market is slowly moving downward:

    upload_2023-8-16_13-54-18.png
    ES FUT 202309 CME 50 E-mini S&P 500 [ESU3, 497222760, mult: 50]

    but we are adequately protected by long legs, so we can handle it pretty well:

    upload_2023-8-16_13-55-6.png

    (follow my journal in the trading journal section of this site).

    I am quite happy I made the extra effort to add the unified feed section because this way we can have media that have the best of the two worlds: a "forum-like" architecture and at the same time an "X-feel" :), with the difference that here you can easily get a decent discussion after your posts because each goes into a thread of a forum, instead of having that throw-stuff-in-a black-hole feeling ...

    upload_2023-8-16_13-57-57.png

    "Centralized feed" section:

    upload_2023-8-16_13-58-22.png

    For now, I have set up the paginated posts in the feed to go down from the most recent.

    While in the forum/thread, on the contrary, they are arranged as you would normally read a book (top/down), as you have here on ET. We will see with practice if this is intuitive to use... :)

    I have also been adding stuff to the editor, and some math symbols in the emoji picker (you never know). Also added the euro symbol, for the sites, where people can also buy/sell

    upload_2023-8-16_14-9-25.png
     
    Last edited: Aug 16, 2023
    #52     Aug 16, 2023
  3. I am thinking of adding another section, similar to a thread, where all the user profile posts can be browsed.

    This requires the creation of a new "virtual" thread so that I can "reuse" all the post pagination features.

    I have reorganized a bit the DB structure, taking into account the recent code refactoring, and, at the moment, it looks like this (which would be pretty close to the "final" form):

    upload_2023-8-19_11-22-46.png

    a preview of the section:

    upload_2023-8-19_10-28-11.png


    I am using the same "class" for ordinary posts and user profile posts so that there is no limit to the material (video, photos, attachments) that can be put into a user profile. This, of course, also allows for a more elegant implementation and easier code maintenance. :)
     
    Last edited: Aug 19, 2023
    #53     Aug 19, 2023
  4. I need to rush before the new semester activity restart :)

    Sunday is the best day to make a full 16 hours of coding, which is my preferred activity
    after physical exercise (I like a lot tumbling related stuff, in case you did not notice yet :)), or a bit of piano for which very rarely I can spare some time :)

    upload_2023-8-20_11-5-5.png


    A nice little rose from my garden this morning salutes all of you:

    upload_2023-8-20_11-1-46.jpeg

    Have a full and productive Sunday :)
     
    #54     Aug 20, 2023
  5. The development continues. I may not be able to close the social sites by September, due to some unexpected "extra work" and activity :)

    Anyway, I have been working on the user profile "virtual" thread and now that I see it it's actually good to have.
    This is similar to a topic thread but will contain the user profiles (fantasy, random content here).

    upload_2023-8-28_18-18-37.png


    Trading is going fine here a couple of accounts, 217 days and 574 days respectively, 2MM and 1MM start cap. Obviously $$$ used is always "fictitious", even though the algorithm does not know :)


    upload_2023-8-28_18-19-46.png


    upload_2023-8-28_18-20-46.png

    see how the 2MM account does a much better result because we are not forced to close a lot of running positions to keep funds usage within the desired limits.

    This "superlinear" return (that is "more than linear" if you prefer, but less than quadratic) is due to several factors, like the capability to "recover" more stop-loss orders and also to create more hedging layers (those that we call "long" meaning specifically a positive position of the instrument; clearly, these are just conventions.) Note however that the hedging action is carried out also on short layers because the position is continuously "modulated". For instance, on a short game layer, the position will become zero if the price rises, to be reloaded when it comes down.

    So "short" and "long" game, obviously, does not mean we only make sell or only buy orders, it refers to the type of scalping game that "tends" to "prefer" either a short or long position.
     
    Last edited: Aug 28, 2023
    #55     Aug 28, 2023
  6. destriero

    destriero

    A math prof that doesn't know what superlinear means. The returns are not superlinear (mkt beta) as you're leveraged your fcking moron. lol.
     
    #56     Aug 29, 2023
  7. #57     Aug 29, 2023